Skip to content

Commit 3a5d18c

Browse files
committed
twitter plugin
1 parent 44defed commit 3a5d18c

16 files changed

Lines changed: 111 additions & 3531 deletions

File tree

‎apps/server/bun.lock‎

Lines changed: 0 additions & 215 deletions
This file was deleted.

‎apps/server/src/index.ts‎

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,11 @@ import { onError } from '@orpc/server'
44
import { OpenAPIHandler } from '@orpc/openapi/fetch'
55
import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'
66
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'
7-
import { initializePlugins } from '@crosspost/api'
8-
import { createAppRouter } from '@crosspost/api/routers'
7+
import { router } from '@crosspost/api/routers'
98
import { createContext } from '@crosspost/api/context'
109

11-
// Initialize plugins
12-
const plugins = await initializePlugins({
13-
TWITTER_PLUGIN_URL: process.env.TWITTER_PLUGIN_URL,
14-
TWITTER_CLIENT_ID: process.env.TWITTER_CLIENT_ID!,
15-
TWITTER_CLIENT_SECRET: process.env.TWITTER_CLIENT_SECRET!,
16-
});
17-
18-
// Create router with initialized plugins
19-
const appRouter = createAppRouter(plugins);
20-
2110
// Create RPC handler
22-
const rpcHandler = new RPCHandler(appRouter, {
11+
const rpcHandler = new RPCHandler(router, {
2312
interceptors: [
2413
onError((error) => {
2514
console.error('RPC Error:', error)
@@ -28,7 +17,7 @@ const rpcHandler = new RPCHandler(appRouter, {
2817
})
2918

3019
// Create OpenAPI handler
31-
const apiHandler = new OpenAPIHandler(appRouter, {
20+
const apiHandler = new OpenAPIHandler(router, {
3221
plugins: [
3322
new OpenAPIReferencePlugin({
3423
schemaConverters: [new ZodToJsonSchemaConverter()],
@@ -48,28 +37,39 @@ app.get('/', (c) => {
4837
return c.text('OK')
4938
})
5039

51-
// Handle all routes
52-
app.all('*', async (c) => {
40+
// RPC endpoint
41+
app.all('/rpc/*', async (c) => {
5342
const req = c.req.raw
5443
const context = await createContext(req)
5544

56-
// Try RPC first
57-
const rpcResult = await rpcHandler.handle(req, {
58-
prefix: '/api',
45+
const result = await rpcHandler.handle(req, {
46+
prefix: '/rpc',
5947
context
6048
})
61-
if (rpcResult.response) return c.newResponse(rpcResult.response.body, rpcResult.response)
6249

63-
// Try OpenAPI docs
64-
const apiResult = await apiHandler.handle(req, {
65-
prefix: '/docs',
50+
return result.response
51+
? c.newResponse(result.response.body, result.response)
52+
: c.text('Not Found', 404)
53+
})
54+
55+
// API endpoint (w/ OpenAPI Documentation UI)
56+
app.all('/api/*', async (c) => {
57+
const req = c.req.raw
58+
const context = await createContext(req)
59+
60+
const result = await apiHandler.handle(req, {
61+
prefix: '/api',
6662
context
6763
})
68-
if (apiResult.response) return c.newResponse(apiResult.response.body, apiResult.response)
6964

70-
return c.text('Not Found', 404)
65+
return result.response
66+
? c.newResponse(result.response.body, result.response)
67+
: c.text('Not Found', 404)
7168
})
7269

70+
// 404 handler
71+
app.all('*', (c) => c.text('Not Found', 404))
72+
7373
const port = Number(process.env.PORT) || 8787
7474
console.log(`🚀 Plugin Service running on http://localhost:${port}`)
7575

‎bun.lock‎

Lines changed: 0 additions & 2013 deletions
This file was deleted.

‎packages/api/package.json‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"@orpc/server": "^1.10.0",
2828
"@orpc/zod": "^1.10.0",
2929
"dotenv": "^17.2.2",
30-
"every-plugin": "link:every-plugin",
31-
"zod": "^3.23.8"
30+
"every-plugin": "0.4.4"
3231
}
3332
}

‎packages/api/src/index.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ export const o = os.$context<Context>();
66
export const publicProcedure = o;
77

88
// Plugin exports
9-
export { initializePlugins, type PluginEnv, type PluginsInstance } from './plugins';
10-
export { createAppRouter, type AppRouter, type AppRouterClient } from './routers';
9+
export { runtime, plugins } from './plugins';
10+
export { router, type AppRouter, type AppRouterClient } from './routers';

‎packages/api/src/plugins.ts‎

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,24 @@ declare module "every-plugin" {
77
}
88
}
99

10-
export interface PluginEnv {
11-
TWITTER_PLUGIN_URL?: string;
12-
TWITTER_CLIENT_ID: string;
13-
TWITTER_CLIENT_SECRET: string;
14-
}
15-
16-
export async function initializePlugins(env: PluginEnv) {
17-
const runtime = createPluginRuntime({
18-
registry: {
19-
"@crosspost/twitter": {
20-
remoteUrl: env.TWITTER_PLUGIN_URL || "http://localhost:3014/remoteEntry.js",
21-
},
22-
},
23-
secrets: {
24-
TWITTER_CLIENT_ID: env.TWITTER_CLIENT_ID,
25-
TWITTER_CLIENT_SECRET: env.TWITTER_CLIENT_SECRET,
10+
export const runtime = createPluginRuntime({
11+
registry: {
12+
"@crosspost/twitter": {
13+
remoteUrl: process.env.TWITTER_PLUGIN_URL || "http://localhost:3014/remoteEntry.js",
2614
},
27-
});
15+
},
16+
secrets: {
17+
TWITTER_CLIENT_ID: process.env.TWITTER_CLIENT_ID!,
18+
TWITTER_CLIENT_SECRET: process.env.TWITTER_CLIENT_SECRET!,
19+
},
20+
});
2821

29-
const twitter = await runtime.usePlugin("@crosspost/twitter", {
30-
variables: {},
31-
secrets: {
32-
clientId: "{{TWITTER_CLIENT_ID}}",
33-
clientSecret: "{{TWITTER_CLIENT_SECRET}}"
34-
},
35-
});
36-
37-
return { twitter };
38-
}
22+
const twitter = await runtime.usePlugin("@crosspost/twitter", {
23+
variables: {},
24+
secrets: {
25+
clientId: "{{TWITTER_CLIENT_ID}}",
26+
clientSecret: "{{TWITTER_CLIENT_SECRET}}"
27+
},
28+
});
3929

40-
export type PluginsInstance = Awaited<ReturnType<typeof initializePlugins>>;
30+
export const plugins = { twitter } as const;

‎packages/api/src/routers/index.ts‎

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
import { os } from "@orpc/server";
2-
import type { PluginsInstance } from "../plugins";
31
import type { RouterClient } from "@orpc/server";
2+
import { os } from "@orpc/server";
3+
import { plugins } from "../plugins";
44

5-
export function createAppRouter(plugins: PluginsInstance) {
6-
return {
7-
health: os
8-
.route({ method: "GET", path: "/health" })
9-
.handler(() => {
10-
return "OK";
11-
}),
12-
twitter: plugins.twitter.router
13-
};
14-
}
5+
export const router = {
6+
health: os
7+
.route({ method: "GET", path: "/health" })
8+
.handler(() => {
9+
return "OK";
10+
}),
11+
twitter: os.prefix('/twitter').router(plugins.twitter.router)
12+
} as const;
1513

16-
export type AppRouter = ReturnType<typeof createAppRouter>;
17-
export type AppRouterClient = RouterClient<AppRouter>;
14+
export type AppRouter = typeof router;
15+
export type AppRouterClient = RouterClient<AppRouter>;

‎packages/api/tsconfig.json‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,5 @@
1515
"skipLibCheck": true
1616
},
1717
"include": ["src/**/*"],
18-
"exclude": ["node_modules", "dist"],
19-
"references": [
20-
{ "path": "../../plugins/twitter" }
21-
]
18+
"exclude": ["node_modules", "dist"]
2219
}
Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { CommonPluginErrors } from 'every-plugin';
21
import { oc } from 'every-plugin/orpc';
32
import { z } from 'every-plugin/zod';
43
import * as AuthSchemas from './schemas/auth';
5-
import * as PostSchemas from './schemas/post';
64
import * as MediaSchemas from './schemas/media';
5+
import * as PostSchemas from './schemas/post';
76
import * as ProfileSchemas from './schemas/profile';
87
import * as RateLimitSchemas from './schemas/rate-limit';
98

@@ -13,115 +12,88 @@ import * as RateLimitSchemas from './schemas/rate-limit';
1312
*/
1413
export const platformContract = oc.router({
1514
// AUTH DOMAIN - OAuth flow operations
16-
auth: oc.router({
15+
auth: {
1716
getAuthUrl: oc
1817
.route({ method: 'GET', path: '/auth/url' })
1918
.input(AuthSchemas.GetAuthUrlInputSchema)
20-
.output(z.string())
21-
.errors(CommonPluginErrors),
22-
19+
.output(z.string()),
2320
exchangeCodeForToken: oc
2421
.route({ method: 'POST', path: '/auth/token' })
2522
.input(AuthSchemas.ExchangeCodeInputSchema)
26-
.output(AuthSchemas.AuthTokenSchema)
27-
.errors(CommonPluginErrors),
28-
23+
.output(AuthSchemas.AuthTokenSchema),
2924
refreshToken: oc
3025
.route({ method: 'POST', path: '/auth/refresh' })
3126
.input(AuthSchemas.RefreshTokenInputSchema)
32-
.output(AuthSchemas.AuthTokenSchema)
33-
.errors(CommonPluginErrors),
34-
27+
.output(AuthSchemas.AuthTokenSchema),
3528
revokeToken: oc
3629
.route({ method: 'DELETE', path: '/auth/token' })
3730
.input(AuthSchemas.RevokeTokenInputSchema)
3831
.output(z.boolean())
39-
.errors(CommonPluginErrors),
40-
}),
32+
},
4133

4234
// POST DOMAIN - Social media post operations
43-
post: oc.router({
35+
post: {
4436
create: oc
4537
.route({ method: 'POST', path: '/post' })
4638
.input(PostSchemas.CreatePostInputSchema)
47-
.output(PostSchemas.PostResultSchema)
48-
.errors(CommonPluginErrors),
49-
39+
.output(PostSchemas.PostResultSchema),
5040
delete: oc
5141
.route({ method: 'DELETE', path: '/post/{postId}' })
5242
.input(PostSchemas.DeletePostInputSchema)
53-
.output(PostSchemas.DeleteResultSchema)
54-
.errors(CommonPluginErrors),
55-
43+
.output(PostSchemas.DeleteResultSchema),
5644
repost: oc
5745
.route({ method: 'POST', path: '/post/{postId}/repost' })
5846
.input(PostSchemas.RepostInputSchema)
59-
.output(PostSchemas.PostResultSchema)
60-
.errors(CommonPluginErrors),
61-
47+
.output(PostSchemas.PostResultSchema),
6248
quote: oc
6349
.route({ method: 'POST', path: '/post/{postId}/quote' })
6450
.input(PostSchemas.QuotePostInputSchema)
65-
.output(PostSchemas.PostResultSchema)
66-
.errors(CommonPluginErrors),
67-
51+
.output(PostSchemas.PostResultSchema),
6852
reply: oc
6953
.route({ method: 'POST', path: '/post/{postId}/reply' })
7054
.input(PostSchemas.ReplyInputSchema)
71-
.output(PostSchemas.PostResultSchema)
72-
.errors(CommonPluginErrors),
73-
55+
.output(PostSchemas.PostResultSchema),
7456
like: oc
7557
.route({ method: 'POST', path: '/post/{postId}/like' })
7658
.input(PostSchemas.LikeInputSchema)
77-
.output(PostSchemas.LikeResultSchema)
78-
.errors(CommonPluginErrors),
79-
59+
.output(PostSchemas.LikeResultSchema),
8060
unlike: oc
8161
.route({ method: 'DELETE', path: '/post/{postId}/like' })
8262
.input(PostSchemas.UnlikeInputSchema)
8363
.output(PostSchemas.LikeResultSchema)
84-
.errors(CommonPluginErrors),
85-
}),
64+
},
8665

8766
// MEDIA DOMAIN - Media upload and management
88-
media: oc.router({
67+
media: {
8968
upload: oc
9069
.route({ method: 'POST', path: '/media' })
9170
.input(MediaSchemas.UploadMediaInputSchema)
92-
.output(MediaSchemas.MediaUploadResultSchema)
93-
.errors(CommonPluginErrors),
94-
71+
.output(MediaSchemas.MediaUploadResultSchema),
9572
getStatus: oc
9673
.route({ method: 'GET', path: '/media/{mediaId}/status' })
9774
.input(MediaSchemas.GetMediaStatusInputSchema)
98-
.output(MediaSchemas.MediaStatusResultSchema)
99-
.errors(CommonPluginErrors),
100-
75+
.output(MediaSchemas.MediaStatusResultSchema),
10176
updateMetadata: oc
10277
.route({ method: 'PUT', path: '/media/{mediaId}/metadata' })
10378
.input(MediaSchemas.UpdateMediaMetadataInputSchema)
10479
.output(z.boolean())
105-
.errors(CommonPluginErrors),
106-
}),
80+
},
10781

10882
// PROFILE DOMAIN - User profile operations
109-
profile: oc.router({
83+
profile: {
11084
get: oc
11185
.route({ method: 'GET', path: '/profile' })
11286
.input(ProfileSchemas.GetProfileInputSchema)
11387
.output(ProfileSchemas.UserProfileSchema)
114-
.errors(CommonPluginErrors),
115-
}),
88+
},
11689

11790
// RATE LIMIT DOMAIN - Rate limit checking
118-
rateLimit: oc.router({
91+
rateLimit: {
11992
check: oc
12093
.route({ method: 'GET', path: '/rate-limit' })
12194
.input(RateLimitSchemas.CheckRateLimitInputSchema)
12295
.output(RateLimitSchemas.RateLimitStatusSchema)
123-
.errors(CommonPluginErrors),
124-
}),
96+
},
12597
});
12698

12799
export type PlatformContract = typeof platformContract;

‎packages/shared-contract/package.json‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,26 @@
33
"version": "1.0.0",
44
"description": "Shared contract for Crosspost platform plugins",
55
"type": "module",
6-
"main": "./index.ts",
7-
"types": "./index.ts",
6+
"main": "./dist/index.mjs",
7+
"types": "./dist/index.d.mts",
88
"exports": {
9-
".": "./index.ts"
9+
".": {
10+
"types": "./dist/index.d.mts",
11+
"default": "./dist/index.mjs"
12+
}
1013
},
14+
"files": ["dist"],
1115
"scripts": {
12-
"type-check": "tsc --noEmit"
16+
"build": "tsdown",
17+
"type-check": "tsc --noEmit",
18+
"prepublishOnly": "bun run build"
1319
},
1420
"dependencies": {
15-
"every-plugin": "link:every-plugin"
21+
"every-plugin": "0.4.4"
1622
},
1723
"devDependencies": {
18-
"@types/bun": "latest"
24+
"@types/bun": "latest",
25+
"tsdown": "latest"
1926
},
2027
"peerDependencies": {
2128
"typescript": "^5"

0 commit comments

Comments
 (0)