-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
07b6c39
commit f1a115b
Showing
19 changed files
with
384 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.DS_Store | ||
node_modules | ||
*.generated.ts | ||
*.generated | ||
.env | ||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"recommendations": [ | ||
"oven.bun-vscode", | ||
"pucelle.run-on-save" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"runOnSave.commands": [ | ||
{ | ||
"globMatch": "**/*.{graphql,test.ts}", | ||
"command": "bun run graphql-codegen", | ||
"runIn": "terminal" | ||
}, | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# posthog | ||
|
||
## Develop | ||
|
||
```bash | ||
bun dev | ||
``` | ||
|
||
## Test | ||
|
||
```bash | ||
bun test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { PostHog } from 'posthog-node' | ||
|
||
import plugin from './plugin' | ||
|
||
const PH_HOST = plugin.config.PH_HOST ?? (plugin.config.PH_REGION === 'us' ? 'https://app.posthog.com' : 'https://eu.posthog.com') | ||
|
||
export const client = new PostHog( | ||
plugin.config.PH_API_KEY, | ||
{ host: PH_HOST, ...plugin.config.postHogOptions }, | ||
) | ||
|
||
await client.shutdown() | ||
|
||
export default client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import defaultConfig from '@zemble/graphql/codegen' | ||
|
||
import type { CodegenConfig } from '@graphql-codegen/cli' | ||
|
||
const config: CodegenConfig = { | ||
...defaultConfig, | ||
} | ||
|
||
export default config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { createTestApp } from '@zemble/core/test-utils' | ||
import { | ||
it, expect, | ||
} from 'bun:test' | ||
|
||
import plugin from '../../plugin' | ||
import { graphql } from '../client.generated' | ||
|
||
const randomNumberMutation = graphql(` | ||
mutation RandomNumber { | ||
randomNumber | ||
} | ||
`) | ||
|
||
it('Should return a number', async () => { | ||
const app = await createTestApp(plugin) | ||
|
||
const response = await app.gqlRequest(randomNumberMutation, {}) | ||
expect(response.data).toEqual({ | ||
|
||
randomNumber: expect.any(Number), | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import type { MutationResolvers } from '../schema.generated' | ||
|
||
const randomNumber: MutationResolvers['randomNumber'] = (_, __, { pubsub }) => { | ||
const randomNumber = Math.floor(Math.random() * 1000) | ||
|
||
pubsub.publish('randomNumber', randomNumber) | ||
|
||
return randomNumber | ||
} | ||
|
||
export default randomNumber |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createTestApp } from '@zemble/core/test-utils' | ||
import { it, expect } from 'bun:test' | ||
|
||
import plugin from '../../plugin' | ||
import { graphql } from '../client.generated' | ||
|
||
const HelloWorldQuery = graphql(` | ||
query Hello { | ||
hello | ||
} | ||
`) | ||
|
||
it('Should return world!', async () => { | ||
const app = await createTestApp(plugin) | ||
|
||
const response = await app.gqlRequest(HelloWorldQuery, {}) | ||
|
||
expect(response.data).toEqual({ | ||
hello: 'world!', | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import type { QueryResolvers } from '../schema.generated' | ||
|
||
const hello: QueryResolvers['hello'] = () => 'world!' | ||
|
||
export default hello |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { SubscriptionResolvers } from '../schema.generated' | ||
|
||
const countdown: SubscriptionResolvers['countdown'] = { | ||
// This will return the value on every 1 sec until it reaches 0 | ||
// eslint-disable-next-line object-shorthand | ||
subscribe: async function* (_, { from }, { logger }) { | ||
// eslint-disable-next-line no-plusplus | ||
for (let i = from; i >= 0; i--) { | ||
// eslint-disable-next-line no-await-in-loop | ||
await new Promise((resolve) => { | ||
logger.info('countdown', { countdown: i }) | ||
setTimeout(resolve, 1000) | ||
}) | ||
yield { countdown: i } | ||
} | ||
}, | ||
resolve: (payload: unknown) => (payload as { readonly countdown: number}).countdown, | ||
} | ||
|
||
export default countdown |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { SubscriptionResolvers } from '../schema.generated' | ||
|
||
const randomNumber: SubscriptionResolvers['randomNumber'] = { | ||
// subscribe to the randomNumber event | ||
subscribe: (_, __, { pubsub }) => { | ||
console.log('subscribing to randomNumber') | ||
return pubsub.subscribe('randomNumber') | ||
}, | ||
resolve: (payload: number) => { | ||
console.log('resolving randomNumber', payload) | ||
return payload | ||
}, | ||
} | ||
|
||
export default randomNumber |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import type { SubscriptionResolvers } from '../schema.generated' | ||
|
||
let initialized = false | ||
const initializeOnce = (pubsub: Zemble.PubSubType) => { | ||
if (initialized) return | ||
initialized = true | ||
setInterval(() => { | ||
pubsub.publish('tick', Date.now()) | ||
}, 1000) | ||
} | ||
|
||
const tick: SubscriptionResolvers['tick'] = { | ||
// subscribe to the tick event | ||
subscribe: (_, __, { pubsub }) => { | ||
initializeOnce(pubsub) | ||
console.log('subscribing to tick') | ||
return pubsub.subscribe('tick') | ||
}, | ||
resolve: (payload: number) => payload, | ||
} | ||
|
||
export default tick |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
type Query { | ||
hello: String! | ||
} | ||
|
||
type Mutation { | ||
randomNumber: Int! | ||
} | ||
|
||
type Subscription { | ||
countdown(from: Int!): Int! | ||
tick: Float! | ||
randomNumber: Int! | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "posthog", | ||
"version": "0.0.1", | ||
"description": "", | ||
"type": "module", | ||
"keywords": [ | ||
"zemble", | ||
"zemble-plugin", | ||
"@zemble" | ||
], | ||
"dependencies": { | ||
"@zemble/bun": "workspace:*", | ||
"@zemble/core": "workspace:*", | ||
"@zemble/graphql": "workspace:*", | ||
"@zemble/routes": "workspace:*", | ||
"posthog-node": "^4.0.0" | ||
}, | ||
"scripts": { | ||
"test": "bun test", | ||
"dev": "zemble-dev plugin.ts", | ||
"typecheck": "tsc --noEmit", | ||
"codegen": "graphql-codegen" | ||
}, | ||
"devDependencies": { | ||
"@types/bun": "*", | ||
"@graphql-codegen/add": "^5.0.0", | ||
"@graphql-codegen/cli": "^5.0.0", | ||
"@graphql-codegen/client-preset": "^4.1.0", | ||
"@graphql-codegen/typescript": "^4.0.1", | ||
"@graphql-codegen/typescript-resolvers": "^4.0.1", | ||
"@tsconfig/bun": "^1.0.1" | ||
}, | ||
"peerDependencies": { | ||
"typescript": "^5.3.3" | ||
}, | ||
"module": "plugin.ts", | ||
"main": "plugin.ts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import { Plugin } from '@zemble/core' | ||
import GraphQL from '@zemble/graphql' | ||
import Routes from '@zemble/routes' | ||
// import https from 'node:https' | ||
import * as tls from 'node:tls' | ||
|
||
import type { PostHogOptions } from 'posthog-node' | ||
|
||
type PhRegion = 'us' | 'eu' | ||
|
||
interface Config extends Zemble.GlobalConfig { | ||
readonly PH_API_KEY: string | ||
readonly PH_REGION?: PhRegion | ||
readonly PH_HOST?: string, | ||
readonly PH_API_HOST?: string, | ||
readonly PH_ASSET_HOST?: string, | ||
readonly PH_INGEST_PATH?: string | ||
|
||
readonly postHogOptions?: PostHogOptions | ||
} | ||
|
||
const defaultConfig = { | ||
PH_REGION: process.env.PH_REGION as PhRegion ?? 'us', | ||
PH_HOST: process.env.PH_HOST, | ||
PH_API_KEY: process.env.PH_API_KEY ?? '', | ||
PH_API_HOST: process.env.PH_API_HOST, | ||
PH_ASSET_HOST: process.env.PH_ASSET_HOST, | ||
PH_INGEST_PATH: process.env.PH_INGEST_PATH ?? '/ph-ingest', | ||
} satisfies Config | ||
|
||
// const agent = new https.Agent({ | ||
// rejectUnauthorized: false, | ||
// }) | ||
|
||
export default new Plugin<Config, typeof defaultConfig>( | ||
import.meta.dir, | ||
{ | ||
defaultConfig, | ||
middleware: async ({ app, config, logger }) => { | ||
const { | ||
PH_REGION, PH_API_KEY, PH_API_HOST, PH_ASSET_HOST, PH_INGEST_PATH, | ||
} = config | ||
|
||
if (!PH_API_KEY || PH_API_KEY === '') { | ||
throw new Error('PH_API_KEY not set') | ||
} | ||
|
||
if (!['us', 'eu'].includes(PH_REGION)) { | ||
logger.warn('Expected PH_REGION to be either "us" or "eu"') | ||
} | ||
|
||
const phHost = PH_API_HOST ?? `${PH_REGION}.i.posthog.com` | ||
const phAssetHost = PH_ASSET_HOST ?? `${PH_REGION}-assets.i.posthog.com` | ||
|
||
console.log('phHost', phHost) | ||
|
||
app.hono.all(`${PH_INGEST_PATH}/static/*`, async (ctx) => { | ||
const path = ctx.req.path.replace(PH_INGEST_PATH, '') | ||
|
||
console.log('path', path) | ||
console.log('headers', ctx.req.header()) | ||
|
||
const res = await fetch(`https://${phAssetHost}${path}`, { | ||
method: ctx.req.method, | ||
body: ctx.req.raw.body, | ||
headers: { | ||
...ctx.req.header(), | ||
host: phAssetHost.replace('https://', ''), | ||
}, | ||
/* tls: { | ||
rejectUnauthorized: false, | ||
checkServerIdentity: (hostname: string, cert: tls.PeerCertificate): Error | undefined => { | ||
console.log('checkServerIdentity', hostname) | ||
if (hostname.includes('posthog.com')) { | ||
return undefined | ||
} | ||
/// here you can add a custom check for specific cert and/or hostname | ||
return tls.checkServerIdentity(hostname, cert) | ||
}, | ||
}, | ||
cache: 'no-cache', */ | ||
}).catch((err) => { | ||
console.error(err) | ||
throw err | ||
}) | ||
|
||
const resHeaders = res.headers.toJSON() | ||
|
||
console.log('resHeaders', resHeaders) | ||
delete resHeaders['content-encoding'] | ||
return ctx.newResponse(res.body, res.status as 200, resHeaders) | ||
}) | ||
|
||
app.hono.all(`${PH_INGEST_PATH}/*`, async (ctx) => { | ||
const url = new URL(ctx.req.url) | ||
// eslint-disable-next-line functional/immutable-data | ||
url.pathname = url.pathname.replace(PH_INGEST_PATH, '') | ||
// eslint-disable-next-line functional/immutable-data | ||
url.host = phHost | ||
url.port = '443' | ||
// eslint-disable-next-line functional/immutable-data | ||
url.protocol = 'https:' | ||
|
||
// console.log('url.host', url.host.toString()) | ||
console.log('url', url.toString()) | ||
console.log('data', await ctx.req.text()) | ||
|
||
const res = await fetch(url, { | ||
method: ctx.req.method, | ||
body: ctx.req.raw.body, | ||
headers: { | ||
...ctx.req.header(), | ||
host: phHost.replace('https://', ''), | ||
}, | ||
/* tls: { | ||
rejectUnauthorized: false, | ||
checkServerIdentity: (hostname: string, cert: tls.PeerCertificate): Error | undefined => { | ||
console.log('checkServerIdentity', hostname) | ||
if (hostname.includes('posthog.com')) { | ||
return undefined | ||
} | ||
/// here you can add a custom check for specific cert and/or hostname | ||
return tls.checkServerIdentity(hostname, cert) | ||
}, | ||
}, | ||
cache: 'no-cache', */ | ||
}).catch((err) => { | ||
console.error(url.toString(), err) | ||
throw err | ||
}) | ||
|
||
const resHeaders = res.headers.toJSON() | ||
|
||
console.log(`${url.toString()}: ${res.statusText}`, await res.text()) | ||
delete resHeaders['content-encoding'] | ||
return ctx.newResponse(res.body, res.status as 200, resHeaders) | ||
}) | ||
}, | ||
dependencies: [{ plugin: GraphQL }, { plugin: Routes }], | ||
}, | ||
) |
Oops, something went wrong.