From 687925bcbf9fa4bae0d960fcfa36c4733a11c43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentinas=20=C4=8Cirba?= Date: Fri, 3 Apr 2026 08:35:00 +0300 Subject: [PATCH 01/80] Update Hostinger link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb58d9ac..15df6984 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ | Sponsor | Logo | Description | |---------|:-----------------------------------------------------------------------:|-----------------| -| [Hostinger](https://www.hostinger.com/?ref=postiz) | Hostinger | Hostinger is on a mission to make online success possible for anyone – from developers to aspiring bloggers and business owners | +| [Hostinger](https://www.hostinger.com/vps/docker/postiz?ref=postiz) | Hostinger | Hostinger is on a mission to make online success possible for anyone – from developers to aspiring bloggers and business owners | | [Virlo](https://dev.virlo.ai/?ref=postiz) | Virlo | Virlo is the #1 social media trend spotting and all-in-one GTM tool for teams leveraging short-form video | From 073479bc4a9d915558922790f876c806f30f0b02 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 3 Apr 2026 13:34:24 +0700 Subject: [PATCH 02/80] feat: pinterest, show more boards --- .../src/integrations/social/pinterest.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts b/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts index 377b93db..2f216182 100644 --- a/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts @@ -159,7 +159,7 @@ export class PinterestProvider @Tool({ description: 'List of boards', dataSchema: [] }) async boards(accessToken: string) { const { items } = await ( - await fetch('https://api.pinterest.com/v5/boards', { + await fetch('https://api.pinterest.com/v5/boards?page_size=250', { method: 'GET', headers: { Authorization: `Bearer ${accessToken}`, From 5d46a6cd344f8da4dde48ccc4693be10dfbd31d0 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 3 Apr 2026 18:39:33 +0700 Subject: [PATCH 03/80] feat: new mastra --- .../src/api/routes/copilot.controller.ts | 23 +- apps/backend/src/main.ts | 9 +- .../src/chat/agent.tool.interface.ts | 14 +- .../nestjs-libraries/src/chat/auth.context.ts | 20 +- .../src/chat/load.tools.service.ts | 9 +- .../nestjs-libraries/src/chat/mastra.store.ts | 5 +- .../nestjs-libraries/src/chat/start.mcp.ts | 5 +- .../src/chat/tools/generate.image.tool.ts | 10 +- .../chat/tools/generate.video.options.tool.ts | 6 +- .../src/chat/tools/generate.video.tool.ts | 18 +- .../src/chat/tools/integration.list.tool.ts | 12 +- .../chat/tools/integration.schedule.post.ts | 20 +- .../chat/tools/integration.trigger.tool.ts | 24 +- .../chat/tools/integration.validation.tool.ts | 9 +- .../src/chat/tools/video.function.tool.ts | 11 +- package.json | 11 +- pnpm-lock.yaml | 1928 ++++++++++------- 17 files changed, 1197 insertions(+), 937 deletions(-) diff --git a/apps/backend/src/api/routes/copilot.controller.ts b/apps/backend/src/api/routes/copilot.controller.ts index ffd61391..fb451280 100644 --- a/apps/backend/src/api/routes/copilot.controller.ts +++ b/apps/backend/src/api/routes/copilot.controller.ts @@ -20,7 +20,7 @@ import { SubscriptionService } from '@gitroom/nestjs-libraries/database/prisma/s import { MastraAgent } from '@ag-ui/mastra'; import { MastraService } from '@gitroom/nestjs-libraries/chat/mastra.service'; import { Request, Response } from 'express'; -import { RuntimeContext } from '@mastra/core/di'; +import { RequestContext } from '@mastra/core/di'; import { CheckPolicies } from '@gitroom/backend/services/auth/permissions/permissions.ability'; import { AuthorizationActions, Sections } from '@gitroom/backend/services/auth/permissions/permission.exception.class'; @@ -72,20 +72,19 @@ export class CopilotController { return; } const mastra = await this._mastraService.mastra(); - const runtimeContext = new RuntimeContext(); - runtimeContext.set( + const requestContext = new RequestContext(); + requestContext.set( 'integrations', req?.body?.variables?.properties?.integrations || [] ); - runtimeContext.set('organization', JSON.stringify(organization)); - runtimeContext.set('ui', 'true'); + requestContext.set('organization', JSON.stringify(organization)); + requestContext.set('ui', 'true'); const agents = MastraAgent.getLocalAgents({ resourceId: organization.id, mastra, - // @ts-ignore - runtimeContext, + requestContext: requestContext as any, }); const runtime = new CopilotRuntime({ @@ -124,7 +123,7 @@ export class CopilotController { const mastra = await this._mastraService.mastra(); const memory = await mastra.getAgent('postiz').getMemory(); try { - return await memory.query({ + return await memory.recall({ resourceId: organization.id, threadId, }); @@ -137,14 +136,12 @@ export class CopilotController { @CheckPolicies([AuthorizationActions.Create, Sections.AI]) async getList(@GetOrgFromRequest() organization: Organization) { const mastra = await this._mastraService.mastra(); - // @ts-ignore const memory = await mastra.getAgent('postiz').getMemory(); - const list = await memory.getThreadsByResourceIdPaginated({ - resourceId: organization.id, + const list = await memory.listThreads({ + filter: { resourceId: organization.id }, perPage: 100000, page: 0, - orderBy: 'createdAt', - sortDirection: 'DESC', + orderBy: { field: 'createdAt', direction: 'DESC' }, }); return { diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 16f24427..2e6fb480 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -22,6 +22,7 @@ import { startMcp } from '@gitroom/nestjs-libraries/chat/start.mcp'; async function start() { const app = await NestFactory.create(AppModule, { rawBody: true, + bodyParser: false, cors: { ...(!process.env.NOT_SECURED ? { credentials: true } : {}), allowedHeaders: [ @@ -52,8 +53,12 @@ async function start() { }) ); - app.use(['/copilot/*', '/posts'], (req: any, res: any, next: any) => { - json({ limit: '50mb' })(req, res, next); + app.use((req: any, res: any, next: any) => { + if (req.path.startsWith('/mcp') || req.path.startsWith('/sse/') || req.path.startsWith('/message/')) { + return next(); + } + const limit = ['/copilot/', '/posts'].some((p) => req.path.startsWith(p)) ? '50mb' : '100kb'; + json({ limit })(req, res, next); }); app.use(cookieParser()); diff --git a/libraries/nestjs-libraries/src/chat/agent.tool.interface.ts b/libraries/nestjs-libraries/src/chat/agent.tool.interface.ts index daf9b315..42de6075 100644 --- a/libraries/nestjs-libraries/src/chat/agent.tool.interface.ts +++ b/libraries/nestjs-libraries/src/chat/agent.tool.interface.ts @@ -1,16 +1,6 @@ -import type { ZodLikeSchema } from '@mastra/core/dist/types/zod-compat'; -import type { - ToolExecutionContext, -} from '@mastra/core/dist/tools/types'; -import { Tool } from '@mastra/core/dist/tools/tool'; +import type { ToolAction } from '@mastra/core/tools'; -export type ToolReturn = Tool< - ZodLikeSchema, - ZodLikeSchema, - ZodLikeSchema, - ZodLikeSchema, - ToolExecutionContext ->; +export type ToolReturn = ToolAction; export interface AgentToolInterface { name: string; diff --git a/libraries/nestjs-libraries/src/chat/auth.context.ts b/libraries/nestjs-libraries/src/chat/auth.context.ts index 989a2a53..8c709c87 100644 --- a/libraries/nestjs-libraries/src/chat/auth.context.ts +++ b/libraries/nestjs-libraries/src/chat/auth.context.ts @@ -1,20 +1,16 @@ -import { ToolAction } from '@mastra/core/dist/tools/types'; import { getAuth } from '@gitroom/nestjs-libraries/chat/async.storage'; -export const checkAuth: ToolAction['execute'] = async ( - { runtimeContext }, - options +export const checkAuth = ( + inputData: any, + context: any ) => { const auth = getAuth(); - // @ts-ignore - if (options?.extra?.authInfo || auth) { - runtimeContext.set( - // @ts-ignore + const authInfo = context?.mcp?.extra?.authInfo || auth; + if (authInfo && context?.requestContext) { + (context.requestContext as any).set( 'organization', - // @ts-ignore - JSON.stringify(options?.extra?.authInfo || auth) + JSON.stringify(authInfo) ); - // @ts-ignore - runtimeContext.set('ui', 'false'); + (context.requestContext as any).set('ui', 'false'); } }; diff --git a/libraries/nestjs-libraries/src/chat/load.tools.service.ts b/libraries/nestjs-libraries/src/chat/load.tools.service.ts index d5908905..10118d94 100644 --- a/libraries/nestjs-libraries/src/chat/load.tools.service.ts +++ b/libraries/nestjs-libraries/src/chat/load.tools.service.ts @@ -43,10 +43,11 @@ export class LoadToolsService { async agent() { const tools = await this.loadTools(); return new Agent({ + id: 'postiz', name: 'postiz', description: 'Agent that helps manage and schedule social media posts for users', - instructions: ({ runtimeContext }) => { - const ui: string = runtimeContext.get('ui' as never); + instructions: ({ requestContext }) => { + const ui: string = requestContext.get('ui' as never); return ` Global information: - Date (UTC): ${dayjs().format('YYYY-MM-DD HH:mm:ss')} @@ -90,9 +91,7 @@ export class LoadToolsService { memory: new Memory({ storage: pStore, options: { - threads: { - generateTitle: true, - }, + generateTitle: true, workingMemory: { enabled: true, schema: AgentState, diff --git a/libraries/nestjs-libraries/src/chat/mastra.store.ts b/libraries/nestjs-libraries/src/chat/mastra.store.ts index d5601601..4dc00896 100644 --- a/libraries/nestjs-libraries/src/chat/mastra.store.ts +++ b/libraries/nestjs-libraries/src/chat/mastra.store.ts @@ -1,5 +1,6 @@ -import { PostgresStore, PgVector } from '@mastra/pg'; +import { PostgresStore } from '@mastra/pg'; export const pStore = new PostgresStore({ - connectionString: process.env.DATABASE_URL, + id: 'postiz-store', + connectionString: process.env.DATABASE_URL!, }); diff --git a/libraries/nestjs-libraries/src/chat/start.mcp.ts b/libraries/nestjs-libraries/src/chat/start.mcp.ts index cc2dd5d7..60f099bb 100644 --- a/libraries/nestjs-libraries/src/chat/start.mcp.ts +++ b/libraries/nestjs-libraries/src/chat/start.mcp.ts @@ -6,6 +6,7 @@ import { randomUUID } from 'crypto'; import { OrganizationService } from '@gitroom/nestjs-libraries/database/prisma/organizations/organization.service'; import { OAuthService } from '@gitroom/nestjs-libraries/database/prisma/oauth/oauth.service'; import { runWithContext } from './async.storage'; + export const startMcp = async (app: INestApplication) => { const mastraService = app.get(MastraService, { strict: false }); const organizationService = app.get(OrganizationService, { strict: false }); @@ -22,7 +23,7 @@ export const startMcp = async (app: INestApplication) => { const mastra = await mastraService.mastra(); const agent = mastra.getAgent('postiz'); - const tools = await agent.getTools(); + const tools = await agent.listTools(); const serverConfig = { name: 'Postiz MCP', @@ -76,6 +77,7 @@ export const startMcp = async (app: INestApplication) => { sessionIdGenerator: () => { return randomUUID(); }, + enableJsonResponse: true, }, req, res, @@ -119,6 +121,7 @@ export const startMcp = async (app: INestApplication) => { sessionIdGenerator: () => { return randomUUID(); }, + enableJsonResponse: true, }, req, res, diff --git a/libraries/nestjs-libraries/src/chat/tools/generate.image.tool.ts b/libraries/nestjs-libraries/src/chat/tools/generate.image.tool.ts index f475f189..1a5455ef 100644 --- a/libraries/nestjs-libraries/src/chat/tools/generate.image.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/generate.image.tool.ts @@ -27,13 +27,11 @@ export class GenerateImageTool implements AgentToolInterface { id: z.string(), path: z.string(), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); - // @ts-ignore - const org = JSON.parse(runtimeContext.get('organization') as string); + execute: async (inputData, context) => { + checkAuth(inputData, context); + const org = JSON.parse((context?.requestContext as any)?.get('organization') as string); const image = await this._mediaService.generateImage( - context.prompt, + inputData.prompt, org ); diff --git a/libraries/nestjs-libraries/src/chat/tools/generate.video.options.tool.ts b/libraries/nestjs-libraries/src/chat/tools/generate.video.options.tool.ts index 453b7660..06461dd5 100644 --- a/libraries/nestjs-libraries/src/chat/tools/generate.video.options.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/generate.video.options.tool.ts @@ -1,6 +1,5 @@ import { AgentToolInterface, - ToolReturn, } from '@gitroom/nestjs-libraries/chat/agent.tool.interface'; import { createTool } from '@mastra/core/tools'; import { Injectable } from '@nestjs/common'; @@ -33,9 +32,8 @@ export class GenerateVideoOptionsTool implements AgentToolInterface { }) ), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); + execute: async (inputData, context) => { + checkAuth(inputData, context); const videos = this._videoManagerService.getAllVideos(); console.log( JSON.stringify( diff --git a/libraries/nestjs-libraries/src/chat/tools/generate.video.tool.ts b/libraries/nestjs-libraries/src/chat/tools/generate.video.tool.ts index c8d4eb35..05bc94c0 100644 --- a/libraries/nestjs-libraries/src/chat/tools/generate.video.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/generate.video.tool.ts @@ -48,20 +48,18 @@ export class GenerateVideoTool implements AgentToolInterface { outputSchema: z.object({ url: z.string(), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); - // @ts-ignore - const org = JSON.parse(runtimeContext.get('organization') as string); + execute: async (inputData, context) => { + checkAuth(inputData, context); + const org = JSON.parse((context?.requestContext as any)?.get('organization') as string); const value = await this._mediaService.generateVideo(org, { - type: context.identifier, - output: context.output, - customParams: context.customParams.reduce( - (all, current) => ({ + type: inputData.identifier, + output: inputData.output, + customParams: inputData.customParams.reduce( + (all: Record, current: { key: string; value: any }) => ({ ...all, [current.key]: current.value, }), - {} + {} as Record ), }); diff --git a/libraries/nestjs-libraries/src/chat/tools/integration.list.tool.ts b/libraries/nestjs-libraries/src/chat/tools/integration.list.tool.ts index 98d54ce2..894c3a09 100644 --- a/libraries/nestjs-libraries/src/chat/tools/integration.list.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/integration.list.tool.ts @@ -1,13 +1,11 @@ import { AgentToolInterface, - ToolReturn, } from '@gitroom/nestjs-libraries/chat/agent.tool.interface'; import { createTool } from '@mastra/core/tools'; import { Injectable } from '@nestjs/common'; import { IntegrationService } from '@gitroom/nestjs-libraries/database/prisma/integrations/integration.service'; import z from 'zod'; import { checkAuth } from '@gitroom/nestjs-libraries/chat/auth.context'; -import { getAuth } from '@gitroom/nestjs-libraries/chat/async.storage'; @Injectable() export class IntegrationListTool implements AgentToolInterface { @@ -28,14 +26,10 @@ export class IntegrationListTool implements AgentToolInterface { }) ), }), - execute: async (args, options) => { - console.log(getAuth()); - console.log(options); - const { context, runtimeContext } = args; - checkAuth(args, options); + execute: async (inputData, context) => { + checkAuth(inputData, context); const organizationId = JSON.parse( - // @ts-ignore - runtimeContext.get('organization') as string + (context?.requestContext as any)?.get('organization') as string ).id; return { diff --git a/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts b/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts index 078bea72..4155116e 100644 --- a/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts +++ b/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts @@ -114,17 +114,15 @@ If the tools return errors, you would need to rerun it with the right parameters ) .or(z.object({ errors: z.string() })), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); + execute: async (inputData, context) => { + checkAuth(inputData, context); const organizationId = JSON.parse( - // @ts-ignore - runtimeContext.get('organization') as string + (context?.requestContext as any)?.get('organization') as string ).id; const finalOutput = []; const integrations = {} as Record; - for (const platform of context.socialPost) { + for (const platform of inputData.socialPost) { integrations[platform.integrationId] = await this._integrationService.getIntegrationById( organizationId, @@ -142,7 +140,7 @@ If the tools return errors, you would need to rerun it with the right parameters const obj = Object.assign( newDTO, platform.settings.reduce( - (acc, s) => ({ + (acc: AllProvidersSettings, s: { key: string; value: any }) => ({ ...acc, [s.key]: s.value, }), @@ -180,7 +178,7 @@ If the tools return errors, you would need to rerun it with the right parameters } } - for (const post of context.socialPost) { + for (const post of inputData.socialPost) { const integration = integrations[post.integrationId]; if (!integration) { @@ -197,7 +195,7 @@ If the tools return errors, you would need to rerun it with the right parameters integration, group: makeId(10), settings: post.settings.reduce( - (acc, s) => ({ + (acc: AllProvidersSettings, s: { key: string; value: any }) => ({ ...acc, [s.key]: s.value, }), @@ -205,11 +203,11 @@ If the tools return errors, you would need to rerun it with the right parameters __type: integration.providerIdentifier, } as AllProvidersSettings ), - value: post.postsAndComments.map((p) => ({ + value: post.postsAndComments.map((p: any) => ({ content: p.content, id: makeId(10), delay: 0, - image: p.attachments.map((p) => ({ + image: p.attachments.map((p: any) => ({ id: makeId(10), path: p, })), diff --git a/libraries/nestjs-libraries/src/chat/tools/integration.trigger.tool.ts b/libraries/nestjs-libraries/src/chat/tools/integration.trigger.tool.ts index b03e7c5b..2f63f227 100644 --- a/libraries/nestjs-libraries/src/chat/tools/integration.trigger.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/integration.trigger.tool.ts @@ -43,19 +43,17 @@ export class IntegrationTriggerTool implements AgentToolInterface { outputSchema: z.object({ output: z.array(z.record(z.string(), z.any())), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); - console.log('triggerTool', context); + execute: async (inputData, context) => { + checkAuth(inputData, context); + console.log('triggerTool', inputData); const organizationId = JSON.parse( - // @ts-ignore - runtimeContext.get('organization') as string + (context?.requestContext as any)?.get('organization') as string ).id; const getIntegration = await this._integrationService.getIntegrationById( organizationId, - context.integrationId + inputData.integrationId ); if (!getIntegration) { @@ -78,10 +76,10 @@ export class IntegrationTriggerTool implements AgentToolInterface { if ( // @ts-ignore !tools[integrationProvider.identifier].some( - (p) => p.methodName === context.methodName + (p) => p.methodName === inputData.methodName ) || // @ts-ignore - !integrationProvider[context.methodName] + !integrationProvider[inputData.methodName] ) { return { output: 'tool not found' }; } @@ -89,14 +87,14 @@ export class IntegrationTriggerTool implements AgentToolInterface { while (true) { try { // @ts-ignore - const load = await integrationProvider[context.methodName]( + const load = await integrationProvider[inputData.methodName]( getIntegration.token, - context.dataSchema.reduce( - (all, current) => ({ + inputData.dataSchema.reduce( + (all: Record, current: { key: string; value: string }) => ({ ...all, [current.key]: current.value, }), - {} + {} as Record ), getIntegration.internalId, getIntegration diff --git a/libraries/nestjs-libraries/src/chat/tools/integration.validation.tool.ts b/libraries/nestjs-libraries/src/chat/tools/integration.validation.tool.ts index 1e1e28a0..13060979 100644 --- a/libraries/nestjs-libraries/src/chat/tools/integration.validation.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/integration.validation.tool.ts @@ -72,11 +72,10 @@ export class IntegrationValidationTool implements AgentToolInterface { ), }), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); + execute: async (inputData, context) => { + checkAuth(inputData, context); const integration = socialIntegrationList.find( - (p) => p.identifier === context.platform + (p) => p.identifier === inputData.platform )!; if (!integration) { @@ -85,7 +84,7 @@ export class IntegrationValidationTool implements AgentToolInterface { }; } - const maxLength = integration.maxLength(context.isPremium); + const maxLength = integration.maxLength(inputData.isPremium); const schemas = !integration.dto ? false : getValidationSchemas()[integration.dto.name]; diff --git a/libraries/nestjs-libraries/src/chat/tools/video.function.tool.ts b/libraries/nestjs-libraries/src/chat/tools/video.function.tool.ts index 2a116d91..4f4156cc 100644 --- a/libraries/nestjs-libraries/src/chat/tools/video.function.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/video.function.tool.ts @@ -22,14 +22,13 @@ export class VideoFunctionTool implements AgentToolInterface { identifier: z.string(), functionName: z.string(), }), - execute: async (args, options) => { - const { context, runtimeContext } = args; - checkAuth(args, options); + execute: async (inputData, context) => { + checkAuth(inputData, context); const videos = this._videoManagerService.getAllVideos(); const findVideo = videos.find( (p) => - p.identifier === context.identifier && - p.tools.some((p) => p.functionName === context.functionName) + p.identifier === inputData.identifier && + p.tools.some((p) => p.functionName === inputData.functionName) ); if (!findVideo) { @@ -39,7 +38,7 @@ export class VideoFunctionTool implements AgentToolInterface { const func = await this._moduleRef // @ts-ignore .get(findVideo.target, { strict: false }) - [context.functionName](); + [inputData.functionName](); return func; }, }); diff --git a/package.json b/package.json index 1fbd3fae..f1307977 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "test": "jest --coverage --detectOpenHandles --reporters=default --reporters=jest-junit" }, "dependencies": { - "@ag-ui/mastra": "0.2.0", + "@ag-ui/mastra": "^1.0.1", "@ai-sdk/openai": "^2.0.52", "@atproto/api": "^0.15.15", "@aws-sdk/client-s3": "^3.787.0", @@ -63,9 +63,10 @@ "@mantine/dates": "^5.10.5", "@mantine/hooks": "^5.10.5", "@mantine/modals": "^5.10.5", - "@mastra/core": "^0.20.2", - "@mastra/memory": "^0.15.6", - "@mastra/pg": "^0.17.2", + "@mastra/core": "^1.21.0", + "@mastra/mcp": "^1.4.1", + "@mastra/memory": "^1.13.0", + "@mastra/pg": "^1.8.5", "@modelcontextprotocol/sdk": "^1.22.0", "@nest-lab/throttler-storage-redis": "^1.2.0", "@nestjs/cli": "10.0.2", @@ -178,7 +179,7 @@ "json-to-graphql-query": "^2.2.5", "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", - "mastra": "^0.13.2", + "mastra": "^1.3.19", "md5": "^2.3.0", "mime": "^3.0.0", "mime-types": "^2.1.35", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 120c5fcb..058bb740 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,8 +17,8 @@ importers: .: dependencies: '@ag-ui/mastra': - specifier: 0.2.0 - version: 0.2.0(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(f12a340d274d725e3b3c5f801023ae18))(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) + specifier: ^1.0.1 + version: 1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(204b25c7c9e393334c406e7fe2b14723))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@ai-sdk/openai': specifier: ^2.0.52 version: 2.0.98(zod@3.25.76) @@ -45,7 +45,7 @@ importers: version: 1.10.6(@types/react@19.1.8)(graphql@16.13.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@copilotkit/runtime': specifier: 1.10.6 - version: 1.10.6(f12a340d274d725e3b3c5f801023ae18) + version: 1.10.6(204b25c7c9e393334c406e7fe2b14723) '@dub/analytics': specifier: ^0.0.32 version: 0.0.32 @@ -54,7 +54,7 @@ importers: version: 3.10.0(react-hook-form@7.71.2(react@19.2.4)) '@langchain/community': specifier: ^0.3.40 - version: 0.3.59(9266573ded5fda56099eca4ab106a463) + version: 0.3.59(45cfa14f738c5b504e0280393b96505c) '@langchain/core': specifier: ^0.3.44 version: 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) @@ -77,14 +77,17 @@ importers: specifier: ^5.10.5 version: 5.10.5(@mantine/core@5.10.5(@emotion/react@11.14.0(@types/react@19.1.8)(react@19.2.4))(@mantine/hooks@5.10.5(react@19.2.4))(@types/react@19.1.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@5.10.5(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@mastra/core': - specifier: ^0.20.2 - version: 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) + specifier: ^1.21.0 + version: 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@mastra/mcp': + specifier: ^1.4.1 + version: 1.4.1(@cfworker/json-schema@4.1.1)(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(@types/json-schema@7.0.15)(zod@3.25.76) '@mastra/memory': - specifier: ^0.15.6 - version: 0.15.13(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(react@19.2.4)(zod@3.25.76) + specifier: ^1.13.0 + version: 1.13.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@mastra/pg': - specifier: ^0.17.2 - version: 0.17.10(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(pg-query-stream@4.10.3(pg@8.16.3)) + specifier: ^1.8.5 + version: 1.8.5(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76)) '@meronex/icons': specifier: ^4.0.0 version: 4.0.0(react@19.2.4) @@ -96,7 +99,7 @@ importers: version: 1.2.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@nestjs/throttler@6.5.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(reflect-metadata@0.1.14))(ioredis@5.10.0)(reflect-metadata@0.1.14) '@nestjs/cli': specifier: 10.0.2 - version: 10.0.2(@swc/cli@0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + version: 10.0.2(@swc/cli@0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) '@nestjs/common': specifier: ^10.0.2 version: 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2) @@ -138,7 +141,7 @@ importers: version: 10.45.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22) '@sentry/nextjs': specifier: ^10.26.0 - version: 10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.2.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + version: 10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.2.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) '@sentry/profiling-node': specifier: ^10.25.0 version: 10.45.0 @@ -177,7 +180,7 @@ importers: version: 1.15.0 '@temporalio/worker': specifier: ^1.14.0 - version: 1.15.0(@swc/helpers@0.5.13)(esbuild@0.25.12)(tslib@2.8.1) + version: 1.15.0(@swc/helpers@0.5.13)(esbuild@0.27.7)(tslib@2.8.1) '@temporalio/workflow': specifier: ^1.14.0 version: 1.15.0 @@ -425,8 +428,8 @@ importers: specifier: ^4.17.21 version: 4.17.23 mastra: - specifier: ^0.13.2 - version: 0.13.4(@cfworker/json-schema@4.1.1)(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@opentelemetry/api@1.9.0)(@types/json-schema@7.0.15)(typescript@5.5.4)(zod@3.25.76) + specifier: ^1.3.19 + version: 1.3.19(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(typescript@5.5.4)(zod@3.25.76) md5: specifier: ^2.3.0 version: 2.3.0 @@ -450,7 +453,7 @@ importers: version: 3.0.1(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2)) nestjs-temporal-core: specifier: ^3.2.0 - version: 3.2.3(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@temporalio/client@1.15.0)(@temporalio/common@1.15.0)(@temporalio/worker@1.15.0(@swc/helpers@0.5.13)(esbuild@0.25.12)(tslib@2.8.1))(@temporalio/workflow@1.15.0)(reflect-metadata@0.1.14)(rxjs@7.8.2) + version: 3.2.3(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@temporalio/client@1.15.0)(@temporalio/common@1.15.0)(@temporalio/worker@1.15.0(@swc/helpers@0.5.13)(esbuild@0.27.7)(tslib@2.8.1))(@temporalio/workflow@1.15.0)(reflect-metadata@0.1.14)(rxjs@7.8.2) next: specifier: 16.2.1 version: 16.2.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) @@ -655,7 +658,7 @@ importers: version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22) '@pmmmwh/react-refresh-webpack-plugin': specifier: ^0.5.7 - version: 0.5.17(react-refresh@0.10.0)(type-fest@4.41.0)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + version: 0.5.17(react-refresh@0.10.0)(type-fest@4.41.0)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) '@svgr/webpack': specifier: ^8.0.1 version: 8.1.0(typescript@5.5.4) @@ -793,7 +796,7 @@ importers: version: 0.10.0 ts-jest: specifier: ^29.1.0 - version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(esbuild@0.25.12)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4)))(typescript@5.5.4) + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(esbuild@0.27.7)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4)))(typescript@5.5.4) ts-node: specifier: 10.9.2 version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4) @@ -866,14 +869,14 @@ packages: '@ag-ui/client': '>=0.0.42' '@ag-ui/core': '>=0.0.42' - '@ag-ui/mastra@0.2.0': - resolution: {integrity: sha512-4d2LwT15I/B87HSeEMqqtdy2n9L+FieAhVmYK6XFSImWnXS4G0YVe+qfncIHMwRnq4XtGM8F9uq6tzaMK8/qdA==} + '@ag-ui/mastra@1.0.1': + resolution: {integrity: sha512-8XcsAdZVweiQU7HeZW4sD9x4oXOk3VJ7piK3eihwIzVkEvd8YtfiPgwNlOzNxT6my8IHaHIuKtAlxLS/wo3TKQ==} peerDependencies: - '@ag-ui/client': '>=0.0.40' - '@ag-ui/core': '>=0.0.39' - '@copilotkit/runtime': ^1.10.5 - '@mastra/core': '>=0.20.1' - zod: ^3.25.67 + '@ag-ui/client': '>=0.0.44' + '@ag-ui/core': '>=0.0.44' + '@copilotkit/runtime': 0.0.0-mme-ag-ui-0-0-46-20260227141603 + '@mastra/client-js': '>=1.0.0-0 <2.0.0-0' + '@mastra/core': '>=1.0.0-0 <2.0.0-0' '@ag-ui/proto@0.0.47': resolution: {integrity: sha512-+KCrkeVeR6MulWoYUq9Fwm22gFlI9aKG50eKYRtbTM/Yuei/Che5vjbF297XfSnGUunzScrOmdnTeTCprrtb7A==} @@ -926,12 +929,24 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@3.0.20': + resolution: {integrity: sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@3.0.22': resolution: {integrity: sha512-fFT1KfUUKktfAFm5mClJhS1oux9tP2qgzmEZVl5UdwltQ1LO/s8hd7znVrgKzivwv1s1FIPza0s9OpJaNB/vHw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@4.0.0': + resolution: {integrity: sha512-HyCyOls9I3a3e38+gtvOJOEjuw9KRcvbBnCL5GBuSmJvS9Jh9v3fz7pRC6ha1EUo/ZH1zwvLWYXBMtic8MTguA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider@1.1.3': resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} engines: {node: '>=18'} @@ -944,6 +959,14 @@ packages: resolution: {integrity: sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==} engines: {node: '>=18'} + '@ai-sdk/provider@3.0.0': + resolution: {integrity: sha512-m9ka3ptkPQbaHHZHqDXDF9C9B5/Mav0KTdky1k2HZ3/nrW2t1AgObxIVPyGDWQNS9FXT/FS6PIoSjpcP/No8rQ==} + engines: {node: '>=18'} + + '@ai-sdk/provider@3.0.5': + resolution: {integrity: sha512-2Xmoq6DBJqmSl80U6V9z5jJSJP7ehaJJQMy2iFUqTay06wdCqTnPVBBQbtEL8RCChenL+q5DC5H5WzU3vV3v8w==} + engines: {node: '>=18'} + '@ai-sdk/react@1.2.12': resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==} engines: {node: '>=18'} @@ -1944,11 +1967,11 @@ packages: '@cfworker/json-schema@4.1.1': resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} - '@clack/core@0.5.0': - resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + '@clack/core@1.2.0': + resolution: {integrity: sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg==} - '@clack/prompts@0.11.0': - resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + '@clack/prompts@1.2.0': + resolution: {integrity: sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w==} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -2104,6 +2127,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} @@ -2116,6 +2145,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} @@ -2128,6 +2163,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} @@ -2140,6 +2181,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} @@ -2152,6 +2199,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} @@ -2164,6 +2217,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} @@ -2176,6 +2235,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} @@ -2188,6 +2253,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} @@ -2200,6 +2271,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} @@ -2212,6 +2289,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} @@ -2224,6 +2307,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} @@ -2236,6 +2325,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} @@ -2248,6 +2343,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} @@ -2260,6 +2361,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} @@ -2272,6 +2379,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} @@ -2284,6 +2397,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} @@ -2296,6 +2415,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} @@ -2308,6 +2433,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} @@ -2320,6 +2451,12 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} @@ -2332,6 +2469,12 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} @@ -2344,6 +2487,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} @@ -2356,6 +2505,12 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} @@ -2368,6 +2523,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} @@ -2380,6 +2541,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} @@ -2392,6 +2559,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} @@ -2404,6 +2577,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2867,6 +3046,10 @@ packages: resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} + '@isaacs/ttlcache@2.1.4': + resolution: {integrity: sha512-7kMz0BJpMvgAMkyglums7B2vtrn5g0a0am77JY0GjkZZNetOBCFn7AG7gKCwT0QPiXyxW7YIQSgtARknUEOcxQ==} + engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -3688,33 +3871,44 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 - '@mastra/deployer@0.19.1': - resolution: {integrity: sha512-J1jC+BnR7VPEodraHO7IWswhAxbDOX/TPuO3+0kOM5efS95nHdTx2P6HwoensRdpyOmoimN3nHG8ApeP1VePOA==} + '@mastra/core@1.21.0': + resolution: {integrity: sha512-DgFZpdvR1XR6tE/ocX+bhjlzGfjuSDPfiF0aWFYXpmvs66fKeLE/S/tWxkhWOPGr64e3fCU6U1GGOaPI1nh7OA==} + engines: {node: '>=22.13.0'} peerDependencies: - '@mastra/core': '>=0.19.1-0 <0.20.0-0' zod: ^3.25.0 || ^4.0.0 - '@mastra/loggers@0.10.19': - resolution: {integrity: sha512-H4qTgqKt3YJxz6B1I0lOPqRpOpR8gEzYYNZ6iO/TGQ11r+wvug/i80MAKr0B1IBZvr9l18vr7wjYCdTxPqaAGg==} + '@mastra/deployer@1.21.0': + resolution: {integrity: sha512-+B9z1bNCS+cXHHy8GRtNzYP9N5zjRucK3MicSc28fzPCxGib7SbqDJdLvUIRdtaxBLG9chKqM2enToPuALKwSQ==} + engines: {node: '>=22.13.0'} peerDependencies: - '@mastra/core': '>=0.18.1-0 <0.25.0-0' - - '@mastra/mcp@0.13.5': - resolution: {integrity: sha512-GFHOHTbUY8PuEwzObIVCaHF855M4S4xIOnNJE1WJeEsPvWOllyL+y1Wz3HGjusrAfZIDrZ8j8Z5Diqxf3KTW/A==} - peerDependencies: - '@mastra/core': '>=0.20.1-0 <0.22.0-0' + '@mastra/core': '>=1.0.0-0 <2.0.0-0' zod: ^3.25.0 || ^4.0.0 - '@mastra/memory@0.15.13': - resolution: {integrity: sha512-88RBgT1VIseyvKdkzVJFw88gtFmf/+6vOMwJaeLzSq++oHtoD+A0nkUvCtuX3aYsicpf5IPUBnvEgJ9pH6J/gg==} + '@mastra/loggers@1.1.0': + resolution: {integrity: sha512-SwEsBsckP3/00th4iV80k5/rj2OjaArIR8fedPq4MMnWS1a6HurXjnFF4ISGHuiTVvsx15a+3sRVy0IfSFp+QQ==} + engines: {node: '>=22.13.0'} peerDependencies: - '@mastra/core': '>=0.20.1-0 <0.25.0-0' + '@mastra/core': '>=1.0.0-0 <2.0.0-0' + + '@mastra/mcp@1.4.1': + resolution: {integrity: sha512-LvFSh7NlKB7sMNfJKy/38h4QNN49Kqo6MmeM4mT6l3D8obUyYaFtrscmosuEoD7JnRx0ASuptGWKW0x+Afxp1Q==} + engines: {node: '>=22.13.0'} + peerDependencies: + '@mastra/core': '>=1.0.0-0 <2.0.0-0' zod: ^3.25.0 || ^4.0.0 - '@mastra/pg@0.17.10': - resolution: {integrity: sha512-+aP8FpDI6Y32ZO4TYqVdxWtoJXc4ZUp0joltRZwUwazond8WB7i7ZTw8BzWoaKsEcEumf5EMoYwxUPJrV90sZA==} + '@mastra/memory@1.13.0': + resolution: {integrity: sha512-fNAQ/C2ArKhmZwcRoy8oD1dEDKdIXyZrFMFX52GJzPcntlKx5YsL58BOB3kilFi/kFzfEE6h3nemv0CgI7l+SA==} + engines: {node: '>=22.13.0'} peerDependencies: - '@mastra/core': '>=0.20.1-0 <0.25.0-0' + '@mastra/core': '>=1.4.1-0 <2.0.0-0' + zod: ^3.25.0 || ^4.0.0 + + '@mastra/pg@1.8.5': + resolution: {integrity: sha512-TNHA1KfgLrFjkjxuCDvn0s2Kqd9J4ivxbqGxOG4LA43SP8djYVoergigk5Us1JDktFIxGQru/HmS3HIOti0/tg==} + engines: {node: '>=22.13.0'} + peerDependencies: + '@mastra/core': '>=1.4.0-0 <2.0.0-0' '@mastra/schema-compat@0.11.4': resolution: {integrity: sha512-oh3+enP3oYftZlmJAKQQj5VXR86KgTMwfMnwALZyLk04dPSWfVD2wGytoDg5Qbi3rX9qHj6g0rMNa0CUjR6aTg==} @@ -3722,16 +3916,17 @@ packages: ai: ^4.0.0 || ^5.0.0 zod: ^3.25.0 || ^4.0.0 - '@mastra/schema-compat@0.11.9': - resolution: {integrity: sha512-LXEChx5n3bcuSFWQ5Wn9K2spLEpzHGf+DCnAeryuecpOo8VGLJ2QCK9Ugsnfjuc6hC0Ha73HvL1AD8zDhjmYOg==} + '@mastra/schema-compat@1.2.7': + resolution: {integrity: sha512-t63E0f5HcH8neXPfs3D5x4qqQM6Pf/pbhFUVk0cTC0bFo6609sT/+189I+2HY4sbAF3uzurOgy2fXIS4vfMkOA==} + engines: {node: '>=22.13.0'} peerDependencies: - ai: ^4.0.0 || ^5.0.0 zod: ^3.25.0 || ^4.0.0 - '@mastra/server@0.19.1': - resolution: {integrity: sha512-JN1CyUf8C+MjpCuGVaRA2RMpUOsl2Cum2oNm5NZlwa9CIKdiU4pO2mF3Fa7/I7xsx3rQSBoaFv9ItvFXOob+MQ==} + '@mastra/server@1.21.0': + resolution: {integrity: sha512-VZTzNlsumEpibXjvDDyTbY9UzBgwa+TGO7CRReP+oaqfxu+kFi98ni9LuVGRQ8Hm9RhzuaO+PeRaVkxKgLN9oQ==} + engines: {node: '>=22.13.0'} peerDependencies: - '@mastra/core': '>=0.19.1-0 <0.20.0-0' + '@mastra/core': '>=1.13.2-0 <2.0.0-0' zod: ^3.25.0 || ^4.0.0 '@meronex/icons@4.0.0': @@ -3991,9 +4186,6 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@neon-rs/load@0.1.82': - resolution: {integrity: sha512-H4Gu2o5kPp+JOEhRrOQCnJnf7X6sv9FBLttM/wSbb4efsgFWeHzfU/ItZ01E5qqEk+U6QGdeVO7lxXIAtYHr5A==} - '@nest-lab/throttler-storage-redis@1.2.0': resolution: {integrity: sha512-tMkUyo68NCKTR+zILk+EC35SMYBtDPZY2mCj7ZaCietWGVTnuP4zwq9ERYfvU6kJv6h8teNZrC6MJCmY6/dljw==} peerDependencies: @@ -5220,6 +5412,9 @@ packages: '@posthog/core@1.23.2': resolution: {integrity: sha512-zTDdda9NuSHrnwSOfFMxX/pyXiycF4jtU1kTr8DL61dHhV+7LF6XF1ndRZZTuaGGbfbb/GJYkEsjEX9SXfNZeQ==} + '@posthog/core@1.7.1': + resolution: {integrity: sha512-kjK0eFMIpKo9GXIbts8VtAknsoZ18oZorANdtuTj1CbgS28t4ZVq//HAWhnxEuXRTrtkd+SUJ6Ux3j2Af8NCuA==} + '@posthog/types@1.359.1': resolution: {integrity: sha512-oQihoHWLnOkSkzOToCWKNigbJ7UZcIkl+rSJuq2PLwL7EB0Q/r1UGSbVCkrPH8xtPbYpi7w4TVpMrg41TMT+LQ==} @@ -5751,25 +5946,10 @@ packages: peerDependencies: '@redis/client': ^1.0.0 - '@redis/bloom@5.11.0': - resolution: {integrity: sha512-KYiVilAhAFN3057afUb/tfYJpsEyTkQB+tQcn5gVVA7DgcNOAj8lLxe4j8ov8BF6I9C1Fe/kwlbuAICcTMX8Lw==} - engines: {node: '>= 18'} - peerDependencies: - '@redis/client': ^5.11.0 - '@redis/client@1.6.1': resolution: {integrity: sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==} engines: {node: '>=14'} - '@redis/client@5.11.0': - resolution: {integrity: sha512-GHoprlNQD51Xq2Ztd94HHV94MdFZQ3CVrpA04Fz8MVoHM0B7SlbmPEVIjwTbcv58z8QyjnrOuikS0rWF03k5dQ==} - engines: {node: '>= 18'} - peerDependencies: - '@node-rs/xxhash': ^1.1.0 - peerDependenciesMeta: - '@node-rs/xxhash': - optional: true - '@redis/graph@1.1.1': resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==} peerDependencies: @@ -5780,34 +5960,16 @@ packages: peerDependencies: '@redis/client': ^1.0.0 - '@redis/json@5.11.0': - resolution: {integrity: sha512-1iAy9kAtcD0quB21RbPTbUqqy+T2Uu2JxucwE+B4A+VaDbIRvpZR6DMqV8Iqaws2YxJYB3GC5JVNzPYio2ErUg==} - engines: {node: '>= 18'} - peerDependencies: - '@redis/client': ^5.11.0 - '@redis/search@1.2.0': resolution: {integrity: sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==} peerDependencies: '@redis/client': ^1.0.0 - '@redis/search@5.11.0': - resolution: {integrity: sha512-g1l7f3Rnyk/xI99oGHIgWHSKFl45Re5YTIcO8j/JE8olz389yUFyz2+A6nqVy/Zi031VgPDWscbbgOk8hlhZ3g==} - engines: {node: '>= 18'} - peerDependencies: - '@redis/client': ^5.11.0 - '@redis/time-series@1.1.0': resolution: {integrity: sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==} peerDependencies: '@redis/client': ^1.0.0 - '@redis/time-series@5.11.0': - resolution: {integrity: sha512-TWFeOcU4xkj0DkndnOyhtxvX1KWD+78UHT3XX3x3XRBUGWeQrKo3jqzDsZwxbggUgf9yLJr/akFHXru66X5UQA==} - engines: {node: '>= 18'} - peerDependencies: - '@redis/client': ^5.11.0 - '@remirror/core-constants@3.0.0': resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} @@ -5843,11 +6005,11 @@ packages: '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@rollup/plugin-alias@5.1.1': - resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} - engines: {node: '>=14.0.0'} + '@rollup/plugin-alias@6.0.0': + resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==} + engines: {node: '>=20.19.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + rollup: '>=4.0.0' peerDependenciesMeta: rollup: optional: true @@ -5861,8 +6023,8 @@ packages: rollup: optional: true - '@rollup/plugin-commonjs@28.0.9': - resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==} + '@rollup/plugin-commonjs@29.0.2': + resolution: {integrity: sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 @@ -5919,111 +6081,56 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.50.2': - resolution: {integrity: sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==} - cpu: [arm] - os: [android] - '@rollup/rollup-android-arm-eabi@4.59.0': resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.50.2': - resolution: {integrity: sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==} - cpu: [arm64] - os: [android] - '@rollup/rollup-android-arm64@4.59.0': resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.50.2': - resolution: {integrity: sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==} - cpu: [arm64] - os: [darwin] - '@rollup/rollup-darwin-arm64@4.59.0': resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.50.2': - resolution: {integrity: sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==} - cpu: [x64] - os: [darwin] - '@rollup/rollup-darwin-x64@4.59.0': resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.50.2': - resolution: {integrity: sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==} - cpu: [arm64] - os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.59.0': resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.50.2': - resolution: {integrity: sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==} - cpu: [x64] - os: [freebsd] - '@rollup/rollup-freebsd-x64@4.59.0': resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.50.2': - resolution: {integrity: sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.50.2': - resolution: {integrity: sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.59.0': resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.50.2': - resolution: {integrity: sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.59.0': resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.50.2': - resolution: {integrity: sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-musl@4.59.0': resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.50.2': - resolution: {integrity: sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==} - cpu: [loong64] - os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.59.0': resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] @@ -6034,11 +6141,6 @@ packages: cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.50.2': - resolution: {integrity: sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==} - cpu: [ppc64] - os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.59.0': resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] @@ -6049,51 +6151,26 @@ packages: cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.50.2': - resolution: {integrity: sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.59.0': resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.50.2': - resolution: {integrity: sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.59.0': resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.50.2': - resolution: {integrity: sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==} - cpu: [s390x] - os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.59.0': resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.50.2': - resolution: {integrity: sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-gnu@4.59.0': resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.50.2': - resolution: {integrity: sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-musl@4.59.0': resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] @@ -6104,31 +6181,16 @@ packages: cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.50.2': - resolution: {integrity: sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==} - cpu: [arm64] - os: [openharmony] - '@rollup/rollup-openharmony-arm64@4.59.0': resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.50.2': - resolution: {integrity: sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==} - cpu: [arm64] - os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.59.0': resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.50.2': - resolution: {integrity: sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==} - cpu: [ia32] - os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.59.0': resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] @@ -6139,11 +6201,6 @@ packages: cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.50.2': - resolution: {integrity: sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==} - cpu: [x64] - os: [win32] - '@rollup/rollup-win32-x64-msvc@4.59.0': resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] @@ -6967,6 +7024,67 @@ packages: peerDependencies: '@solana/web3.js': '*' + '@standard-community/standard-json@0.3.5': + resolution: {integrity: sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA==} + peerDependencies: + '@standard-schema/spec': ^1.0.0 + '@types/json-schema': ^7.0.15 + '@valibot/to-json-schema': ^1.3.0 + arktype: ^2.1.20 + effect: ^3.16.8 + quansync: ^0.2.11 + sury: ^10.0.0 + typebox: ^1.0.17 + valibot: ^1.1.0 + zod: ^3.25.0 || ^4.0.0 + zod-to-json-schema: ^3.24.5 + peerDependenciesMeta: + '@valibot/to-json-schema': + optional: true + arktype: + optional: true + effect: + optional: true + sury: + optional: true + typebox: + optional: true + valibot: + optional: true + zod: + optional: true + zod-to-json-schema: + optional: true + + '@standard-community/standard-openapi@0.2.9': + resolution: {integrity: sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg==} + peerDependencies: + '@standard-community/standard-json': ^0.3.5 + '@standard-schema/spec': ^1.0.0 + arktype: ^2.1.20 + effect: ^3.17.14 + openapi-types: ^12.1.3 + sury: ^10.0.0 + typebox: ^1.0.0 + valibot: ^1.1.0 + zod: ^3.25.0 || ^4.0.0 + zod-openapi: ^4 + peerDependenciesMeta: + arktype: + optional: true + effect: + optional: true + sury: + optional: true + typebox: + optional: true + valibot: + optional: true + zod: + optional: true + zod-openapi: + optional: true + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -8641,9 +8759,6 @@ packages: '@webcomponents/custom-elements@1.6.0': resolution: {integrity: sha512-CqTpxOlUCPWRNUPZDxT5v2NnHXA4oox612iUGnmTUGQFhZ1Gkj8kirtl/2wcF6MqX7+PqqicZzOCBKKfIn0dww==} - '@webcontainer/env@1.1.1': - resolution: {integrity: sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==} - '@whatwg-node/disposablestack@0.0.6': resolution: {integrity: sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==} engines: {node: '>=18.0.0'} @@ -8686,6 +8801,9 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@zeit/schemas@2.36.0': + resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} + abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead @@ -8844,6 +8962,9 @@ packages: anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -8984,10 +9105,6 @@ packages: asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - assert-options@0.8.3: - resolution: {integrity: sha512-s6v4HnA+vYSGO4eZX+F+I3gvF74wPk+m6Z1Q3w1Dsg4Pnv/R24vhKAasoMVZGvDpOOfTg1Qz4ptZnEbuy95XsQ==} - engines: {node: '>=14.0.0'} - assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} @@ -9231,6 +9348,10 @@ packages: bowser@2.14.1: resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + boxen@7.0.0: + resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} + engines: {node: '>=14.16'} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -9311,13 +9432,6 @@ packages: resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} engines: {node: '>=6.14.2'} - builtins@5.1.0: - resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} - - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} - bundle-require@5.1.0: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -9328,6 +9442,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -9378,6 +9496,10 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} + camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + caniuse-lite@1.0.30001777: resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} @@ -9401,10 +9523,18 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + chalk-template@0.4.0: + resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} + engines: {node: '>=12'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.0.1: + resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -9532,6 +9662,10 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -9555,6 +9689,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + clipboardy@3.0.0: + resolution: {integrity: sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -9751,6 +9889,10 @@ packages: constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + content-disposition@0.5.2: + resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} + engines: {node: '>= 0.6'} + content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -10002,9 +10144,6 @@ packages: date-fns@3.6.0: resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} @@ -10030,15 +10169,6 @@ packages: supports-color: optional: true - debug@4.3.1: - resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -10086,6 +10216,10 @@ packages: resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} engines: {node: '>= 0.4'} + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -10097,14 +10231,6 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - default-browser-id@5.0.1: - resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} - engines: {node: '>=18'} - - default-browser@5.5.0: - resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} - engines: {node: '>=18'} - defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -10116,10 +10242,6 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -10285,6 +10407,10 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dotenv@17.4.0: + resolution: {integrity: sha512-kCKF62fwtzwYm0IGBNjRUjtJgMfGapII+FslMHIjMR5KTnwEmBmWLDRSnc3XSNP8bNy34tekgQyDT0hr7pERRQ==} + engines: {node: '>=12'} + draggabilly@3.0.0: resolution: {integrity: sha512-aEs+B6prbMZQMxc9lgTpCBfyCUhRur/VFucHhIOvlvvdARTj7TcDmX/cdOUtqbjJJUh7+agyJXR5Z6IFe1MxwQ==} @@ -10469,6 +10595,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -10735,9 +10866,9 @@ packages: exifr@7.1.3: resolution: {integrity: sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==} - exit-hook@4.0.0: - resolution: {integrity: sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==} - engines: {node: '>=18'} + exit-hook@5.1.0: + resolution: {integrity: sha512-INjr2xyxHo7bhAqf5ong++GZPPnpcuBcaXUKt03yf7Fie9yWD7FapL4teOU0+awQazGs5ucBh7xWs/AD+6nhog==} + engines: {node: '>=20'} exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} @@ -10779,6 +10910,10 @@ packages: resolution: {integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==} engines: {node: '>=4'} + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -10843,12 +10978,21 @@ packages: fast-stable-stringify@1.0.0: resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + fast-string-truncated-width@1.2.1: + resolution: {integrity: sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==} + + fast-string-width@1.1.0: + resolution: {integrity: sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==} + fast-text-encoding@1.0.6: resolution: {integrity: sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==} fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-wrap-ansi@0.1.6: + resolution: {integrity: sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==} + fast-xml-builder@1.0.0: resolution: {integrity: sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==} @@ -11344,6 +11488,10 @@ packages: resolution: {integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + groq-sdk@0.5.0: resolution: {integrity: sha512-RVmhW7qZ+XZoy5fIuSdx/LGQJONpL8MHgZEW7dFwTdgkzStub2XQx6OKv28CHogijdwH41J+Npj/z2jBPu3vmw==} @@ -11581,6 +11729,25 @@ packages: zod-openapi: optional: true + hono-openapi@1.3.0: + resolution: {integrity: sha512-xDvCWpWEIv0weEmnl3EjRQzqbHIO8LnfzMuYOCmbuyE5aes6aXxLg4vM3ybnoZD5TiTUkA6PuRQPJs3R7WRBig==} + peerDependencies: + '@hono/standard-validator': ^0.2.0 + '@standard-community/standard-json': ^0.3.5 + '@standard-community/standard-openapi': ^0.2.9 + '@types/json-schema': ^7.0.15 + hono: ^4.8.3 + openapi-types: ^12.1.3 + peerDependenciesMeta: + '@hono/standard-validator': + optional: true + hono: + optional: true + + hono@4.12.10: + resolution: {integrity: sha512-mx/p18PLy5og9ufies2GOSUqep98Td9q4i/EF6X7yJgAiIopxqdfIO3jbqsi3jRgTgw88jMDEzVKi+V2EF+27w==} + engines: {node: '>=16.9.0'} + hono@4.12.5: resolution: {integrity: sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==} engines: {node: '>=16.9.0'} @@ -11730,6 +11897,11 @@ packages: engines: {node: '>=16.x'} hasBin: true + image-size@2.0.2: + resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} + engines: {node: '>=16.x'} + hasBin: true + image-to-pdf@3.0.2: resolution: {integrity: sha512-6/IQCt4f384zjQ1w8P7FHIN/tF0mau8RbAIydT/+wyfZ1RAb8E2fiKe9t/k0V880h0d3zRpw9Q1bM5AIgVL/4g==} @@ -11816,10 +11988,6 @@ packages: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} - ip-regex@4.3.0: - resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} - engines: {node: '>=8'} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -11910,10 +12078,9 @@ packages: engines: {node: '>=8'} hasBin: true - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} is-extendable@1.0.1: resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} @@ -11952,11 +12119,6 @@ packages: is-hotkey@0.1.8: resolution: {integrity: sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==} - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} @@ -12015,6 +12177,10 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + is-port-reachable@4.0.0: + resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -12071,9 +12237,6 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} - is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -12090,14 +12253,6 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.1: - resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} - engines: {node: '>=16'} - - is2@2.0.9: - resolution: {integrity: sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==} - engines: {node: '>=v0.10.0'} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -12550,6 +12705,10 @@ packages: keyvaluestorage-interface@1.0.0: resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -12919,6 +13078,10 @@ packages: resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} + lru-cache@11.2.7: + resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} + engines: {node: 20 || >=22} + lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -12988,11 +13151,12 @@ packages: marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - mastra@0.13.4: - resolution: {integrity: sha512-p9abBTH65OgmZwQVDLkegikeuEg7kruKHOs9IKc2slrv83FcCXGevQDNMWa533iuAjEOE2ev85jcsZ+7ZSpKLA==} + mastra@1.3.19: + resolution: {integrity: sha512-ZN1ZQ4mjK2t9KNdD/kSBNr4m2TlEfcbGxWGHtnVQ5bU6Vn0YywCDhESEa+4djIVO88jkqb+8ETFavsTiCecLsg==} + engines: {node: '>=22.13.0'} hasBin: true peerDependencies: - '@mastra/core': '>=0.17.0-0 <0.20.0-0' + '@mastra/core': '>=1.1.0-0 <2.0.0-0' zod: ^3.25.0 || ^4.0.0 material-icons@1.13.14: @@ -13344,6 +13508,10 @@ packages: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true + mime-db@1.33.0: + resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} + engines: {node: '>= 0.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -13355,6 +13523,10 @@ packages: mime-match@1.0.2: resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==} + mime-types@2.1.18: + resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -13491,9 +13663,6 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -13562,6 +13731,11 @@ packages: resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} hasBin: true + needle@2.9.1: + resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -13870,10 +14044,6 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - open@10.2.0: - resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} - engines: {node: '>=18'} - open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -14023,6 +14193,10 @@ packages: resolution: {integrity: sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==} engines: {node: '>=16.17'} + p-retry@7.1.1: + resolution: {integrity: sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==} + engines: {node: '>=20'} + p-timeout@3.2.0: resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} engines: {node: '>=8'} @@ -14116,6 +14290,9 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + path-is-inside@1.0.2: + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} + path-key@2.0.1: resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} engines: {node: '>=4'} @@ -14189,51 +14366,22 @@ packages: pg-connection-string@2.12.0: resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} - pg-cursor@2.19.0: - resolution: {integrity: sha512-J5cF1MUz7LRJ9emOqF/06QjabMHMZy587rSPF0UuA8rCwKeeYl2co8Pp+6k5UU9YrAYHMzWkLxilfZB0hqsWWw==} - peerDependencies: - pg: ^8 - pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-minify@1.8.0: - resolution: {integrity: sha512-jO/oJOununpx8DzKgvSsWm61P8JjwXlaxSlbbfTBo1nvSWoo/+I6qZYaSN96jm/KDwa5d+JMQwPGgcP6HXDRow==} - engines: {node: '>=16.0.0'} - pg-pool@3.13.0: resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} peerDependencies: pg: '>=8.0' - pg-promise@11.15.0: - resolution: {integrity: sha512-EUXpXn90yPVPKxQH4qqUAEVcApd2tp/JdR3wG6LzBUgaXTUYqwmuXG4vFhhZTCctzhfzRA20EbORb9H4aAgUHA==} - engines: {node: '>=16.0'} - peerDependencies: - pg-query-stream: 4.10.3 - pg-protocol@1.13.0: resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - pg-query-stream@4.10.3: - resolution: {integrity: sha512-h2utrzpOIzeT9JfaqfvBbVuvCfBjH86jNfVrGGTbyepKAIOyTfDew0lAt8bbJjs9n/I5bGDl7S2sx6h5hPyJxw==} - peerDependencies: - pg: ^8 - pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.16.3: - resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - pg@8.20.0: resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} engines: {node: '>= 16.0.0'} @@ -14288,6 +14436,10 @@ packages: pino-std-serializers@7.1.0: resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true + pino@7.11.0: resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} hasBin: true @@ -14431,16 +14583,12 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} - postgres@3.4.8: - resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==} - engines: {node: '>=12'} - posthog-js@1.359.1: resolution: {integrity: sha512-Gy/eX02im6ON0zMxfTR61GNk1sjgLT9rVGfBQ5C757/WS4mN3vTUJveQYoX9jr3y0pqPZ57DqCcf6zcw++bpzQ==} - posthog-node@4.18.0: - resolution: {integrity: sha512-XROs1h+DNatgKh/AlIlCtDxWzwrKdYDb2mOs58n4yN8BkGN9ewqeQwG5ApS4/IzwCb7HPttUkOVulkYatd2PIw==} - engines: {node: '>=15.0.0'} + posthog-node@5.17.2: + resolution: {integrity: sha512-lz3YJOr0Nmiz0yHASaINEDHqoV+0bC3eD8aZAG+Ky292dAnVYul+ga/dMX8KCBXg8hHfKdxw0SztYD5j6dgUqQ==} + engines: {node: '>=20'} preact@10.28.4: resolution: {integrity: sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==} @@ -14493,6 +14641,9 @@ packages: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + probe-image-size@7.2.3: + resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -14735,6 +14886,10 @@ packages: randomfill@1.0.4: resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + range-parser@1.2.0: + resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} + engines: {node: '>= 0.6'} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -14750,6 +14905,10 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + react-colorful@5.6.1: resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} peerDependencies: @@ -15086,10 +15245,6 @@ packages: redis@4.7.1: resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==} - redis@5.11.0: - resolution: {integrity: sha512-YwXjATVDT+AuxcyfOwZn046aml9jMlQPvU1VXIlLDVAExe0u93aTfPYSeRgG4p9Q/Jlkj+LXJ1XEoFV+j2JKcQ==} - engines: {node: '>= 18'} - redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} @@ -15130,6 +15285,13 @@ packages: resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} engines: {node: '>=4'} + registry-auth-token@3.3.2: + resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} + + registry-url@3.1.0: + resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} + engines: {node: '>=0.10.0'} + regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} @@ -15326,22 +15488,11 @@ packages: esbuild: '>=0.18.0' rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 - rollup-plugin-node-externals@8.1.2: - resolution: {integrity: sha512-EuB6/lolkMLK16gvibUjikERq5fCRVIGwD2xue/CrM8D0pz5GXD2V6N8IrgxegwbcUoKkUFI8VYCEEv8MMvgpA==} - engines: {node: '>= 21 || ^20.6.0 || ^18.19.0'} - peerDependencies: - rollup: ^4.0.0 - rollup@2.79.2: resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} engines: {node: '>=10.0.0'} hasBin: true - rollup@4.50.2: - resolution: {integrity: sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - rollup@4.59.0: resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -15367,10 +15518,6 @@ packages: resolution: {integrity: sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==} engines: {node: '>=6.0.0', npm: '>=3.10.0'} - run-applescript@7.1.0: - resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} - engines: {node: '>=18'} - run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -15462,6 +15609,10 @@ packages: sdp@2.12.0: resolution: {integrity: sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==} + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} @@ -15508,6 +15659,9 @@ packages: resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} engines: {node: '>=0.10.0'} + serve-handler@6.1.7: + resolution: {integrity: sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==} + serve-static@1.16.3: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} @@ -15516,6 +15670,11 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + serve@14.2.6: + resolution: {integrity: sha512-QEjUSA+sD4Rotm1znR8s50YqA3kYpRGPmtd5GlFxbaL9n/FdUNbqMhxClqdditSk0LlZyA/dhud6XNRTOC9x2Q==} + engines: {node: '>= 14'} + hasBin: true + server-only@0.0.1: resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} @@ -15737,10 +15896,6 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - spex@3.4.1: - resolution: {integrity: sha512-Br0Mu3S+c70kr4keXF+6K4B8ohR+aJjI9s7SbdsI3hliE1Riz4z+FQk7FQL+r7X1t90KPkpuKwQyITpCIQN9mg==} - engines: {node: '>=14.0.0'} - split-on-first@1.1.0: resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} engines: {node: '>=6'} @@ -15808,6 +15963,9 @@ packages: stream-json@1.9.1: resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} + stream-parser@0.3.1: + resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} + stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} @@ -15871,6 +16029,10 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -15891,6 +16053,10 @@ packages: resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} engines: {node: '>=18'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -16065,9 +16231,6 @@ packages: engines: {node: '>=10'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - tcp-port-used@1.0.2: - resolution: {integrity: sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==} - terser-webpack-plugin@5.3.17: resolution: {integrity: sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==} engines: {node: '>= 10.13.0'} @@ -16118,6 +16281,10 @@ packages: thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + thread-stream@4.0.0: + resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} + engines: {node: '>=20'} + throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} @@ -16219,6 +16386,9 @@ packages: resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} engines: {node: '>=14.16'} + tokenx@1.3.0: + resolution: {integrity: sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==} + toposort@2.0.2: resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} @@ -16739,6 +16909,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-check@1.5.4: + resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} + upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -16866,6 +17039,10 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + uuid@13.0.0: + resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + hasBin: true + uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. @@ -17186,6 +17363,10 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + widest-line@4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + wildcard@1.1.2: resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==} @@ -17270,10 +17451,6 @@ packages: utf-8-validate: optional: true - wsl-utils@0.1.0: - resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} - engines: {node: '>=18'} - xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} @@ -17358,8 +17535,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-spinner@0.2.3: - resolution: {integrity: sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==} + yocto-spinner@1.1.0: + resolution: {integrity: sha512-/BY0AUXnS7IKO354uLLA2eRcWiqDifEbd6unXCsOxkFDAkhgUL3PH9X2bFoaU0YchnDXsF+iKleeTLJGckbXfA==} engines: {node: '>=18.19'} yoctocolors@2.1.2: @@ -17479,32 +17656,17 @@ snapshots: - react - react-dom - '@ag-ui/mastra@0.2.0(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(f12a340d274d725e3b3c5f801023ae18))(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76)': + '@ag-ui/mastra@1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(204b25c7c9e393334c406e7fe2b14723))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@ag-ui/client': 0.0.47 '@ag-ui/core': 0.0.47 '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) - '@copilotkit/runtime': 1.10.6(f12a340d274d725e3b3c5f801023ae18) + '@copilotkit/runtime': 1.10.6(204b25c7c9e393334c406e7fe2b14723) '@mastra/client-js': 0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) rxjs: 7.8.1 - zod: 3.25.76 transitivePeerDependencies: - - '@hono/arktype-validator' - - '@hono/effect-validator' - - '@hono/typebox-validator' - - '@hono/valibot-validator' - - '@hono/zod-validator' - - '@sinclair/typebox' - - '@valibot/to-json-schema' - - arktype - - effect - - encoding - - openapi-types - - react - - supports-color - - valibot - - zod-openapi + - zod '@ag-ui/proto@0.0.47': dependencies: @@ -17563,6 +17725,13 @@ snapshots: eventsource-parser: 3.0.6 zod: 3.25.76 + '@ai-sdk/provider-utils@3.0.20(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.1 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 3.25.76 + '@ai-sdk/provider-utils@3.0.22(zod@3.25.76)': dependencies: '@ai-sdk/provider': 2.0.1 @@ -17570,6 +17739,13 @@ snapshots: eventsource-parser: 3.0.6 zod: 3.25.76 + '@ai-sdk/provider-utils@4.0.0(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 3.0.0 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 3.25.76 + '@ai-sdk/provider@1.1.3': dependencies: json-schema: 0.4.0 @@ -17582,6 +17758,14 @@ snapshots: dependencies: json-schema: 0.4.0 + '@ai-sdk/provider@3.0.0': + dependencies: + json-schema: 0.4.0 + + '@ai-sdk/provider@3.0.5': + dependencies: + json-schema: 0.4.0 + '@ai-sdk/react@1.2.12(react@19.2.4)(zod@3.25.76)': dependencies: '@ai-sdk/provider-utils': 2.2.8(zod@3.25.76) @@ -19281,15 +19465,16 @@ snapshots: '@cfworker/json-schema@4.1.1': {} - '@clack/core@0.5.0': + '@clack/core@1.2.0': dependencies: - picocolors: 1.1.1 + fast-wrap-ansi: 0.1.6 sisteransi: 1.0.5 - '@clack/prompts@0.11.0': + '@clack/prompts@1.2.0': dependencies: - '@clack/core': 0.5.0 - picocolors: 1.1.1 + '@clack/core': 1.2.0 + fast-string-width: 1.1.0 + fast-wrap-ansi: 0.1.6 sisteransi: 1.0.5 '@colors/colors@1.5.0': @@ -19372,7 +19557,7 @@ snapshots: - encoding - graphql - '@copilotkit/runtime@1.10.6(f12a340d274d725e3b3c5f801023ae18)': + '@copilotkit/runtime@1.10.6(204b25c7c9e393334c406e7fe2b14723)': dependencies: '@ag-ui/client': 0.0.47 '@ag-ui/core': 0.0.47 @@ -19383,7 +19568,7 @@ snapshots: '@copilotkit/shared': 1.10.6 '@graphql-yoga/plugin-defer-stream': 3.18.0(graphql-yoga@5.18.0(graphql@16.13.1))(graphql@16.13.1) '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - '@langchain/community': 0.3.59(60b357dc096a3106ab16514b06ce052e) + '@langchain/community': 0.3.59(56da3b82a111ce776c286ff2a1d7f635) '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76) '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react@19.2.4) @@ -19762,156 +19947,234 @@ snapshots: '@esbuild/aix-ppc64@0.27.3': optional: true + '@esbuild/aix-ppc64@0.27.7': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true '@esbuild/android-arm64@0.27.3': optional: true + '@esbuild/android-arm64@0.27.7': + optional: true + '@esbuild/android-arm@0.25.12': optional: true '@esbuild/android-arm@0.27.3': optional: true + '@esbuild/android-arm@0.27.7': + optional: true + '@esbuild/android-x64@0.25.12': optional: true '@esbuild/android-x64@0.27.3': optional: true + '@esbuild/android-x64@0.27.7': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true '@esbuild/darwin-arm64@0.27.3': optional: true + '@esbuild/darwin-arm64@0.27.7': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true '@esbuild/darwin-x64@0.27.3': optional: true + '@esbuild/darwin-x64@0.27.7': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true '@esbuild/freebsd-arm64@0.27.3': optional: true + '@esbuild/freebsd-arm64@0.27.7': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true '@esbuild/freebsd-x64@0.27.3': optional: true + '@esbuild/freebsd-x64@0.27.7': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true '@esbuild/linux-arm64@0.27.3': optional: true + '@esbuild/linux-arm64@0.27.7': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true '@esbuild/linux-arm@0.27.3': optional: true + '@esbuild/linux-arm@0.27.7': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true '@esbuild/linux-ia32@0.27.3': optional: true + '@esbuild/linux-ia32@0.27.7': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true '@esbuild/linux-loong64@0.27.3': optional: true + '@esbuild/linux-loong64@0.27.7': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true '@esbuild/linux-mips64el@0.27.3': optional: true + '@esbuild/linux-mips64el@0.27.7': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true '@esbuild/linux-ppc64@0.27.3': optional: true + '@esbuild/linux-ppc64@0.27.7': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true '@esbuild/linux-riscv64@0.27.3': optional: true + '@esbuild/linux-riscv64@0.27.7': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true '@esbuild/linux-s390x@0.27.3': optional: true + '@esbuild/linux-s390x@0.27.7': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true '@esbuild/linux-x64@0.27.3': optional: true + '@esbuild/linux-x64@0.27.7': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true '@esbuild/netbsd-arm64@0.27.3': optional: true + '@esbuild/netbsd-arm64@0.27.7': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true '@esbuild/netbsd-x64@0.27.3': optional: true + '@esbuild/netbsd-x64@0.27.7': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true '@esbuild/openbsd-arm64@0.27.3': optional: true + '@esbuild/openbsd-arm64@0.27.7': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true '@esbuild/openbsd-x64@0.27.3': optional: true + '@esbuild/openbsd-x64@0.27.7': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true '@esbuild/openharmony-arm64@0.27.3': optional: true + '@esbuild/openharmony-arm64@0.27.7': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true '@esbuild/sunos-x64@0.27.3': optional: true + '@esbuild/sunos-x64@0.27.7': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true '@esbuild/win32-arm64@0.27.3': optional: true + '@esbuild/win32-arm64@0.27.7': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true '@esbuild/win32-ia32@0.27.3': optional: true + '@esbuild/win32-ia32@0.27.7': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true '@esbuild/win32-x64@0.27.3': optional: true + '@esbuild/win32-x64@0.27.7': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.0)': dependencies: eslint: 8.57.0 @@ -20386,6 +20649,8 @@ snapshots: '@isaacs/ttlcache@1.4.1': {} + '@isaacs/ttlcache@2.1.4': {} + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -20784,71 +21049,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@langchain/community@0.3.59(60b357dc096a3106ab16514b06ce052e)': - dependencies: - '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) - '@ibm-cloud/watsonx-ai': 1.7.9 - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - '@langchain/weaviate': 0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - binary-extensions: 2.3.0 - flat: 5.0.2 - ibm-cloud-sdk-core: 5.4.8 - js-yaml: 4.1.1 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - math-expression-evaluator: 2.0.7 - openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) - uuid: 10.0.0 - zod: 3.25.76 - optionalDependencies: - '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-bedrock-agent-runtime': 3.1003.0 - '@aws-sdk/client-bedrock-runtime': 3.1003.0 - '@aws-sdk/client-kendra': 3.1003.0 - '@aws-sdk/client-s3': 3.1003.0 - '@aws-sdk/credential-provider-node': 3.972.17 - '@browserbasehq/sdk': 2.7.0 - '@smithy/util-utf8': 2.3.0 - '@upstash/redis': 1.36.3 - cheerio: 1.2.0 - crypto-js: 4.2.0 - fast-xml-parser: 4.5.4 - google-auth-library: 9.15.1 - googleapis: 137.1.0 - html-to-text: 9.0.5 - ignore: 5.3.2 - ioredis: 5.10.0 - jsdom: 22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10) - jsonwebtoken: 9.0.3 - lodash: 4.17.23 - pg: 8.16.3 - playwright: 1.58.2 - redis: 4.7.1 - weaviate-client: 3.12.0 - ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - '@langchain/anthropic' - - '@langchain/aws' - - '@langchain/cerebras' - - '@langchain/cohere' - - '@langchain/deepseek' - - '@langchain/google-genai' - - '@langchain/google-vertexai' - - '@langchain/google-vertexai-web' - - '@langchain/groq' - - '@langchain/mistralai' - - '@langchain/ollama' - - '@langchain/xai' - - '@opentelemetry/api' - - '@opentelemetry/exporter-trace-otlp-proto' - - '@opentelemetry/sdk-trace-base' - - axios - - encoding - - handlebars - - peggy - - '@langchain/community@0.3.59(9266573ded5fda56099eca4ab106a463)': + '@langchain/community@0.3.59(45cfa14f738c5b504e0280393b96505c)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) '@ibm-cloud/watsonx-ai': 1.7.9 @@ -20886,7 +21087,71 @@ snapshots: jsdom: 22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10) jsonwebtoken: 9.0.3 lodash: 4.17.23 - pg: 8.16.3 + pg: 8.20.0 + playwright: 1.58.2 + redis: 4.7.1 + weaviate-client: 3.12.0 + ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - '@langchain/anthropic' + - '@langchain/aws' + - '@langchain/cerebras' + - '@langchain/cohere' + - '@langchain/deepseek' + - '@langchain/google-genai' + - '@langchain/google-vertexai' + - '@langchain/google-vertexai-web' + - '@langchain/groq' + - '@langchain/mistralai' + - '@langchain/ollama' + - '@langchain/xai' + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - axios + - encoding + - handlebars + - peggy + + '@langchain/community@0.3.59(56da3b82a111ce776c286ff2a1d7f635)': + dependencies: + '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) + '@ibm-cloud/watsonx-ai': 1.7.9 + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/weaviate': 0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) + binary-extensions: 2.3.0 + flat: 5.0.2 + ibm-cloud-sdk-core: 5.4.8 + js-yaml: 4.1.1 + langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + math-expression-evaluator: 2.0.7 + openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + uuid: 10.0.0 + zod: 3.25.76 + optionalDependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-bedrock-agent-runtime': 3.1003.0 + '@aws-sdk/client-bedrock-runtime': 3.1003.0 + '@aws-sdk/client-kendra': 3.1003.0 + '@aws-sdk/client-s3': 3.1003.0 + '@aws-sdk/credential-provider-node': 3.972.17 + '@browserbasehq/sdk': 2.7.0 + '@smithy/util-utf8': 2.3.0 + '@upstash/redis': 1.36.3 + cheerio: 1.2.0 + crypto-js: 4.2.0 + fast-xml-parser: 4.5.4 + google-auth-library: 9.15.1 + googleapis: 137.1.0 + html-to-text: 9.0.5 + ignore: 5.3.2 + ioredis: 5.10.0 + jsdom: 22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10) + jsonwebtoken: 9.0.3 + lodash: 4.17.23 + pg: 8.20.0 playwright: 1.58.2 redis: 4.7.1 weaviate-client: 3.12.0 @@ -21211,8 +21476,8 @@ snapshots: ai-v5: ai@5.0.60(zod@3.25.76) date-fns: 3.6.0 dotenv: 16.6.1 - hono: 4.12.5 - hono-openapi: 0.4.8(hono@4.12.5)(openapi-types@12.1.3)(zod@3.25.76) + hono: 4.12.10 + hono-openapi: 0.4.8(hono@4.12.10)(openapi-types@12.1.3)(zod@3.25.76) js-tiktoken: 1.0.21 json-schema: 0.4.0 json-schema-to-zod: 2.7.0 @@ -21241,35 +21506,76 @@ snapshots: - valibot - zod-openapi - '@mastra/deployer@0.19.1(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(typescript@5.5.4)(zod@3.25.76)': + '@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@a2a-js/sdk': 0.2.5 + '@ai-sdk/provider-utils-v5': '@ai-sdk/provider-utils@3.0.20(zod@3.25.76)' + '@ai-sdk/provider-utils-v6': '@ai-sdk/provider-utils@4.0.0(zod@3.25.76)' + '@ai-sdk/provider-v5': '@ai-sdk/provider@2.0.1' + '@ai-sdk/provider-v6': '@ai-sdk/provider@3.0.5' + '@ai-sdk/ui-utils-v5': '@ai-sdk/ui-utils@1.2.11(zod@3.25.76)' + '@isaacs/ttlcache': 2.1.4 + '@lukeed/uuid': 2.0.1 + '@mastra/schema-compat': 1.2.7(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@sindresorhus/slugify': 2.2.1 + '@standard-schema/spec': 1.1.0 + ajv: 8.18.0 + dotenv: 17.4.0 + execa: 9.6.1 + gray-matter: 4.0.3 + hono: 4.12.10 + hono-openapi: 1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(hono@4.12.10)(openapi-types@12.1.3) + ignore: 7.0.5 + js-tiktoken: 1.0.21 + json-schema: 0.4.0 + lru-cache: 11.2.7 + p-map: 7.0.4 + p-retry: 7.1.1 + picomatch: 4.0.3 + radash: 12.1.1 + tokenx: 1.3.0 + ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + xxhash-wasm: 1.1.0 + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@hono/standard-validator' + - '@standard-community/standard-json' + - '@standard-community/standard-openapi' + - '@types/json-schema' + - bufferutil + - openapi-types + - supports-color + - utf-8-validate + + '@mastra/deployer@1.21.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(typescript@5.5.4)(zod@3.25.76)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) - '@mastra/server': 0.19.1(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(zod@3.25.76) - '@neon-rs/load': 0.1.82 - '@optimize-lodash/rollup-plugin': 5.1.0(rollup@4.50.2) - '@rollup/plugin-alias': 5.1.1(rollup@4.50.2) - '@rollup/plugin-commonjs': 28.0.9(rollup@4.50.2) - '@rollup/plugin-esm-shim': 0.1.8(rollup@4.50.2) - '@rollup/plugin-json': 6.1.0(rollup@4.50.2) - '@rollup/plugin-node-resolve': 16.0.3(rollup@4.50.2) - '@rollup/plugin-virtual': 3.0.2(rollup@4.50.2) + '@babel/traverse': 7.29.0 + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@mastra/server': 1.21.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + '@optimize-lodash/rollup-plugin': 5.1.0(rollup@4.59.0) + '@rollup/plugin-alias': 6.0.0(rollup@4.59.0) + '@rollup/plugin-commonjs': 29.0.2(rollup@4.59.0) + '@rollup/plugin-esm-shim': 0.1.8(rollup@4.59.0) + '@rollup/plugin-json': 6.1.0(rollup@4.59.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.59.0) + '@rollup/plugin-virtual': 3.0.2(rollup@4.59.0) '@sindresorhus/slugify': 2.2.1 - builtins: 5.1.0 - detect-libc: 2.1.2 - dotenv: 16.6.1 + '@types/babel__traverse': 7.28.0 empathic: 2.0.0 - esbuild: 0.25.12 + esbuild: 0.27.7 find-workspaces: 0.3.1 fs-extra: 11.3.4 - hono: 4.12.5 + hono: 4.12.10 local-pkg: 1.1.2 resolve-from: 5.0.0 - rollup: 4.50.2 - rollup-plugin-esbuild: 6.2.1(esbuild@0.25.12)(rollup@4.50.2) - rollup-plugin-node-externals: 8.1.2(rollup@4.50.2) + resolve.exports: 2.0.3 + rollup: 4.59.0 + rollup-plugin-esbuild: 6.2.1(esbuild@0.27.7)(rollup@4.59.0) + strip-json-comments: 5.0.3 tinyglobby: 0.2.15 typescript-paths: 1.5.1(typescript@5.5.4) zod: 3.25.76 @@ -21277,61 +21583,49 @@ snapshots: - supports-color - typescript - '@mastra/loggers@0.10.19(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))': + '@mastra/loggers@1.1.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) - pino: 9.14.0 + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) + pino: 10.3.1 pino-pretty: 13.1.3 - '@mastra/mcp@0.13.5(@cfworker/json-schema@4.1.1)(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@types/json-schema@7.0.15)(zod@3.25.76)': + '@mastra/mcp@1.4.1(@cfworker/json-schema@4.1.1)(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(@types/json-schema@7.0.15)(zod@3.25.76)': dependencies: '@apidevtools/json-schema-ref-parser': 14.2.1(@types/json-schema@7.0.15) - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) '@modelcontextprotocol/sdk': 1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) - date-fns: 4.1.0 - exit-hook: 4.0.0 + exit-hook: 5.1.0 fast-deep-equal: 3.1.3 - uuid: 11.1.0 + uuid: 13.0.0 zod: 3.25.76 - zod-from-json-schema: 0.5.2 - zod-from-json-schema-v3: zod-from-json-schema@0.0.5 transitivePeerDependencies: - '@cfworker/json-schema' - '@types/json-schema' - supports-color - '@mastra/memory@0.15.13(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(react@19.2.4)(zod@3.25.76)': + '@mastra/memory@1.13.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) - '@mastra/schema-compat': 0.11.9(ai@4.3.19(react@19.2.4)(zod@3.25.76))(zod@3.25.76) - '@upstash/redis': 1.36.3 - ai: 4.3.19(react@19.2.4)(zod@3.25.76) - ai-v5: ai@5.0.60(zod@3.25.76) + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@mastra/schema-compat': 1.2.7(zod@3.25.76) async-mutex: 0.5.0 - js-tiktoken: 1.0.21 + image-size: 2.0.2 json-schema: 0.4.0 - pg: 8.20.0 - pg-pool: 3.13.0(pg@8.20.0) - postgres: 3.4.8 - redis: 5.11.0 + lru-cache: 11.2.7 + probe-image-size: 7.2.3 + tokenx: 1.3.0 xxhash-wasm: 1.1.0 zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - - '@node-rs/xxhash' - - pg-native - - react + - supports-color - '@mastra/pg@0.17.10(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(pg-query-stream@4.10.3(pg@8.16.3))': + '@mastra/pg@1.8.5(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) async-mutex: 0.5.0 pg: 8.20.0 - pg-promise: 11.15.0(pg-query-stream@4.10.3(pg@8.16.3)) xxhash-wasm: 1.1.0 transitivePeerDependencies: - pg-native - - pg-query-stream '@mastra/schema-compat@0.11.4(ai@4.3.19(react@19.2.4)(zod@3.25.76))(zod@3.25.76)': dependencies: @@ -21342,19 +21636,18 @@ snapshots: zod-from-json-schema-v3: zod-from-json-schema@0.0.5 zod-to-json-schema: 3.25.1(zod@3.25.76) - '@mastra/schema-compat@0.11.9(ai@4.3.19(react@19.2.4)(zod@3.25.76))(zod@3.25.76)': + '@mastra/schema-compat@1.2.7(zod@3.25.76)': dependencies: - ai: 4.3.19(react@19.2.4)(zod@3.25.76) - json-schema: 0.4.0 json-schema-to-zod: 2.7.0 zod: 3.25.76 zod-from-json-schema: 0.5.2 zod-from-json-schema-v3: zod-from-json-schema@0.0.5 zod-to-json-schema: 3.25.1(zod@3.25.76) - '@mastra/server@0.19.1(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(zod@3.25.76)': + '@mastra/server@1.21.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) + hono: 4.12.10 zod: 3.25.76 '@meronex/icons@4.0.0(react@19.2.4)': @@ -21605,8 +21898,6 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@neon-rs/load@0.1.82': {} - '@nest-lab/throttler-storage-redis@1.2.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@nestjs/throttler@6.5.0(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(reflect-metadata@0.1.14))(ioredis@5.10.0)(reflect-metadata@0.1.14)': dependencies: '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2) @@ -21622,7 +21913,7 @@ snapshots: axios: 1.13.6(debug@4.4.3) rxjs: 7.8.2 - '@nestjs/cli@10.0.2(@swc/cli@0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)': + '@nestjs/cli@10.0.2(@swc/cli@0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)': dependencies: '@angular-devkit/core': 16.1.0(chokidar@3.5.3) '@angular-devkit/schematics': 16.1.0(chokidar@3.5.3) @@ -21632,7 +21923,7 @@ snapshots: chokidar: 3.5.3 cli-table3: 0.6.3 commander: 4.1.1 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.1.3)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.1.3)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) inquirer: 8.2.5 node-emoji: 1.11.0 ora: 5.4.1 @@ -21644,7 +21935,7 @@ snapshots: tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.0.1 typescript: 5.1.3 - webpack: 5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) webpack-node-externals: 3.0.0 optionalDependencies: '@swc/cli': 0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3) @@ -22981,11 +23272,11 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) - '@optimize-lodash/rollup-plugin@5.1.0(rollup@4.50.2)': + '@optimize-lodash/rollup-plugin@5.1.0(rollup@4.59.0)': dependencies: '@optimize-lodash/transform': 3.0.6 - '@rollup/pluginutils': 5.3.0(rollup@4.50.2) - rollup: 4.50.2 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + rollup: 4.59.0 '@optimize-lodash/transform@3.0.6': dependencies: @@ -23118,7 +23409,7 @@ snapshots: dependencies: playwright: 1.58.2 - '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.10.0)(type-fest@4.41.0)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(react-refresh@0.10.0)(type-fest@4.41.0)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7))': dependencies: ansi-html: 0.0.9 core-js-pure: 3.48.0 @@ -23128,7 +23419,7 @@ snapshots: react-refresh: 0.10.0 schema-utils: 4.3.3 source-map: 0.7.6 - webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) optionalDependencies: type-fest: 4.41.0 @@ -23140,6 +23431,10 @@ snapshots: dependencies: cross-spawn: 7.0.6 + '@posthog/core@1.7.1': + dependencies: + cross-spawn: 7.0.6 + '@posthog/types@1.359.1': {} '@postiz/wallets@0.0.1(@babel/runtime@7.28.6)(@react-native-async-storage/async-storage@1.24.0(react-native@0.84.1(@babel/core@7.29.0)(@types/react@19.1.8)(bufferutil@4.1.0)(react@19.2.4)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.1.0)(typescript@5.5.4)(utf-8-validate@5.0.10))(@types/react@19.1.8)(@upstash/redis@1.36.3)(bs58@6.0.0)(bufferutil@4.1.0)(ioredis@5.10.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.25.76)': @@ -23758,20 +24053,12 @@ snapshots: dependencies: '@redis/client': 1.6.1 - '@redis/bloom@5.11.0(@redis/client@5.11.0)': - dependencies: - '@redis/client': 5.11.0 - '@redis/client@1.6.1': dependencies: cluster-key-slot: 1.1.2 generic-pool: 3.9.0 yallist: 4.0.0 - '@redis/client@5.11.0': - dependencies: - cluster-key-slot: 1.1.2 - '@redis/graph@1.1.1(@redis/client@1.6.1)': dependencies: '@redis/client': 1.6.1 @@ -23780,26 +24067,14 @@ snapshots: dependencies: '@redis/client': 1.6.1 - '@redis/json@5.11.0(@redis/client@5.11.0)': - dependencies: - '@redis/client': 5.11.0 - '@redis/search@1.2.0(@redis/client@1.6.1)': dependencies: '@redis/client': 1.6.1 - '@redis/search@5.11.0(@redis/client@5.11.0)': - dependencies: - '@redis/client': 5.11.0 - '@redis/time-series@1.1.0(@redis/client@1.6.1)': dependencies: '@redis/client': 1.6.1 - '@redis/time-series@5.11.0(@redis/client@5.11.0)': - dependencies: - '@redis/client': 5.11.0 - '@remirror/core-constants@3.0.0': {} '@reown/appkit-common@1.7.2(bufferutil@4.1.0)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.22.4)': @@ -24030,9 +24305,9 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/plugin-alias@5.1.1(rollup@4.50.2)': + '@rollup/plugin-alias@6.0.0(rollup@4.59.0)': optionalDependencies: - rollup: 4.50.2 + rollup: 4.59.0 '@rollup/plugin-commonjs@28.0.1(rollup@4.59.0)': dependencies: @@ -24046,9 +24321,9 @@ snapshots: optionalDependencies: rollup: 4.59.0 - '@rollup/plugin-commonjs@28.0.9(rollup@4.50.2)': + '@rollup/plugin-commonjs@29.0.2(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.50.2) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.5.0(picomatch@4.0.3) @@ -24056,48 +24331,40 @@ snapshots: magic-string: 0.30.21 picomatch: 4.0.3 optionalDependencies: - rollup: 4.50.2 + rollup: 4.59.0 - '@rollup/plugin-esm-shim@0.1.8(rollup@4.50.2)': + '@rollup/plugin-esm-shim@0.1.8(rollup@4.59.0)': dependencies: magic-string: 0.30.21 mlly: 1.8.1 optionalDependencies: - rollup: 4.50.2 + rollup: 4.59.0 - '@rollup/plugin-json@6.1.0(rollup@4.50.2)': + '@rollup/plugin-json@6.1.0(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.50.2) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) optionalDependencies: - rollup: 4.50.2 + rollup: 4.59.0 - '@rollup/plugin-node-resolve@16.0.3(rollup@4.50.2)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.59.0)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.50.2) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.11 optionalDependencies: - rollup: 4.50.2 + rollup: 4.59.0 - '@rollup/plugin-virtual@3.0.2(rollup@4.50.2)': + '@rollup/plugin-virtual@3.0.2(rollup@4.59.0)': optionalDependencies: - rollup: 4.50.2 + rollup: 4.59.0 '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/pluginutils@5.3.0(rollup@4.50.2)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.50.2 - '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 @@ -24106,141 +24373,78 @@ snapshots: optionalDependencies: rollup: 4.59.0 - '@rollup/rollup-android-arm-eabi@4.50.2': - optional: true - '@rollup/rollup-android-arm-eabi@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.50.2': - optional: true - '@rollup/rollup-android-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.50.2': - optional: true - '@rollup/rollup-darwin-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.50.2': - optional: true - '@rollup/rollup-darwin-x64@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.50.2': - optional: true - '@rollup/rollup-freebsd-arm64@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.50.2': - optional: true - '@rollup/rollup-freebsd-x64@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.50.2': - optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.50.2': - optional: true - '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.50.2': - optional: true - '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.50.2': - optional: true - '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.50.2': - optional: true - '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.50.2': - optional: true - '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.50.2': - optional: true - '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.50.2': - optional: true - '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.50.2': - optional: true - '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.50.2': - optional: true - '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-musl@4.50.2': - optional: true - '@rollup/rollup-linux-x64-musl@4.59.0': optional: true '@rollup/rollup-openbsd-x64@4.59.0': optional: true - '@rollup/rollup-openharmony-arm64@4.50.2': - optional: true - '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.50.2': - optional: true - '@rollup/rollup-win32-arm64-msvc@4.59.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.50.2': - optional: true - '@rollup/rollup-win32-ia32-msvc@4.59.0': optional: true '@rollup/rollup-win32-x64-gnu@4.59.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.50.2': - optional: true - '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true @@ -24434,7 +24638,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@sentry/nextjs@10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.2.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12))': + '@sentry/nextjs@10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@16.2.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.40.0 @@ -24446,7 +24650,7 @@ snapshots: '@sentry/opentelemetry': 10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0) '@sentry/react': 10.45.0(react@19.2.4) '@sentry/vercel-edge': 10.45.0 - '@sentry/webpack-plugin': 5.1.1(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + '@sentry/webpack-plugin': 5.1.1(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) next: 16.2.1(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) rollup: 4.59.0 stacktrace-parser: 0.1.11 @@ -24542,11 +24746,11 @@ snapshots: '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) '@sentry/core': 10.45.0 - '@sentry/webpack-plugin@5.1.1(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12))': + '@sentry/webpack-plugin@5.1.1(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7))': dependencies: '@sentry/bundler-plugin-core': 5.1.1 uuid: 9.0.1 - webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) transitivePeerDependencies: - encoding - supports-color @@ -25443,6 +25647,23 @@ snapshots: eventemitter3: 5.0.4 uuid: 9.0.1 + '@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/json-schema': 7.0.15 + quansync: 0.2.11 + optionalDependencies: + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + + '@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76)': + dependencies: + '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76) + '@standard-schema/spec': 1.1.0 + openapi-types: 12.1.3 + optionalDependencies: + zod: 3.25.76 + '@standard-schema/spec@1.1.0': {} '@stripe/react-stripe-js@5.6.1(@stripe/stripe-js@8.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -25784,7 +26005,7 @@ snapshots: long: 5.3.2 protobufjs: 7.5.4 - '@temporalio/worker@1.15.0(@swc/helpers@0.5.13)(esbuild@0.25.12)(tslib@2.8.1)': + '@temporalio/worker@1.15.0(@swc/helpers@0.5.13)(esbuild@0.27.7)(tslib@2.8.1)': dependencies: '@grpc/grpc-js': 1.14.3 '@swc/core': 1.5.7(@swc/helpers@0.5.13) @@ -25803,11 +26024,11 @@ snapshots: protobufjs: 7.5.4 rxjs: 7.8.2 source-map: 0.7.6 - source-map-loader: 4.0.2(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + source-map-loader: 4.0.2(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) supports-color: 8.1.1 - swc-loader: 0.2.7(@swc/core@1.5.7(@swc/helpers@0.5.13))(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + swc-loader: 0.2.7(@swc/core@1.5.7(@swc/helpers@0.5.13))(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) unionfs: 4.6.0 - webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) transitivePeerDependencies: - '@swc/helpers' - esbuild @@ -27166,6 +27387,7 @@ snapshots: '@upstash/redis@1.36.3': dependencies: uncrypto: 0.1.3 + optional: true '@urql/core@5.2.0(graphql@16.13.1)': dependencies: @@ -27909,8 +28131,6 @@ snapshots: '@webcomponents/custom-elements@1.6.0': {} - '@webcontainer/env@1.1.1': {} - '@whatwg-node/disposablestack@0.0.6': dependencies: '@whatwg-node/promise-helpers': 1.3.2 @@ -27984,6 +28204,8 @@ snapshots: '@xtuc/long@4.2.2': {} + '@zeit/schemas@2.36.0': {} + abab@2.0.6: {} abbrev@1.1.1: {} @@ -28135,6 +28357,10 @@ snapshots: anser@1.4.10: {} + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -28291,8 +28517,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - assert-options@0.8.3: {} - assert-plus@1.0.0: {} assert@2.1.0: @@ -28579,6 +28803,17 @@ snapshots: bowser@2.14.1: {} + boxen@7.0.0: + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.1 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.19.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -28696,14 +28931,6 @@ snapshots: dependencies: node-gyp-build: 4.8.4 - builtins@5.1.0: - dependencies: - semver: 7.7.4 - - bundle-name@4.1.0: - dependencies: - run-applescript: 7.1.0 - bundle-require@5.1.0(esbuild@0.27.3): dependencies: esbuild: 0.27.3 @@ -28713,6 +28940,8 @@ snapshots: dependencies: streamsearch: 1.1.0 + bytes@3.0.0: {} + bytes@3.1.2: {} cac@6.7.14: {} @@ -28764,6 +28993,8 @@ snapshots: camelcase@6.3.0: {} + camelcase@7.0.1: {} + caniuse-lite@1.0.30001777: {} canvas@2.11.2: @@ -28795,11 +29026,17 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 + chalk-template@0.4.0: + dependencies: + chalk: 4.1.2 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.0.1: {} + chalk@5.6.2: {} change-case@4.1.2: @@ -28964,6 +29201,8 @@ snapshots: clean-stack@2.2.0: {} + cli-boxes@3.0.0: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -28982,6 +29221,12 @@ snapshots: client-only@0.0.1: {} + clipboardy@3.0.0: + dependencies: + arch: 2.2.0 + execa: 5.1.1 + is-wsl: 2.2.0 + cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -29175,6 +29420,8 @@ snapshots: tslib: 2.8.1 upper-case: 2.0.2 + content-disposition@0.5.2: {} + content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -29452,8 +29699,6 @@ snapshots: date-fns@3.6.0: {} - date-fns@4.1.0: {} - dateformat@4.6.3: {} dayjs@1.11.13: {} @@ -29468,10 +29713,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.1: - dependencies: - ms: 2.1.2 - debug@4.4.3(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -29523,19 +29764,14 @@ snapshots: which-collection: 1.0.2 which-typed-array: 1.1.20 + deep-extend@0.6.0: {} + deep-is@0.1.4: {} deepmerge@2.2.1: {} deepmerge@4.3.1: {} - default-browser-id@5.0.1: {} - - default-browser@5.5.0: - dependencies: - bundle-name: 4.1.0 - default-browser-id: 5.0.1 - defaults@1.0.4: dependencies: clone: 1.0.4 @@ -29548,8 +29784,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - define-lazy-prop@3.0.0: {} - define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -29696,6 +29930,8 @@ snapshots: dotenv@16.6.1: {} + dotenv@17.4.0: {} + draggabilly@3.0.0: dependencies: get-size: 3.0.0 @@ -30013,6 +30249,35 @@ snapshots: '@esbuild/win32-ia32': 0.27.3 '@esbuild/win32-x64': 0.27.3 + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -30422,7 +30687,7 @@ snapshots: exifr@7.1.3: {} - exit-hook@4.0.0: {} + exit-hook@5.1.0: {} exit@0.1.2: {} @@ -30523,6 +30788,10 @@ snapshots: ext-list: 2.2.2 sort-keys-length: 1.0.1 + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + extend@3.0.2: {} external-editor@3.1.0: @@ -30585,10 +30854,20 @@ snapshots: fast-stable-stringify@1.0.0: {} + fast-string-truncated-width@1.2.1: {} + + fast-string-width@1.1.0: + dependencies: + fast-string-truncated-width: 1.2.1 + fast-text-encoding@1.0.6: {} fast-uri@3.1.0: {} + fast-wrap-ansi@0.1.6: + dependencies: + fast-string-width: 1.1.0 + fast-xml-builder@1.0.0: {} fast-xml-parser@4.5.4: @@ -30797,7 +31076,7 @@ snapshots: forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.1.3)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.1.3)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -30812,7 +31091,7 @@ snapshots: semver: 7.7.4 tapable: 2.3.0 typescript: 5.1.3 - webpack: 5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) form-data-encoder@1.7.2: {} @@ -31217,6 +31496,13 @@ snapshots: graphql@16.13.1: {} + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.2 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + groq-sdk@0.5.0: dependencies: '@types/node': 18.16.9 @@ -31531,14 +31817,25 @@ snapshots: dependencies: react-is: 16.13.1 - hono-openapi@0.4.8(hono@4.12.5)(openapi-types@12.1.3)(zod@3.25.76): + hono-openapi@0.4.8(hono@4.12.10)(openapi-types@12.1.3)(zod@3.25.76): dependencies: json-schema-walker: 2.0.0 openapi-types: 12.1.3 optionalDependencies: - hono: 4.12.5 + hono: 4.12.10 zod: 3.25.76 + hono-openapi@1.3.0(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(hono@4.12.10)(openapi-types@12.1.3): + dependencies: + '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76) + '@standard-community/standard-openapi': 0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76) + '@types/json-schema': 7.0.15 + openapi-types: 12.1.3 + optionalDependencies: + hono: 4.12.10 + + hono@4.12.10: {} + hono@4.12.5: {} hookified@1.15.1: {} @@ -31720,6 +32017,8 @@ snapshots: dependencies: queue: 6.0.2 + image-size@2.0.2: {} + image-to-pdf@3.0.2: dependencies: pdfkit: 0.15.2 @@ -31850,8 +32149,6 @@ snapshots: ip-address@10.1.0: {} - ip-regex@4.3.0: {} - ipaddr.js@1.9.1: {} iron-webcrypto@1.2.1: {} @@ -31939,7 +32236,7 @@ snapshots: is-docker@2.2.1: {} - is-docker@3.0.0: {} + is-extendable@0.1.1: {} is-extendable@1.0.1: dependencies: @@ -31973,10 +32270,6 @@ snapshots: is-hotkey@0.1.8: {} - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 - is-interactive@1.0.0: {} is-map@2.0.3: {} @@ -32016,6 +32309,8 @@ snapshots: is-plain-object@5.0.0: {} + is-port-reachable@4.0.0: {} + is-potential-custom-element-name@1.0.1: {} is-promise@4.0.0: {} @@ -32064,8 +32359,6 @@ snapshots: is-unicode-supported@2.1.0: {} - is-url@1.2.4: {} - is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -32081,16 +32374,6 @@ snapshots: dependencies: is-docker: 2.2.1 - is-wsl@3.1.1: - dependencies: - is-inside-container: 1.0.0 - - is2@2.0.9: - dependencies: - deep-is: 0.1.4 - ip-regex: 4.3.0 - is-url: 1.2.4 - isarray@1.0.0: {} isarray@2.0.5: {} @@ -32808,6 +33091,8 @@ snapshots: keyvaluestorage-interface@1.0.0: {} + kind-of@6.0.3: {} + kleur@3.0.3: {} kleur@4.1.5: {} @@ -33134,6 +33419,8 @@ snapshots: lru-cache@11.2.6: {} + lru-cache@11.2.7: {} + lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 @@ -33204,45 +33491,30 @@ snapshots: marky@1.3.0: {} - mastra@0.13.4(@cfworker/json-schema@4.1.1)(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@opentelemetry/api@1.9.0)(@types/json-schema@7.0.15)(typescript@5.5.4)(zod@3.25.76): + mastra@1.3.19(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(typescript@5.5.4)(zod@3.25.76): dependencies: - '@clack/prompts': 0.11.0 + '@clack/prompts': 1.2.0 '@expo/devcert': 1.2.1 - '@mastra/core': 0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) - '@mastra/deployer': 0.19.1(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(typescript@5.5.4)(zod@3.25.76) - '@mastra/loggers': 0.10.19(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76)) - '@mastra/mcp': 0.13.5(@cfworker/json-schema@4.1.1)(@mastra/core@0.20.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@types/json-schema@7.0.15)(zod@3.25.76) - '@opentelemetry/auto-instrumentations-node': 0.62.2(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0)) - '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-grpc': 0.203.0(@opentelemetry/api@1.9.0) - '@opentelemetry/exporter-trace-otlp-http': 0.203.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.203.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-node': 0.203.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.40.0 - '@webcontainer/env': 1.1.1 - commander: 12.1.0 - dotenv: 16.6.1 + '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@mastra/deployer': 1.21.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(typescript@5.5.4)(zod@3.25.76) + '@mastra/loggers': 1.1.0(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76)) + commander: 14.0.3 + dotenv: 17.4.0 execa: 9.6.1 fs-extra: 11.3.4 get-port: 7.1.0 - open: 10.2.0 + local-pkg: 1.1.2 picocolors: 1.1.1 - posthog-node: 4.18.0 + posthog-node: 5.17.2 prettier: 3.8.1 + semver: 7.7.4 + serve: 14.2.6 + serve-handler: 6.1.7 shell-quote: 1.8.3 strip-json-comments: 5.0.3 - tcp-port-used: 1.0.2 - yocto-spinner: 0.2.3 + yocto-spinner: 1.1.0 zod: 3.25.76 - zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - - '@cfworker/json-schema' - - '@opentelemetry/api' - - '@types/json-schema' - - debug - - encoding - supports-color - typescript @@ -34040,6 +34312,8 @@ snapshots: bn.js: 4.12.3 brorand: 1.1.0 + mime-db@1.33.0: {} + mime-db@1.52.0: {} mime-db@1.54.0: {} @@ -34048,6 +34322,10 @@ snapshots: dependencies: wildcard: 1.1.2 + mime-types@2.1.18: + dependencies: + mime-db: 1.33.0 + mime-types@2.1.35: dependencies: mime-db: 1.52.0 @@ -34150,8 +34428,6 @@ snapshots: ms@2.0.0: {} - ms@2.1.2: {} - ms@2.1.3: {} ms@3.0.0-canary.1: {} @@ -34221,6 +34497,14 @@ snapshots: ncp@2.0.0: {} + needle@2.9.1: + dependencies: + debug: 3.2.7 + iconv-lite: 0.4.24 + sax: 1.5.0 + transitivePeerDependencies: + - supports-color + negotiator@0.6.3: {} negotiator@0.6.4: {} @@ -34242,13 +34526,13 @@ snapshots: '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2) '@supercharge/request-ip': 1.2.0 - nestjs-temporal-core@3.2.3(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@temporalio/client@1.15.0)(@temporalio/common@1.15.0)(@temporalio/worker@1.15.0(@swc/helpers@0.5.13)(esbuild@0.25.12)(tslib@2.8.1))(@temporalio/workflow@1.15.0)(reflect-metadata@0.1.14)(rxjs@7.8.2): + nestjs-temporal-core@3.2.3(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@10.4.22)(@temporalio/client@1.15.0)(@temporalio/common@1.15.0)(@temporalio/worker@1.15.0(@swc/helpers@0.5.13)(esbuild@0.27.7)(tslib@2.8.1))(@temporalio/workflow@1.15.0)(reflect-metadata@0.1.14)(rxjs@7.8.2): dependencies: '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2) '@nestjs/core': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(reflect-metadata@0.1.14)(rxjs@7.8.2) '@temporalio/client': 1.15.0 '@temporalio/common': 1.15.0 - '@temporalio/worker': 1.15.0(@swc/helpers@0.5.13)(esbuild@0.25.12)(tslib@2.8.1) + '@temporalio/worker': 1.15.0(@swc/helpers@0.5.13)(esbuild@0.27.7)(tslib@2.8.1) '@temporalio/workflow': 1.15.0 ms: 2.1.3 reflect-metadata: 0.1.14 @@ -34540,13 +34824,6 @@ snapshots: dependencies: mimic-fn: 2.1.0 - open@10.2.0: - dependencies: - default-browser: 5.5.0 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - wsl-utils: 0.1.0 - open@7.4.2: dependencies: is-docker: 2.2.1 @@ -34730,6 +35007,10 @@ snapshots: is-network-error: 1.3.1 retry: 0.13.1 + p-retry@7.1.1: + dependencies: + is-network-error: 1.3.1 + p-timeout@3.2.0: dependencies: p-finally: 1.0.0 @@ -34847,6 +35128,8 @@ snapshots: path-is-absolute@1.0.1: {} + path-is-inside@1.0.2: {} + path-key@2.0.1: {} path-key@3.1.1: {} @@ -34909,39 +35192,14 @@ snapshots: pg-connection-string@2.12.0: {} - pg-cursor@2.19.0(pg@8.16.3): - dependencies: - pg: 8.16.3 - pg-int8@1.0.1: {} - pg-minify@1.8.0: {} - - pg-pool@3.13.0(pg@8.16.3): - dependencies: - pg: 8.16.3 - pg-pool@3.13.0(pg@8.20.0): dependencies: pg: 8.20.0 - pg-promise@11.15.0(pg-query-stream@4.10.3(pg@8.16.3)): - dependencies: - assert-options: 0.8.3 - pg: 8.16.3 - pg-minify: 1.8.0 - pg-query-stream: 4.10.3(pg@8.16.3) - spex: 3.4.1 - transitivePeerDependencies: - - pg-native - pg-protocol@1.13.0: {} - pg-query-stream@4.10.3(pg@8.16.3): - dependencies: - pg: 8.16.3 - pg-cursor: 2.19.0(pg@8.16.3) - pg-types@2.2.0: dependencies: pg-int8: 1.0.1 @@ -34950,16 +35208,6 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.16.3: - dependencies: - pg-connection-string: 2.12.0 - pg-pool: 3.13.0(pg@8.16.3) - pg-protocol: 1.13.0 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.3.0 - pg@8.20.0: dependencies: pg-connection-string: 2.12.0 @@ -35034,6 +35282,20 @@ snapshots: pino-std-serializers@7.1.0: {} + pino@10.3.1: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.0.0 + pino@7.11.0: dependencies: atomic-sleep: 1.0.0 @@ -35204,8 +35466,6 @@ snapshots: dependencies: xtend: 4.0.2 - postgres@3.4.8: {} - posthog-js@1.359.1: dependencies: '@opentelemetry/api': 1.9.0 @@ -35222,11 +35482,9 @@ snapshots: query-selector-shadow-dom: 1.0.1 web-vitals: 5.1.0 - posthog-node@4.18.0: + posthog-node@5.17.2: dependencies: - axios: 1.13.6(debug@4.4.3) - transitivePeerDependencies: - - debug + '@posthog/core': 1.7.1 preact@10.28.4: {} @@ -35268,6 +35526,14 @@ snapshots: prismjs@1.30.0: {} + probe-image-size@7.2.3: + dependencies: + lodash.merge: 4.6.2 + needle: 2.9.1 + stream-parser: 0.3.1 + transitivePeerDependencies: + - supports-color + process-nextick-args@2.0.1: {} process-warning@1.0.0: {} @@ -35578,6 +35844,8 @@ snapshots: randombytes: 2.1.0 safe-buffer: 5.2.1 + range-parser@1.2.0: {} + range-parser@1.2.1: {} rasterizehtml@1.4.1: @@ -35601,6 +35869,13 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + react-colorful@5.6.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -36016,16 +36291,6 @@ snapshots: '@redis/search': 1.2.0(@redis/client@1.6.1) '@redis/time-series': 1.1.0(@redis/client@1.6.1) - redis@5.11.0: - dependencies: - '@redis/bloom': 5.11.0(@redis/client@5.11.0) - '@redis/client': 5.11.0 - '@redis/json': 5.11.0(@redis/client@5.11.0) - '@redis/search': 5.11.0(@redis/client@5.11.0) - '@redis/time-series': 5.11.0(@redis/client@5.11.0) - transitivePeerDependencies: - - '@node-rs/xxhash' - redux@4.2.1: dependencies: '@babel/runtime': 7.28.6 @@ -36091,6 +36356,15 @@ snapshots: unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 + registry-auth-token@3.3.2: + dependencies: + rc: 1.2.8 + safe-buffer: 5.2.1 + + registry-url@3.1.0: + dependencies: + rc: 1.2.8 + regjsgen@0.8.0: {} regjsparser@0.13.0: @@ -36363,52 +36637,21 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rollup-plugin-esbuild@6.2.1(esbuild@0.25.12)(rollup@4.50.2): + rollup-plugin-esbuild@6.2.1(esbuild@0.27.7)(rollup@4.59.0): dependencies: debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 - esbuild: 0.25.12 + esbuild: 0.27.7 get-tsconfig: 4.13.6 - rollup: 4.50.2 + rollup: 4.59.0 unplugin-utils: 0.2.5 transitivePeerDependencies: - supports-color - rollup-plugin-node-externals@8.1.2(rollup@4.50.2): - dependencies: - rollup: 4.50.2 - rollup@2.79.2: optionalDependencies: fsevents: 2.3.3 - rollup@4.50.2: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.50.2 - '@rollup/rollup-android-arm64': 4.50.2 - '@rollup/rollup-darwin-arm64': 4.50.2 - '@rollup/rollup-darwin-x64': 4.50.2 - '@rollup/rollup-freebsd-arm64': 4.50.2 - '@rollup/rollup-freebsd-x64': 4.50.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.50.2 - '@rollup/rollup-linux-arm-musleabihf': 4.50.2 - '@rollup/rollup-linux-arm64-gnu': 4.50.2 - '@rollup/rollup-linux-arm64-musl': 4.50.2 - '@rollup/rollup-linux-loong64-gnu': 4.50.2 - '@rollup/rollup-linux-ppc64-gnu': 4.50.2 - '@rollup/rollup-linux-riscv64-gnu': 4.50.2 - '@rollup/rollup-linux-riscv64-musl': 4.50.2 - '@rollup/rollup-linux-s390x-gnu': 4.50.2 - '@rollup/rollup-linux-x64-gnu': 4.50.2 - '@rollup/rollup-linux-x64-musl': 4.50.2 - '@rollup/rollup-openharmony-arm64': 4.50.2 - '@rollup/rollup-win32-arm64-msvc': 4.50.2 - '@rollup/rollup-win32-ia32-msvc': 4.50.2 - '@rollup/rollup-win32-x64-msvc': 4.50.2 - fsevents: 2.3.3 - rollup@4.59.0: dependencies: '@types/estree': 1.0.8 @@ -36476,8 +36719,6 @@ snapshots: dependencies: sdp: 2.12.0 - run-applescript@7.1.0: {} - run-async@2.4.1: {} run-async@3.0.0: {} @@ -36576,6 +36817,11 @@ snapshots: sdp@2.12.0: {} + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + secure-json-parse@2.7.0: {} secure-json-parse@4.1.0: {} @@ -36638,6 +36884,16 @@ snapshots: serialize-error@2.1.0: {} + serve-handler@6.1.7: + dependencies: + bytes: 3.0.0 + content-disposition: 0.5.2 + mime-types: 2.1.18 + minimatch: 3.1.5 + path-is-inside: 1.0.2 + path-to-regexp: 3.3.0 + range-parser: 1.2.0 + serve-static@1.16.3: dependencies: encodeurl: 2.0.0 @@ -36656,6 +36912,22 @@ snapshots: transitivePeerDependencies: - supports-color + serve@14.2.6: + dependencies: + '@zeit/schemas': 2.36.0 + ajv: 8.18.0 + arg: 5.0.2 + boxen: 7.0.0 + chalk: 5.0.1 + chalk-template: 0.4.0 + clipboardy: 3.0.0 + compression: 1.8.1 + is-port-reachable: 4.0.0 + serve-handler: 6.1.7 + update-check: 1.5.4 + transitivePeerDependencies: + - supports-color + server-only@0.0.1: {} set-blocking@2.0.0: {} @@ -36927,11 +37199,11 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@4.0.2(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)): + source-map-loader@4.0.2(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) source-map-support@0.5.13: dependencies: @@ -36955,8 +37227,6 @@ snapshots: space-separated-tokens@2.0.2: {} - spex@3.4.1: {} - split-on-first@1.1.0: {} split2@3.2.2: @@ -37019,6 +37289,12 @@ snapshots: dependencies: stream-chain: 2.2.5 + stream-parser@0.3.1: + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + stream-shift@1.0.3: {} streamsearch@1.1.0: {} @@ -37113,6 +37389,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom-string@1.0.0: {} + strip-bom@3.0.0: {} strip-bom@4.0.0: {} @@ -37123,6 +37401,8 @@ snapshots: strip-final-newline@4.0.0: {} + strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} strip-json-comments@5.0.3: {} @@ -37237,11 +37517,11 @@ snapshots: swagger-ui-dist@5.17.14: {} - swc-loader@0.2.7(@swc/core@1.5.7(@swc/helpers@0.5.13))(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)): + swc-loader@0.2.7(@swc/core@1.5.7(@swc/helpers@0.5.13))(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)): dependencies: '@swc/core': 1.5.7(@swc/helpers@0.5.13) '@swc/counter': 0.1.3 - webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) sweetalert2@11.4.8: {} @@ -37305,34 +37585,27 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - tcp-port-used@1.0.2: - dependencies: - debug: 4.3.1 - is2: 2.0.9 - transitivePeerDependencies: - - supports-color - - terser-webpack-plugin@5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)): + terser-webpack-plugin@5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.46.0 - webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) optionalDependencies: '@swc/core': 1.5.7(@swc/helpers@0.5.13) - esbuild: 0.25.12 + esbuild: 0.27.7 - terser-webpack-plugin@5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)): + terser-webpack-plugin@5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 terser: 5.46.0 - webpack: 5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12) + webpack: 5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7) optionalDependencies: '@swc/core': 1.5.7(@swc/helpers@0.5.13) - esbuild: 0.25.12 + esbuild: 0.27.7 terser@5.46.0: dependencies: @@ -37371,6 +37644,10 @@ snapshots: dependencies: real-require: 0.2.0 + thread-stream@4.0.0: + dependencies: + real-require: 0.2.0 + throat@5.0.0: {} throttleit@2.1.0: {} @@ -37454,6 +37731,8 @@ snapshots: '@tokenizer/token': 0.3.0 ieee754: 1.2.1 + tokenx@1.3.0: {} + toposort@2.0.2: {} totalist@3.0.1: {} @@ -37538,7 +37817,7 @@ snapshots: dependencies: tslib: 2.8.1 - ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(esbuild@0.25.12)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4)))(typescript@5.5.4): + ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(esbuild@0.27.7)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4)))(typescript@5.5.4): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -37556,7 +37835,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.29.0) - esbuild: 0.25.12 + esbuild: 0.27.7 jest-util: 29.7.0 ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4): @@ -37986,6 +38265,11 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-check@1.5.4: + dependencies: + registry-auth-token: 3.3.2 + registry-url: 3.1.0 + upper-case-first@2.0.2: dependencies: tslib: 2.8.1 @@ -38096,6 +38380,8 @@ snapshots: uuid@11.1.0: {} + uuid@13.0.0: {} + uuid@3.4.0: {} uuid@8.3.2: {} @@ -38370,7 +38656,7 @@ snapshots: webpack-sources@3.3.4: {} - webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12): + webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -38394,7 +38680,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + terser-webpack-plugin: 5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)(webpack@5.105.4(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: @@ -38402,7 +38688,7 @@ snapshots: - esbuild - uglify-js - webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12): + webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -38425,7 +38711,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.3.0 - terser-webpack-plugin: 5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.25.12)) + terser-webpack-plugin: 5.3.17(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)(webpack@5.87.0(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)) watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: @@ -38527,6 +38813,10 @@ snapshots: dependencies: string-width: 4.2.3 + widest-line@4.0.1: + dependencies: + string-width: 5.1.2 + wildcard@1.1.2: {} windows-release@4.0.0: @@ -38589,10 +38879,6 @@ snapshots: bufferutil: 4.1.0 utf-8-validate: 6.0.6 - wsl-utils@0.1.0: - dependencies: - is-wsl: 3.1.1 - xml-name-validator@4.0.0: {} xml2js@0.5.0: @@ -38665,7 +38951,7 @@ snapshots: yocto-queue@0.1.0: {} - yocto-spinner@0.2.3: + yocto-spinner@1.1.0: dependencies: yoctocolors: 2.1.2 From ac109bf564a78d10019dbf122c3282d71aee6efa Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 3 Apr 2026 19:17:19 +0700 Subject: [PATCH 04/80] feat: mcp with oauth --- .../src/chat/oauth-middleware.ts | 251 ++++++++++++++++++ .../nestjs-libraries/src/chat/oauth-types.ts | 104 ++++++++ .../nestjs-libraries/src/chat/start.mcp.ts | 77 ++++++ 3 files changed, 432 insertions(+) create mode 100644 libraries/nestjs-libraries/src/chat/oauth-middleware.ts create mode 100644 libraries/nestjs-libraries/src/chat/oauth-types.ts diff --git a/libraries/nestjs-libraries/src/chat/oauth-middleware.ts b/libraries/nestjs-libraries/src/chat/oauth-middleware.ts new file mode 100644 index 00000000..7262f037 --- /dev/null +++ b/libraries/nestjs-libraries/src/chat/oauth-middleware.ts @@ -0,0 +1,251 @@ +/** + * OAuth Middleware for MCP Server + * + * Implements OAuth 2.0 Protected Resource support per RFC 9728 for MCP servers. + * Based on Mastra's implementation at commit 27c37ca. + * + * @see https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization + * @see https://www.rfc-editor.org/rfc/rfc9728.html + */ + +import type * as http from 'node:http'; + +import type { MCPServerOAuthConfig, TokenValidationResult } from './oauth-types'; +import { + generateProtectedResourceMetadata, + generateWWWAuthenticateHeader, + extractBearerToken, +} from './oauth-types'; + +interface OAuthMiddlewareLogger { + debug?: (message: string, ...args: unknown[]) => void; +} + +export interface OAuthMiddlewareOptions { + oauth: MCPServerOAuthConfig; + mcpPath?: string; + logger?: OAuthMiddlewareLogger; +} + +export interface OAuthMiddlewareResult { + proceed: boolean; + handled: boolean; + tokenValidation?: TokenValidationResult; +} + +export function createOAuthMiddleware(options: OAuthMiddlewareOptions) { + const { oauth, mcpPath = '/mcp', logger } = options; + + const protectedResourceMetadata = generateProtectedResourceMetadata(oauth); + const wellKnownPath = '/.well-known/oauth-protected-resource'; + const resourceMetadataUrl = new URL(wellKnownPath, oauth.resource).toString(); + + return async function oauthMiddleware( + req: http.IncomingMessage, + res: http.ServerResponse, + url: URL, + ): Promise { + logger?.debug?.(`OAuth middleware: ${req.method} ${url.pathname}`); + + // Handle Protected Resource Metadata endpoint (RFC 9728) + if (url.pathname === wellKnownPath && req.method === 'GET') { + logger?.debug?.('OAuth middleware: Serving Protected Resource Metadata'); + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Cache-Control': 'max-age=3600', + 'Access-Control-Allow-Origin': '*', + }); + res.end(JSON.stringify(protectedResourceMetadata)); + return { proceed: false, handled: true }; + } + + // Handle CORS preflight for metadata endpoint + if (url.pathname === wellKnownPath && req.method === 'OPTIONS') { + res.writeHead(204, { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type', + 'Access-Control-Max-Age': '86400', + }); + res.end(); + return { proceed: false, handled: true }; + } + + // Only protect the MCP endpoint + if (!url.pathname.startsWith(mcpPath)) { + return { proceed: true, handled: false }; + } + + // Extract and validate bearer token + const authHeader = req.headers['authorization']; + const token = extractBearerToken(authHeader as string | undefined); + + if (!token) { + logger?.debug?.('OAuth middleware: No bearer token provided'); + res.writeHead(401, { + 'Content-Type': 'application/json', + 'WWW-Authenticate': generateWWWAuthenticateHeader({ resourceMetadataUrl }), + }); + res.end( + JSON.stringify({ + error: 'unauthorized', + error_description: 'Bearer token required', + }), + ); + return { proceed: false, handled: true }; + } + + // Validate the token + if (oauth.validateToken) { + logger?.debug?.('OAuth middleware: Validating token'); + const validationResult = await oauth.validateToken(token, oauth.resource); + + if (!validationResult.valid) { + logger?.debug?.(`OAuth middleware: Token validation failed: ${validationResult.error}`); + res.writeHead(401, { + 'Content-Type': 'application/json', + 'WWW-Authenticate': generateWWWAuthenticateHeader({ + resourceMetadataUrl, + additionalParams: { + error: validationResult.error || 'invalid_token', + ...(validationResult.errorDescription && { + error_description: validationResult.errorDescription, + }), + }, + }), + }); + res.end( + JSON.stringify({ + error: validationResult.error || 'invalid_token', + error_description: validationResult.errorDescription || 'Token validation failed', + }), + ); + return { proceed: false, handled: true, tokenValidation: validationResult }; + } + + logger?.debug?.('OAuth middleware: Token validated successfully'); + return { proceed: true, handled: false, tokenValidation: validationResult }; + } + + // If no validateToken function provided, accept the token + logger?.debug?.('OAuth middleware: No token validation configured, accepting token'); + return { + proceed: true, + handled: false, + tokenValidation: { valid: true }, + }; + }; +} + +export function createStaticTokenValidator(validTokens: string[]): MCPServerOAuthConfig['validateToken'] { + const tokenSet = new Set(validTokens); + return async (token: string): Promise => { + if (tokenSet.has(token)) { + return { valid: true, scopes: ['mcp:read', 'mcp:write'] }; + } + return { + valid: false, + error: 'invalid_token', + errorDescription: 'Token not recognized', + }; + }; +} + +interface IntrospectionResponse { + active: boolean; + scope?: string; + client_id?: string; + username?: string; + token_type?: string; + exp?: number; + iat?: number; + nbf?: number; + sub?: string; + aud?: string | string[]; + iss?: string; + jti?: string; + [key: string]: unknown; +} + +export function createIntrospectionValidator( + introspectionEndpoint: string, + clientCredentials?: { clientId: string; clientSecret: string }, +): MCPServerOAuthConfig['validateToken'] { + return async (token: string, resource: string): Promise => { + try { + const headers: Record = { + 'Content-Type': 'application/x-www-form-urlencoded', + }; + + if (clientCredentials) { + if (clientCredentials.clientId.includes(':')) { + return { + valid: false, + error: 'invalid_request', + errorDescription: 'clientId cannot contain a colon character per RFC 7617', + }; + } + const credentials = Buffer.from(`${clientCredentials.clientId}:${clientCredentials.clientSecret}`).toString( + 'base64', + ); + headers['Authorization'] = `Basic ${credentials}`; + } + + const response = await fetch(introspectionEndpoint, { + method: 'POST', + headers, + body: new URLSearchParams({ + token, + token_type_hint: 'access_token', + }), + }); + + if (!response.ok) { + return { + valid: false, + error: 'server_error', + errorDescription: `Introspection failed: ${response.status}`, + }; + } + + const data = (await response.json()) as IntrospectionResponse; + + if (!data.active) { + return { + valid: false, + error: 'invalid_token', + errorDescription: 'Token is not active', + }; + } + + if (data.aud) { + const audiences = Array.isArray(data.aud) ? data.aud : [data.aud]; + if (!audiences.includes(resource)) { + return { + valid: false, + error: 'invalid_token', + errorDescription: 'Token audience does not match this resource', + }; + } + } + + return { + valid: true, + scopes: + data.scope + ?.trim() + .split(' ') + .filter(s => s !== '') || [], + subject: data.sub, + expiresAt: data.exp, + claims: data as Record, + }; + } catch (error) { + return { + valid: false, + error: 'server_error', + errorDescription: error instanceof Error ? error.message : 'Introspection failed', + }; + } + }; +} \ No newline at end of file diff --git a/libraries/nestjs-libraries/src/chat/oauth-types.ts b/libraries/nestjs-libraries/src/chat/oauth-types.ts new file mode 100644 index 00000000..67b4ec44 --- /dev/null +++ b/libraries/nestjs-libraries/src/chat/oauth-types.ts @@ -0,0 +1,104 @@ +/** + * OAuth Types for MCP Authentication + * + * Standalone types and helpers for OAuth-protected MCP servers. + * Based on Mastra's implementation at commit 27c37ca. + * + * @see https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization + * @see https://www.rfc-editor.org/rfc/rfc9728.html + */ + +import type * as http from 'node:http'; + +/** + * Configuration for OAuth-protected MCP server. + */ +export interface MCPServerOAuthConfig { + resource: string; + authorizationServers: string[]; + scopesSupported?: string[]; + resourceName?: string; + resourceDocumentation?: string; + validateToken?: (token: string, resource: string) => Promise; +} + +/** + * Result of token validation. + */ +export interface TokenValidationResult { + valid: boolean; + error?: string; + errorDescription?: string; + scopes?: string[]; + subject?: string; + expiresAt?: number; + claims?: Record; +} + +/** + * Options for OAuth-related HTTP responses. + */ +export interface OAuthResponseOptions { + resourceMetadataUrl?: string; + additionalParams?: Record; +} + +/** + * Protected Resource Metadata per RFC 9728. + */ +export interface OAuthProtectedResourceMetadata { + resource: string; + authorization_servers: string[]; + scopes_supported?: string[]; + bearer_methods_supported?: string[]; + resource_name?: string; + resource_documentation?: string; +} + +function escapeHeaderValue(value: string): string { + return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); +} + +export function generateWWWAuthenticateHeader(options: OAuthResponseOptions = {}): string { + const params: string[] = []; + + if (options.resourceMetadataUrl) { + params.push(`resource_metadata="${escapeHeaderValue(options.resourceMetadataUrl)}"`); + } + + if (options.additionalParams) { + for (const [key, value] of Object.entries(options.additionalParams)) { + params.push(`${key}="${escapeHeaderValue(value)}"`); + } + } + + if (params.length === 0) { + return 'Bearer'; + } + + return `Bearer ${params.join(', ')}`; +} + +export function generateProtectedResourceMetadata(config: MCPServerOAuthConfig): OAuthProtectedResourceMetadata { + return { + resource: config.resource, + authorization_servers: config.authorizationServers, + scopes_supported: config.scopesSupported ?? ['mcp:read', 'mcp:write'], + bearer_methods_supported: ['header'], + ...(config.resourceName && { resource_name: config.resourceName }), + ...(config.resourceDocumentation && { + resource_documentation: config.resourceDocumentation, + }), + }; +} + +export function extractBearerToken(authHeader: string | null | undefined): string | undefined { + if (!authHeader) return undefined; + + const prefix = 'bearer '; + if (authHeader.length <= prefix.length) return undefined; + if (authHeader.slice(0, prefix.length).toLowerCase() !== prefix) return undefined; + + const token = authHeader.slice(prefix.length).trim(); + return token || undefined; +} \ No newline at end of file diff --git a/libraries/nestjs-libraries/src/chat/start.mcp.ts b/libraries/nestjs-libraries/src/chat/start.mcp.ts index cc2dd5d7..0b29419d 100644 --- a/libraries/nestjs-libraries/src/chat/start.mcp.ts +++ b/libraries/nestjs-libraries/src/chat/start.mcp.ts @@ -6,6 +6,7 @@ import { randomUUID } from 'crypto'; import { OrganizationService } from '@gitroom/nestjs-libraries/database/prisma/organizations/organization.service'; import { OAuthService } from '@gitroom/nestjs-libraries/database/prisma/oauth/oauth.service'; import { runWithContext } from './async.storage'; +import { createOAuthMiddleware } from './oauth-middleware'; export const startMcp = async (app: INestApplication) => { const mastraService = app.get(MastraService, { strict: false }); const organizationService = app.get(OrganizationService, { strict: false }); @@ -33,6 +34,82 @@ export const startMcp = async (app: INestApplication) => { const server = new MCPServer(serverConfig); + const oauthMiddleware = createOAuthMiddleware({ + oauth: { + resource: new URL('/mcp-oauth', process.env.NEXT_PUBLIC_BACKEND_URL!).toString(), + authorizationServers: [process.env.NEXT_PUBLIC_BACKEND_URL!], + validateToken: async (token: string) => { + const org = await resolveAuth(token); + if (!org) { + return { valid: false, error: 'invalid_token', errorDescription: 'Invalid API Key or OAuth token' }; + } + return { valid: true, subject: token }; + }, + }, + mcpPath: '/mcp-oauth', + }); + + app.use('/.well-known/oauth-protected-resource', async (req: Request, res: Response) => { + const url = new URL('/.well-known/oauth-protected-resource', process.env.NEXT_PUBLIC_BACKEND_URL); + await oauthMiddleware(req, res, url); + }); + + app.use('/.well-known/oauth-authorization-server', async (req: Request, res: Response) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + if (req.method === 'OPTIONS') { + res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); + res.writeHead(204); + res.end(); + return; + } + res.setHeader('Content-Type', 'application/json'); + res.setHeader('Cache-Control', 'max-age=3600'); + res.json({ + issuer: process.env.NEXT_PUBLIC_BACKEND_URL, + authorization_endpoint: `${process.env.FRONTEND_URL}/oauth/authorize`, + token_endpoint: `${process.env.NEXT_PUBLIC_BACKEND_URL}/oauth/token`, + response_types_supported: ['code'], + grant_types_supported: ['authorization_code'], + code_challenge_methods_supported: ['S256'], + scopes_supported: ['mcp:read', 'mcp:write'], + }); + }); + + app.use('/mcp-oauth', async (req: Request, res: Response, next: () => void) => { + // Skip if this is the /mcp/:id route + if (req.path !== '/' && req.path !== '') { + next(); + return; + } + + const url = new URL('/mcp-oauth', process.env.NEXT_PUBLIC_BACKEND_URL); + + const result = await oauthMiddleware(req, res, url); + if (!result.proceed) return; + + const token = result.tokenValidation?.subject; + const auth = await resolveAuth(token!); + if (!auth) { + res.status(401).json({ error: 'invalid_token', error_description: 'Could not resolve organization' }); + return; + } + + await runWithContext({ requestId: token!, auth }, async () => { + await server.startHTTP({ + url: url, + httpPath: url.pathname, + options: { + sessionIdGenerator: () => { + return randomUUID(); + }, + }, + req, + res, + }); + }); + }); + app.use('/mcp', async (req: Request, res: Response, next: () => void) => { // Skip if this is the /mcp/:id route if (req.path !== '/' && req.path !== '') { From f55cca519c05ab573a7c111d285e2ee683e39f88 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 3 Apr 2026 19:39:29 +0700 Subject: [PATCH 05/80] feat: override --- libraries/nestjs-libraries/src/chat/start.mcp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/chat/start.mcp.ts b/libraries/nestjs-libraries/src/chat/start.mcp.ts index 0b29419d..436d357b 100644 --- a/libraries/nestjs-libraries/src/chat/start.mcp.ts +++ b/libraries/nestjs-libraries/src/chat/start.mcp.ts @@ -68,7 +68,7 @@ export const startMcp = async (app: INestApplication) => { res.json({ issuer: process.env.NEXT_PUBLIC_BACKEND_URL, authorization_endpoint: `${process.env.FRONTEND_URL}/oauth/authorize`, - token_endpoint: `${process.env.NEXT_PUBLIC_BACKEND_URL}/oauth/token`, + token_endpoint: `${process.env.NEXT_PUBLIC_OVERRIDE_BACKEND_URL || process.env.NEXT_PUBLIC_BACKEND_URL}/oauth/token`, response_types_supported: ['code'], grant_types_supported: ['authorization_code'], code_challenge_methods_supported: ['S256'], From 1bbfa8d603ccbe2f233dea95752d5143b4e81f22 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 3 Apr 2026 22:25:24 +0700 Subject: [PATCH 06/80] feat: fix header for all agents --- libraries/nestjs-libraries/src/chat/start.mcp.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libraries/nestjs-libraries/src/chat/start.mcp.ts b/libraries/nestjs-libraries/src/chat/start.mcp.ts index 7eff14a5..6f8afd0f 100644 --- a/libraries/nestjs-libraries/src/chat/start.mcp.ts +++ b/libraries/nestjs-libraries/src/chat/start.mcp.ts @@ -7,6 +7,17 @@ import { OrganizationService } from '@gitroom/nestjs-libraries/database/prisma/o import { OAuthService } from '@gitroom/nestjs-libraries/database/prisma/oauth/oauth.service'; import { runWithContext } from './async.storage'; import { createOAuthMiddleware } from './oauth-middleware'; +const fixAcceptHeader = (req: Request) => { + const value = 'application/json, text/event-stream'; + req.headers.accept = value; + const idx = req.rawHeaders.findIndex((h) => h.toLowerCase() === 'accept'); + if (idx !== -1) { + req.rawHeaders[idx + 1] = value; + } else { + req.rawHeaders.push('Accept', value); + } +}; + export const startMcp = async (app: INestApplication) => { const mastraService = app.get(MastraService, { strict: false }); const organizationService = app.get(OrganizationService, { strict: false }); @@ -95,6 +106,7 @@ export const startMcp = async (app: INestApplication) => { return; } + fixAcceptHeader(req); await runWithContext({ requestId: token!, auth }, async () => { await server.startHTTP({ url: url, @@ -144,6 +156,7 @@ export const startMcp = async (app: INestApplication) => { const url = new URL('/mcp', process.env.NEXT_PUBLIC_BACKEND_URL); + fixAcceptHeader(req); // @ts-ignore await runWithContext({ requestId: token, auth: req.auth }, async () => { await server.startHTTP({ @@ -186,6 +199,7 @@ export const startMcp = async (app: INestApplication) => { process.env.NEXT_PUBLIC_BACKEND_URL ); + fixAcceptHeader(req); await runWithContext( // @ts-ignore { requestId: req.params.id, auth: req.auth }, From c5882d3eae5ab8cd5d65baab2bfbc0fcf088af1e Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 3 Apr 2026 22:52:02 +0700 Subject: [PATCH 07/80] feat: auto accept and json response --- libraries/nestjs-libraries/src/chat/start.mcp.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/nestjs-libraries/src/chat/start.mcp.ts b/libraries/nestjs-libraries/src/chat/start.mcp.ts index 6f8afd0f..3b4d4b42 100644 --- a/libraries/nestjs-libraries/src/chat/start.mcp.ts +++ b/libraries/nestjs-libraries/src/chat/start.mcp.ts @@ -115,6 +115,7 @@ export const startMcp = async (app: INestApplication) => { sessionIdGenerator: () => { return randomUUID(); }, + enableJsonResponse: true, }, req, res, From 008deb0daffb5788ce57538bd6fcb785c8b5c021 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 4 Apr 2026 12:05:11 +0700 Subject: [PATCH 08/80] feat: update axios version --- package.json | 4 +-- pnpm-lock.yaml | 69 +++++++++++++++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index f1307977..fd6640ab 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "@langchain/core": "^0.3.44", "@langchain/langgraph": "^0.2.63", "@langchain/openai": "^0.5.5", - "@meronex/icons": "^4.0.0", "@mantine/core": "^5.10.5", "@mantine/dates": "^5.10.5", "@mantine/hooks": "^5.10.5", @@ -67,6 +66,7 @@ "@mastra/mcp": "^1.4.1", "@mastra/memory": "^1.13.0", "@mastra/pg": "^1.8.5", + "@meronex/icons": "^4.0.0", "@modelcontextprotocol/sdk": "^1.22.0", "@nest-lab/throttler-storage-redis": "^1.2.0", "@nestjs/cli": "10.0.2", @@ -144,7 +144,7 @@ "accept-language": "^3.0.20", "array-move": "^4.0.0", "async-mutex": "^0.5.0", - "axios": "^1.7.7", + "axios": "^1.14.0", "bcrypt": "^5.1.1", "bottleneck": "^2.19.5", "bs58": "^6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 058bb740..5aaf4435 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ importers: dependencies: '@ag-ui/mastra': specifier: ^1.0.1 - version: 1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(204b25c7c9e393334c406e7fe2b14723))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(df7fa9e3d1c753bb493fdac5d039b067))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@ai-sdk/openai': specifier: ^2.0.52 version: 2.0.98(zod@3.25.76) @@ -45,7 +45,7 @@ importers: version: 1.10.6(@types/react@19.1.8)(graphql@16.13.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@copilotkit/runtime': specifier: 1.10.6 - version: 1.10.6(204b25c7c9e393334c406e7fe2b14723) + version: 1.10.6(df7fa9e3d1c753bb493fdac5d039b067) '@dub/analytics': specifier: ^0.0.32 version: 0.0.32 @@ -54,7 +54,7 @@ importers: version: 3.10.0(react-hook-form@7.71.2(react@19.2.4)) '@langchain/community': specifier: ^0.3.40 - version: 0.3.59(45cfa14f738c5b504e0280393b96505c) + version: 0.3.59(2e4a19b3c0fffde05d18130d96cce925) '@langchain/core': specifier: ^0.3.44 version: 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) @@ -323,8 +323,8 @@ importers: specifier: ^0.5.0 version: 0.5.0 axios: - specifier: ^1.7.7 - version: 1.13.6(debug@4.4.3) + specifier: ^1.14.0 + version: 1.14.0 bcrypt: specifier: ^5.1.1 version: 5.1.1 @@ -9171,6 +9171,9 @@ packages: axios@1.13.6: resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} + axios@1.14.0: + resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==} + axobject-query@3.2.4: resolution: {integrity: sha512-aPTElBrbifBU1krmZxGZOlBkslORe7Ll7+BDnI50Wy4LgOt69luMgevkDfTq1O/ZgprooPCtWpjCwKSZw/iZ4A==} engines: {node: '>= 0.4'} @@ -14777,6 +14780,10 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} @@ -17656,12 +17663,12 @@ snapshots: - react - react-dom - '@ag-ui/mastra@1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(204b25c7c9e393334c406e7fe2b14723))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': + '@ag-ui/mastra@1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(df7fa9e3d1c753bb493fdac5d039b067))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@ag-ui/client': 0.0.47 '@ag-ui/core': 0.0.47 '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) - '@copilotkit/runtime': 1.10.6(204b25c7c9e393334c406e7fe2b14723) + '@copilotkit/runtime': 1.10.6(df7fa9e3d1c753bb493fdac5d039b067) '@mastra/client-js': 0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) rxjs: 7.8.1 @@ -19557,7 +19564,7 @@ snapshots: - encoding - graphql - '@copilotkit/runtime@1.10.6(204b25c7c9e393334c406e7fe2b14723)': + '@copilotkit/runtime@1.10.6(df7fa9e3d1c753bb493fdac5d039b067)': dependencies: '@ag-ui/client': 0.0.47 '@ag-ui/core': 0.0.47 @@ -19568,7 +19575,7 @@ snapshots: '@copilotkit/shared': 1.10.6 '@graphql-yoga/plugin-defer-stream': 3.18.0(graphql-yoga@5.18.0(graphql@16.13.1))(graphql@16.13.1) '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - '@langchain/community': 0.3.59(56da3b82a111ce776c286ff2a1d7f635) + '@langchain/community': 0.3.59(758e5da5f9d2f76d548b677d224e5fba) '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76) '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react@19.2.4) @@ -19581,7 +19588,7 @@ snapshots: graphql-scalars: 1.25.0(graphql@16.13.1) graphql-yoga: 5.18.0(graphql@16.13.1) groq-sdk: 0.5.0 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) partial-json: 0.1.7 pino: 9.14.0 @@ -21049,7 +21056,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@langchain/community@0.3.59(45cfa14f738c5b504e0280393b96505c)': + '@langchain/community@0.3.59(2e4a19b3c0fffde05d18130d96cce925)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) '@ibm-cloud/watsonx-ai': 1.7.9 @@ -21060,7 +21067,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.4.8 js-yaml: 4.1.1 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) math-expression-evaluator: 2.0.7 openai: 6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) @@ -21113,7 +21120,7 @@ snapshots: - handlebars - peggy - '@langchain/community@0.3.59(56da3b82a111ce776c286ff2a1d7f635)': + '@langchain/community@0.3.59(758e5da5f9d2f76d548b677d224e5fba)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) '@ibm-cloud/watsonx-ai': 1.7.9 @@ -21124,7 +21131,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.4.8 js-yaml: 4.1.1 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) math-expression-evaluator: 2.0.7 openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) @@ -21907,10 +21914,10 @@ snapshots: reflect-metadata: 0.1.14 tslib: 2.8.1 - '@nestjs/axios@4.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2)': + '@nestjs/axios@4.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.14.0)(rxjs@7.8.2)': dependencies: '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0 rxjs: 7.8.2 '@nestjs/cli@10.0.2(@swc/cli@0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)': @@ -22131,7 +22138,7 @@ snapshots: '@neynar/nodejs-sdk@3.137.0(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(bufferutil@4.1.0)(class-transformer@0.5.1)(class-validator@0.14.4)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@openapitools/openapi-generator-cli': 2.30.2(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4) - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0 semver: 7.7.4 viem: 2.47.0(bufferutil@4.1.0)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: @@ -22240,11 +22247,11 @@ snapshots: '@openapitools/openapi-generator-cli@2.30.2(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4)': dependencies: '@inquirer/select': 1.3.3 - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2) + '@nestjs/axios': 4.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.14.0)(rxjs@7.8.2) '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxtjs/opencollective': 0.3.2 - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0 chalk: 4.1.2 commander: 8.3.0 compare-versions: 6.1.1 @@ -28578,6 +28585,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.14.0: + dependencies: + follow-redirects: 1.15.11(debug@4.4.3) + form-data: 4.0.5 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + axobject-query@3.2.4: {} axobject-query@4.1.0: {} @@ -30806,7 +30821,7 @@ snapshots: facebook-nodejs-business-sdk@21.0.5: dependencies: - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0 currency-codes: 1.5.1 iso-3166-1: 2.1.1 js-sha256: 0.9.0 @@ -31986,7 +32001,7 @@ snapshots: isstream: 0.1.2 jsonwebtoken: 9.0.3 mime-types: 2.1.35 - retry-axios: 2.6.0(axios@1.13.6) + retry-axios: 2.6.0(axios@1.13.6(debug@4.4.3)) tough-cookie: 4.1.4 transitivePeerDependencies: - supports-color @@ -33099,7 +33114,7 @@ snapshots: konva@10.2.0: {} - langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): dependencies: '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) @@ -33115,7 +33130,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0 cheerio: 1.2.0 handlebars: 4.7.8 transitivePeerDependencies: @@ -33125,7 +33140,7 @@ snapshots: - openai - ws - langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.13.6)(cheerio@1.2.0)(handlebars@4.7.8)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): dependencies: '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) @@ -33141,7 +33156,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0 cheerio: 1.2.0 handlebars: 4.7.8 transitivePeerDependencies: @@ -35728,6 +35743,8 @@ snapshots: proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} + pseudomap@1.0.2: {} psl@1.15.0: @@ -36612,7 +36629,7 @@ snapshots: restructure@2.0.1: {} - retry-axios@2.6.0(axios@1.13.6): + retry-axios@2.6.0(axios@1.13.6(debug@4.4.3)): dependencies: axios: 1.13.6(debug@4.4.3) From fb43544bb293393647be676227b36aea08b6b67e Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 4 Apr 2026 12:56:05 +0700 Subject: [PATCH 09/80] feat: fix parseR --- apps/backend/src/main.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 2e6fb480..16f24427 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -22,7 +22,6 @@ import { startMcp } from '@gitroom/nestjs-libraries/chat/start.mcp'; async function start() { const app = await NestFactory.create(AppModule, { rawBody: true, - bodyParser: false, cors: { ...(!process.env.NOT_SECURED ? { credentials: true } : {}), allowedHeaders: [ @@ -53,12 +52,8 @@ async function start() { }) ); - app.use((req: any, res: any, next: any) => { - if (req.path.startsWith('/mcp') || req.path.startsWith('/sse/') || req.path.startsWith('/message/')) { - return next(); - } - const limit = ['/copilot/', '/posts'].some((p) => req.path.startsWith(p)) ? '50mb' : '100kb'; - json({ limit })(req, res, next); + app.use(['/copilot/*', '/posts'], (req: any, res: any, next: any) => { + json({ limit: '50mb' })(req, res, next); }); app.use(cookieParser()); From d16945a9e215bccaa21ba27b0ef12699c48b6e85 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 4 Apr 2026 15:00:27 +0700 Subject: [PATCH 10/80] feat: fix cli + server openai token --- apps/cli/.gitignore | 4 - apps/cli/.npmignore | 9 - apps/cli/CHANGELOG.md | 29 - apps/cli/FEATURES.md | 287 -------- apps/cli/HOW_TO_RUN.md | 300 -------- apps/cli/INTEGRATION_SETTINGS_DISCOVERY.md | 418 ------------ apps/cli/INTEGRATION_TOOLS_WORKFLOW.md | 435 ------------ apps/cli/PROJECT_STRUCTURE.md | 338 --------- apps/cli/PROVIDER_SETTINGS.md | 472 ------------- apps/cli/PROVIDER_SETTINGS_SUMMARY.md | 220 ------ apps/cli/PUBLISHING.md | 377 ---------- apps/cli/QUICK_START.md | 284 -------- apps/cli/README.md | 643 ------------------ apps/cli/SKILL.md | 607 ----------------- apps/cli/SUMMARY.md | 281 -------- apps/cli/SUPPORTED_FILE_TYPES.md | 305 --------- apps/cli/SYNTAX_UPGRADE.md | 291 -------- apps/cli/examples/COMMAND_LINE_GUIDE.md | 358 ---------- apps/cli/examples/EXAMPLES.md | 316 --------- apps/cli/examples/ai-agent-example.js | 103 --- apps/cli/examples/basic-usage.sh | 42 -- apps/cli/examples/command-line-examples.sh | 153 ----- apps/cli/examples/multi-platform-post.json | 89 --- .../multi-platform-with-settings.json | 95 --- apps/cli/examples/post-with-comments.json | 55 -- apps/cli/examples/reddit-post.json | 27 - apps/cli/examples/thread-post.json | 67 -- apps/cli/examples/tiktok-video.json | 31 - apps/cli/examples/youtube-video.json | 34 - apps/cli/package.json | 40 -- apps/cli/src/api.ts | 162 ----- apps/cli/src/commands/integrations.ts | 73 -- apps/cli/src/commands/posts.ts | 155 ----- apps/cli/src/commands/upload.ts | 26 - apps/cli/src/config.ts | 17 - apps/cli/src/index.ts | 240 ------- apps/cli/tsconfig.json | 15 - apps/cli/tsup.config.ts | 14 - .../nestjs-libraries/src/chat/start.mcp.ts | 7 + package.json | 2 - 40 files changed, 7 insertions(+), 7414 deletions(-) delete mode 100644 apps/cli/.gitignore delete mode 100644 apps/cli/.npmignore delete mode 100644 apps/cli/CHANGELOG.md delete mode 100644 apps/cli/FEATURES.md delete mode 100644 apps/cli/HOW_TO_RUN.md delete mode 100644 apps/cli/INTEGRATION_SETTINGS_DISCOVERY.md delete mode 100644 apps/cli/INTEGRATION_TOOLS_WORKFLOW.md delete mode 100644 apps/cli/PROJECT_STRUCTURE.md delete mode 100644 apps/cli/PROVIDER_SETTINGS.md delete mode 100644 apps/cli/PROVIDER_SETTINGS_SUMMARY.md delete mode 100644 apps/cli/PUBLISHING.md delete mode 100644 apps/cli/QUICK_START.md delete mode 100644 apps/cli/README.md delete mode 100644 apps/cli/SKILL.md delete mode 100644 apps/cli/SUMMARY.md delete mode 100644 apps/cli/SUPPORTED_FILE_TYPES.md delete mode 100644 apps/cli/SYNTAX_UPGRADE.md delete mode 100644 apps/cli/examples/COMMAND_LINE_GUIDE.md delete mode 100644 apps/cli/examples/EXAMPLES.md delete mode 100644 apps/cli/examples/ai-agent-example.js delete mode 100755 apps/cli/examples/basic-usage.sh delete mode 100755 apps/cli/examples/command-line-examples.sh delete mode 100644 apps/cli/examples/multi-platform-post.json delete mode 100644 apps/cli/examples/multi-platform-with-settings.json delete mode 100644 apps/cli/examples/post-with-comments.json delete mode 100644 apps/cli/examples/reddit-post.json delete mode 100644 apps/cli/examples/thread-post.json delete mode 100644 apps/cli/examples/tiktok-video.json delete mode 100644 apps/cli/examples/youtube-video.json delete mode 100644 apps/cli/package.json delete mode 100644 apps/cli/src/api.ts delete mode 100644 apps/cli/src/commands/integrations.ts delete mode 100644 apps/cli/src/commands/posts.ts delete mode 100644 apps/cli/src/commands/upload.ts delete mode 100644 apps/cli/src/config.ts delete mode 100644 apps/cli/src/index.ts delete mode 100644 apps/cli/tsconfig.json delete mode 100644 apps/cli/tsup.config.ts diff --git a/apps/cli/.gitignore b/apps/cli/.gitignore deleted file mode 100644 index 75352116..00000000 --- a/apps/cli/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -*.log -.DS_Store diff --git a/apps/cli/.npmignore b/apps/cli/.npmignore deleted file mode 100644 index b9146440..00000000 --- a/apps/cli/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -src -examples -tsconfig.json -tsup.config.ts -*.md -!README.md -node_modules -.git -.gitignore diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md deleted file mode 100644 index 82219562..00000000 --- a/apps/cli/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -# Changelog - -All notable changes to the Postiz CLI will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [1.0.0] - 2026-02-13 - -### Added -- Initial release of Postiz CLI -- `posts:create` - Create new social media posts -- `posts:list` - List all posts with pagination and search -- `posts:delete` - Delete posts by ID -- `integrations:list` - List connected social media integrations -- `upload` - Upload media files (images) -- Environment variable configuration (POSTIZ_API_KEY, POSTIZ_API_URL) -- Comprehensive help documentation -- Example scripts for basic usage and AI agent integration -- SKILL.md for AI agent usage patterns - -### Features -- Command-line interface for Postiz API -- Support for scheduled posts -- Multi-platform posting via integrations -- Media upload functionality -- User-friendly error messages with emojis -- JSON output for programmatic parsing -- Comprehensive examples for AI agents diff --git a/apps/cli/FEATURES.md b/apps/cli/FEATURES.md deleted file mode 100644 index 1e63f545..00000000 --- a/apps/cli/FEATURES.md +++ /dev/null @@ -1,287 +0,0 @@ -# Postiz CLI - Feature Summary - -## ✅ Complete Feature Set - -### Posts with Comments and Media - FULLY SUPPORTED - -The Postiz CLI **fully supports** the complete API structure including: - -#### ✅ Posts with Comments -- Main post content -- Multiple comments/replies -- Each comment can have different content -- Configurable delays between comments - -#### ✅ Multiple Media per Post/Comment -- Each post can have **multiple images** (array of MediaDto) -- Each comment can have **its own images** (separate MediaDto arrays) -- Support for various image formats (PNG, JPG, JPEG, GIF) -- Media can be URLs or uploaded files - -#### ✅ Multi-Platform Posting -- Post to multiple platforms in one request -- Platform-specific content for each integration -- Different media for different platforms - -#### ✅ Advanced Features -- Scheduled posting with precise timestamps -- URL shortening support -- Tags and metadata -- Delays between comments (in milliseconds) -- Draft mode for review before posting - -## Usage Modes - -### 1. Simple Mode (Command Line) - -For quick, simple posts: - -```bash -# Single post -postiz posts:create -c "Hello!" -i "twitter-123" - -# With multiple images -postiz posts:create -c "Post" --image "img1.jpg,img2.jpg,img3.jpg" -i "twitter-123" - -# With comments (no custom media per comment) -postiz posts:create -c "Main" --comments "Comment 1;Comment 2" -i "twitter-123" -``` - -**Limitations of Simple Mode:** -- Comments share the same media as the main post -- Cannot specify different images for each comment -- Cannot set custom delays between comments - -### 2. Advanced Mode (JSON Files) - -For complex posts with comments that have their own media: - -```bash -postiz posts:create --json complex-post.json -``` - -**Capabilities:** -- ✅ Each comment can have different media -- ✅ Custom delays between comments -- ✅ Multiple posts to different platforms -- ✅ Platform-specific content and media -- ✅ Full control over all API features - -## Real-World Examples - -### Example 1: Product Launch with Follow-up Comments - -**Main Post:** Product announcement with 3 product images -**Comment 1:** Feature highlight with 1 feature screenshot (posted 1 hour later) -**Comment 2:** Special offer with 1 promotional image (posted 2 hours later) - -```json -{ - "type": "schedule", - "date": "2024-03-15T09:00:00Z", - "posts": [{ - "integration": { "id": "twitter-123" }, - "value": [ - { - "content": "🚀 Launching our new product!", - "image": [ - { "id": "p1", "path": "product-1.jpg" }, - { "id": "p2", "path": "product-2.jpg" }, - { "id": "p3", "path": "product-3.jpg" } - ] - }, - { - "content": "⭐ Key features you'll love:", - "image": [ - { "id": "f1", "path": "features-screenshot.jpg" } - ], - "delay": 3600000 - }, - { - "content": "🎁 Limited time: 50% off!", - "image": [ - { "id": "o1", "path": "special-offer.jpg" } - ], - "delay": 7200000 - } - ] - }] -} -``` - -### Example 2: Tutorial Thread - -**Main Post:** Introduction with overview image -**Tweets 2-5:** Step-by-step with different screenshots for each step - -```json -{ - "type": "now", - "posts": [{ - "integration": { "id": "twitter-123" }, - "value": [ - { - "content": "🧵 How to use our CLI (1/5)", - "image": [{ "id": "1", "path": "overview.jpg" }] - }, - { - "content": "Step 1: Installation (2/5)", - "image": [{ "id": "2", "path": "step1.jpg" }], - "delay": 2000 - }, - { - "content": "Step 2: Configuration (3/5)", - "image": [{ "id": "3", "path": "step2.jpg" }], - "delay": 2000 - }, - { - "content": "Step 3: First post (4/5)", - "image": [{ "id": "4", "path": "step3.jpg" }], - "delay": 2000 - }, - { - "content": "You're all set! 🎉 (5/5)", - "image": [{ "id": "5", "path": "done.jpg" }], - "delay": 2000 - } - ] - }] -} -``` - -### Example 3: Multi-Platform Campaign - -**Same event, different content per platform:** - -```json -{ - "type": "schedule", - "date": "2024-12-25T12:00:00Z", - "posts": [ - { - "integration": { "id": "twitter-123" }, - "value": [ - { - "content": "Short, catchy Twitter post 🐦", - "image": [{ "id": "t1", "path": "twitter-square.jpg" }] - }, - { - "content": "Thread continuation with details", - "image": [{ "id": "t2", "path": "twitter-details.jpg" }], - "delay": 5000 - } - ] - }, - { - "integration": { "id": "linkedin-456" }, - "value": [{ - "content": "Professional, detailed LinkedIn post with business context...", - "image": [ - { "id": "l1", "path": "linkedin-wide.jpg" }, - { "id": "l2", "path": "linkedin-graph.jpg" } - ] - }] - }, - { - "integration": { "id": "facebook-789" }, - "value": [ - { - "content": "Engaging Facebook post for family/friends audience", - "image": [ - { "id": "f1", "path": "facebook-photo1.jpg" }, - { "id": "f2", "path": "facebook-photo2.jpg" }, - { "id": "f3", "path": "facebook-photo3.jpg" } - ] - }, - { - "content": "More info in the comments!", - "image": [{ "id": "f4", "path": "facebook-cta.jpg" }], - "delay": 300000 - } - ] - } - ] -} -``` - -## API Structure Reference - -### Complete CreatePostDto - -```typescript -{ - type: 'now' | 'schedule' | 'draft' | 'update', - date: string, // ISO 8601 date - shortLink: boolean, - tags: Array<{ - value: string, - label: string - }>, - posts: Array<{ - integration: { - id: string // From integrations:list - }, - value: Array<{ // Main post + comments - content: string, - image: Array<{ // Multiple images per post/comment - id: string, - path: string, - alt?: string, - thumbnail?: string - }>, - delay?: number, // Milliseconds - id?: string - }>, - settings: { - __type: 'EmptySettings' - } - }> -} -``` - -## For AI Agents - -### When to Use Simple Mode -- Quick single posts -- No need for comment-specific media -- Posting to 1-2 platforms -- Same content across platforms - -### When to Use Advanced Mode (JSON) -- ✅ **Comments need their own media** ← YOUR USE CASE -- ✅ Multi-platform with different content -- ✅ Threads with step-by-step images -- ✅ Timed follow-up comments -- ✅ Complex campaigns - -### AI Agent Tips - -1. **Generate JSON programmatically** - Don't write JSON manually -2. **Validate structure** - Use TypeScript types or JSON schema -3. **Test with "draft" type** - Review before posting -4. **Use unique image IDs** - Generate with UUID or random strings -5. **Set appropriate delays** - Twitter: 2-5s, others: 30s-1min+ - -## Files and Documentation - -- **examples/post-with-comments.json** - Post with comments, each having media -- **examples/multi-platform-post.json** - Multi-platform campaign -- **examples/thread-post.json** - Twitter thread example -- **examples/EXAMPLES.md** - Comprehensive guide with all patterns -- **SKILL.md** - Full AI agent usage guide -- **README.md** - Installation and basic usage - -## Summary - -### Question: Does it support posts with comments, each with media? - -**Answer: YES! ✅** - -- ✅ Posts can have multiple comments -- ✅ Each comment can have its own media (multiple images) -- ✅ Each post can have multiple images -- ✅ Use JSON files for full control -- ✅ See examples/ directory for working templates -- ✅ Fully compatible with the Postiz API structure - -The CLI supports the **complete Postiz API** including all advanced features! diff --git a/apps/cli/HOW_TO_RUN.md b/apps/cli/HOW_TO_RUN.md deleted file mode 100644 index ef003c3b..00000000 --- a/apps/cli/HOW_TO_RUN.md +++ /dev/null @@ -1,300 +0,0 @@ -# How to Run the Postiz CLI - -There are several ways to run the CLI, depending on your needs. - -## Option 1: Direct Execution (Quick Test) ⚡ - -The built file at `apps/cli/dist/index.js` is already executable! - -```bash -# From the monorepo root -node apps/cli/dist/index.js --help - -# Or run it directly (it has a shebang) -./apps/cli/dist/index.js --help - -# Example command -export POSTIZ_API_KEY=your_key -node apps/cli/dist/index.js posts:list -``` - -## Option 2: Link Globally (Recommended for Development) 🔗 - -This creates a global `postiz` command you can use anywhere: - -```bash -# From the monorepo root -cd apps/cli -pnpm link --global - -# Now you can use it anywhere! -postiz --help -postiz posts:list -postiz posts:create -c "Hello!" -i "twitter-123" - -# To unlink later -pnpm unlink --global -``` - -**After linking, you can use `postiz` from any directory!** - -## Option 3: Use pnpm Filter (From Root) 📦 - -```bash -# From the monorepo root -pnpm --filter postiz start -- --help -pnpm --filter postiz start -- posts:list -pnpm --filter postiz start -- posts:create -c "Hello" -i "twitter-123" -``` - -## Option 4: Use npm/npx (After Publishing) 🌐 - -Once published to npm: - -```bash -# Install globally -npm install -g postiz - -# Or use with npx (no install) -npx postiz --help -npx postiz posts:list -``` - -## Quick Setup Guide - -### Step 1: Build the CLI - -```bash -# From monorepo root -pnpm run build:cli -``` - -### Step 2: Set Your API Key - -```bash -export POSTIZ_API_KEY=your_api_key_here - -# To make it permanent, add to your shell profile: -echo 'export POSTIZ_API_KEY=your_api_key' >> ~/.bashrc -# or ~/.zshrc if you use zsh -``` - -### Step 3: Choose Your Method - -**For quick testing:** -```bash -node apps/cli/dist/index.js --help -``` - -**For regular use (recommended):** -```bash -cd apps/cli -pnpm link --global -postiz --help -``` - -## Troubleshooting - -### "Command not found: postiz" - -If you linked globally but still get this error: - -```bash -# Check if it's linked -which postiz - -# If not found, try linking again -cd apps/cli -pnpm link --global - -# Or check your PATH -echo $PATH -``` - -### "POSTIZ_API_KEY is not set" - -```bash -export POSTIZ_API_KEY=your_key - -# Verify it's set -echo $POSTIZ_API_KEY -``` - -### Permission Denied - -If you get permission errors: - -```bash -# Make the file executable -chmod +x apps/cli/dist/index.js - -# Then try again -./apps/cli/dist/index.js --help -``` - -### Rebuild After Changes - -After making code changes, rebuild: - -```bash -pnpm run build:cli -``` - -If you linked globally, the changes will be reflected immediately (no need to re-link). - -## Testing the CLI - -### Test Help Command - -```bash -postiz --help -postiz posts:create --help -``` - -### Test with Sample Command (requires API key) - -```bash -export POSTIZ_API_KEY=your_key - -# List integrations -postiz integrations:list - -# Create a test post -postiz posts:create \ - -c "Test post from CLI" \ - -i "your-integration-id" -``` - -## Development Workflow - -### 1. Make Changes - -Edit files in `apps/cli/src/` - -### 2. Rebuild - -```bash -pnpm run build:cli -``` - -### 3. Test - -```bash -# If linked globally -postiz --help - -# Or direct execution -node apps/cli/dist/index.js --help -``` - -### 4. Watch Mode (Auto-rebuild) - -```bash -# From apps/cli directory -pnpm run dev - -# In another terminal, test your changes -postiz --help -``` - -## Environment Variables - -### Required - -- `POSTIZ_API_KEY` - Your Postiz API key (required for all operations) - -### Optional - -- `POSTIZ_API_URL` - Custom API endpoint (default: `https://api.postiz.com`) - -### Setting Environment Variables - -**Temporary (current session):** -```bash -export POSTIZ_API_KEY=your_key -export POSTIZ_API_URL=https://custom-api.com -``` - -**Permanent (add to shell profile):** -```bash -# For bash -echo 'export POSTIZ_API_KEY=your_key' >> ~/.bashrc -source ~/.bashrc - -# For zsh -echo 'export POSTIZ_API_KEY=your_key' >> ~/.zshrc -source ~/.zshrc -``` - -## Using Aliases - -Create a convenient alias: - -```bash -# Add to ~/.bashrc or ~/.zshrc -alias pz='postiz' - -# Now you can use -pz posts:list -pz posts:create -c "Quick post" -i "twitter-123" -``` - -## Production Deployment - -### Publish to npm - -```bash -# From monorepo root -pnpm run publish-cli - -# Or from apps/cli -cd apps/cli -pnpm run publish -``` - -### Install from npm - -```bash -# Global install -npm install -g postiz - -# Project-specific -npm install postiz -npx postiz --help -``` - -## Summary of Methods - -| Method | Command | Use Case | -|--------|---------|----------| -| **Direct Node** | `node apps/cli/dist/index.js` | Quick testing, no installation | -| **Direct Execution** | `./apps/cli/dist/index.js` | Same as above, slightly shorter | -| **Global Link** | `postiz` (after `pnpm link --global`) | **Recommended** for development | -| **pnpm Filter** | `pnpm --filter postiz start --` | From monorepo root | -| **npm Global** | `postiz` (after `npm i -g postiz`) | After publishing to npm | -| **npx** | `npx postiz` | One-off usage without installing | - -## Recommended Setup - -For the best development experience: - -```bash -# 1. Build -pnpm run build:cli - -# 2. Link globally -cd apps/cli -pnpm link --global - -# 3. Set API key -export POSTIZ_API_KEY=your_key - -# 4. Test -postiz --help -postiz integrations:list - -# 5. Start using! -postiz posts:create -c "My first post" -i "twitter-123" -``` - -Now you can use `postiz` from anywhere! 🚀 diff --git a/apps/cli/INTEGRATION_SETTINGS_DISCOVERY.md b/apps/cli/INTEGRATION_SETTINGS_DISCOVERY.md deleted file mode 100644 index a2a4b5db..00000000 --- a/apps/cli/INTEGRATION_SETTINGS_DISCOVERY.md +++ /dev/null @@ -1,418 +0,0 @@ -# Integration Settings Discovery - -The CLI now has a powerful feature to discover what settings are available for each integration! - -## New Command: `integrations:settings` - -Get the settings schema, validation rules, and maximum character limits for any integration. - -## Usage - -```bash -postiz integrations:settings -``` - -## What It Returns - -```json -{ - "output": { - "maxLength": 280, - "settings": { - "properties": { - "who_can_reply_post": { - "enum": ["everyone", "following", "mentionedUsers", "subscribers", "verified"], - "description": "Who can reply to this post" - }, - "community": { - "pattern": "^(https://x.com/i/communities/\\d+)?$", - "description": "X community URL" - } - }, - "required": ["who_can_reply_post"] - } - } -} -``` - -## Workflow - -### 1. List Your Integrations - -```bash -postiz integrations:list -``` - -Output: -```json -[ - { - "id": "reddit-abc123", - "name": "My Reddit Account", - "identifier": "reddit", - "provider": "reddit" - }, - { - "id": "youtube-def456", - "name": "My YouTube Channel", - "identifier": "youtube", - "provider": "youtube" - }, - { - "id": "twitter-ghi789", - "name": "@myhandle", - "identifier": "x", - "provider": "x" - } -] -``` - -### 2. Get Settings for Specific Integration - -```bash -postiz integrations:settings reddit-abc123 -``` - -Output: -```json -{ - "output": { - "maxLength": 40000, - "settings": { - "properties": { - "subreddit": { - "type": "array", - "items": { - "properties": { - "value": { - "properties": { - "subreddit": { - "type": "string", - "minLength": 2, - "description": "Subreddit name" - }, - "title": { - "type": "string", - "minLength": 2, - "description": "Post title" - }, - "type": { - "type": "string", - "description": "Post type (text or link)" - }, - "url": { - "type": "string", - "description": "URL for link posts" - }, - "is_flair_required": { - "type": "boolean", - "description": "Whether flair is required" - }, - "flair": { - "properties": { - "id": "string", - "name": "string" - } - } - }, - "required": ["subreddit", "title", "type", "is_flair_required"] - } - } - } - } - }, - "required": ["subreddit"] - } - } -} -``` - -### 3. Use the Settings in Your Post - -Now you know what settings are available and required! - -```bash -postiz posts:create \ - -c "My post content" \ - -p reddit \ - --settings '{ - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Check this out!", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - }' \ - -i "reddit-abc123" -``` - -## Examples by Platform - -### Reddit - -```bash -postiz integrations:settings reddit-abc123 -``` - -Returns: -- Max length: 40,000 characters -- Required settings: subreddit, title, type -- Optional: flair - -### YouTube - -```bash -postiz integrations:settings youtube-def456 -``` - -Returns: -- Max length: 5,000 characters (description) -- Required settings: title, type (public/private/unlisted) -- Optional: tags, thumbnail, selfDeclaredMadeForKids - -### X (Twitter) - -```bash -postiz integrations:settings twitter-ghi789 -``` - -Returns: -- Max length: 280 characters (or 4,000 for verified) -- Required settings: who_can_reply_post -- Optional: community - -### LinkedIn - -```bash -postiz integrations:settings linkedin-jkl012 -``` - -Returns: -- Max length: 3,000 characters -- Optional settings: post_as_images_carousel, carousel_name - -### TikTok - -```bash -postiz integrations:settings tiktok-mno345 -``` - -Returns: -- Max length: 150 characters (caption) -- Required settings: privacy_level, duet, stitch, comment, autoAddMusic, brand_content_toggle, brand_organic_toggle, content_posting_method -- Optional: title, video_made_with_ai - -### Instagram - -```bash -postiz integrations:settings instagram-pqr678 -``` - -Returns: -- Max length: 2,200 characters -- Required settings: post_type (post or story) -- Optional: is_trial_reel, graduation_strategy, collaborators - -## No Additional Settings Required - -Some platforms don't require specific settings: - -```bash -postiz integrations:settings threads-stu901 -``` - -Returns: -```json -{ - "output": { - "maxLength": 500, - "settings": "No additional settings required" - } -} -``` - -Platforms with no additional settings: -- Threads -- Mastodon -- Bluesky -- Telegram -- Nostr -- VK - -## Use Cases - -### 1. Discovery - -Find out what settings are available before posting: - -```bash -# What settings does YouTube support? -postiz integrations:settings youtube-123 - -# What settings does Reddit support? -postiz integrations:settings reddit-456 -``` - -### 2. Validation - -Check maximum character limits: - -```bash -postiz integrations:settings twitter-789 | jq '.output.maxLength' -# Output: 280 -``` - -### 3. AI Agent Integration - -AI agents can call this endpoint to: -- Discover available settings dynamically -- Validate settings before posting -- Adapt to platform-specific requirements - -```javascript -// Get settings schema -const settings = await execSync( - `postiz integrations:settings ${integrationId}`, - { encoding: 'utf-8' } -); -const schema = JSON.parse(settings); - -// Check max length -if (content.length > schema.output.maxLength) { - content = content.substring(0, schema.output.maxLength); -} - -// Use required settings -const requiredSettings = schema.output.settings.required || []; -``` - -### 4. Form Generation - -Use the schema to generate UI forms: - -```javascript -const settings = await getIntegrationSettings('reddit-123'); -const schema = settings.output.settings; - -// Generate form fields from schema -schema.properties.subreddit.items.properties.value.properties -// → subreddit (text, minLength: 2) -// → title (text, minLength: 2) -// → type (select: text/link) -// → etc. -``` - -## Combined Workflow - -Complete workflow for posting with correct settings: - -```bash -#!/bin/bash -export POSTIZ_API_KEY=your_key - -# 1. List integrations -echo "📋 Available integrations:" -postiz integrations:list - -# 2. Get settings for Reddit -echo "" -echo "⚙️ Reddit settings:" -SETTINGS=$(postiz integrations:settings reddit-123) -echo $SETTINGS | jq '.output.maxLength' -echo $SETTINGS | jq '.output.settings' - -# 3. Create post with correct settings -echo "" -echo "📝 Creating post..." -postiz posts:create \ - -c "My post content" \ - -p reddit \ - --settings '{ - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Interesting post", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - }' \ - -i "reddit-123" -``` - -## API Endpoint - -The command calls: -``` -GET /public/v1/integration-settings/:id -``` - -Returns: -```typescript -{ - output: { - maxLength: number; - settings: ValidationSchema | "No additional settings required"; - } -} -``` - -## Error Handling - -### Integration Not Found - -```bash -postiz integrations:settings invalid-id -# ❌ Failed to get integration settings: Integration not found -``` - -### API Key Not Set - -```bash -postiz integrations:settings reddit-123 -# ❌ Error: POSTIZ_API_KEY environment variable is required -``` - -## Tips - -1. **Always check settings first** before creating posts with custom settings -2. **Use the schema** to validate your settings object -3. **Check maxLength** to avoid exceeding character limits -4. **For AI agents**: Cache the settings to avoid repeated API calls -5. **Required fields** must be included in your settings object - -## Comparison: Before vs After - -### Before ❌ - -```bash -# Had to guess what settings are available -# Had to read documentation or source code -# Didn't know character limits -``` - -### After ✅ - -```bash -# Discover settings programmatically -postiz integrations:settings reddit-123 - -# See exactly what's required and optional -# Know the exact character limits -# Get validation schemas -``` - -## Summary - -✅ **Discover settings for any integration** -✅ **Get character limits** -✅ **See validation schemas** -✅ **Know required vs optional fields** -✅ **Perfect for AI agents** -✅ **No more guesswork!** - -**Now you can discover what settings each platform supports!** 🎉 diff --git a/apps/cli/INTEGRATION_TOOLS_WORKFLOW.md b/apps/cli/INTEGRATION_TOOLS_WORKFLOW.md deleted file mode 100644 index e6986e5d..00000000 --- a/apps/cli/INTEGRATION_TOOLS_WORKFLOW.md +++ /dev/null @@ -1,435 +0,0 @@ -# Integration Tools Workflow - -Some integrations require additional data (like IDs, tags, playlists, etc.) before you can post. The CLI supports a complete workflow to discover and use these tools. - -## The Complete Workflow - -### Step 1: List Integrations - -```bash -postiz integrations:list -``` - -Get your integration IDs. - -### Step 2: Get Integration Settings - -```bash -postiz integrations:settings -``` - -This returns: -- `maxLength` - Character limit -- `settings` - Required/optional fields -- **`tools`** - Callable methods to fetch additional data - -### Step 3: Trigger Tools (If Needed) - -If settings require IDs/data you don't have, use the tools: - -```bash -postiz integrations:trigger -d '{"key":"value"}' -``` - -### Step 4: Create Post with Complete Settings - -Use the data from Step 3 in your post settings. - -## Real-World Example: Reddit - -### 1. Get Reddit Integration Settings - -```bash -postiz integrations:settings reddit-abc123 -``` - -**Output:** -```json -{ - "output": { - "maxLength": 40000, - "settings": { - "properties": { - "subreddit": { - "type": "array", - "items": { - "properties": { - "subreddit": { "type": "string" }, - "title": { "type": "string" }, - "flair": { - "properties": { - "id": { "type": "string" } // ← Need flair ID! - } - } - } - } - } - } - }, - "tools": [ - { - "methodName": "getFlairs", - "description": "Get available flairs for a subreddit", - "dataSchema": [ - { - "key": "subreddit", - "description": "The subreddit name", - "type": "string" - } - ] - }, - { - "methodName": "searchSubreddits", - "description": "Search for subreddits", - "dataSchema": [ - { - "key": "query", - "description": "Search query", - "type": "string" - } - ] - } - ] - } -} -``` - -### 2. Get Flairs for the Subreddit - -```bash -postiz integrations:trigger reddit-abc123 getFlairs -d '{"subreddit":"programming"}' -``` - -**Output:** -```json -{ - "output": [ - { - "id": "flair-12345", - "name": "Discussion" - }, - { - "id": "flair-67890", - "name": "Tutorial" - } - ] -} -``` - -### 3. Create Post with Flair ID - -```bash -postiz posts:create \ - -c "Check out my project!" \ - -p reddit \ - --settings '{ - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "My Cool Project", - "type": "text", - "url": "", - "is_flair_required": true, - "flair": { - "id": "flair-12345", - "name": "Discussion" - } - } - }] - }' \ - -i "reddit-abc123" -``` - -## Example: YouTube Playlists - -### 1. Get YouTube Settings - -```bash -postiz integrations:settings youtube-123 -``` - -**Output includes tools:** -```json -{ - "tools": [ - { - "methodName": "getPlaylists", - "description": "Get your YouTube playlists", - "dataSchema": [] - }, - { - "methodName": "getCategories", - "description": "Get available video categories", - "dataSchema": [] - } - ] -} -``` - -### 2. Get Playlists - -```bash -postiz integrations:trigger youtube-123 getPlaylists -``` - -**Output:** -```json -{ - "output": [ - { - "id": "PLxxxxxx", - "title": "My Tutorials" - }, - { - "id": "PLyyyyyy", - "title": "Product Demos" - } - ] -} -``` - -### 3. Post to Specific Playlist - -```bash -postiz posts:create \ - -c "Video description" \ - -p youtube \ - --settings '{ - "title": "My Video", - "type": "public", - "playlistId": "PLxxxxxx" - }' \ - -i "youtube-123" -``` - -## Example: LinkedIn Companies - -### 1. Get LinkedIn Settings - -```bash -postiz integrations:settings linkedin-123 -``` - -**Output includes tools:** -```json -{ - "tools": [ - { - "methodName": "getCompanies", - "description": "Get companies you can post to", - "dataSchema": [] - } - ] -} -``` - -### 2. Get Companies - -```bash -postiz integrations:trigger linkedin-123 getCompanies -``` - -**Output:** -```json -{ - "output": [ - { - "id": "company-123", - "name": "My Company" - }, - { - "id": "company-456", - "name": "Other Company" - } - ] -} -``` - -### 3. Post as Company - -```bash -postiz posts:create \ - -c "Company announcement" \ - -p linkedin \ - --settings '{ - "companyId": "company-123" - }' \ - -i "linkedin-123" -``` - -## Understanding Tools - -### Tool Structure - -```json -{ - "methodName": "getFlairs", - "description": "Get available flairs for a subreddit", - "dataSchema": [ - { - "key": "subreddit", - "description": "The subreddit name", - "type": "string" - } - ] -} -``` - -- **methodName** - Use this in `integrations:trigger` -- **description** - What the tool does -- **dataSchema** - Required input parameters - -### Calling Tools - -```bash -# No parameters -postiz integrations:trigger - -# With parameters -postiz integrations:trigger -d '{"key":"value"}' -``` - -## Common Tool Methods - -### Reddit -- `getFlairs` - Get flairs for a subreddit -- `searchSubreddits` - Search for subreddits -- `getSubreddits` - Get subscribed subreddits - -### YouTube -- `getPlaylists` - Get your playlists -- `getCategories` - Get video categories -- `getChannels` - Get your channels - -### LinkedIn -- `getCompanies` - Get companies you manage -- `getOrganizations` - Get organizations - -### Twitter/X -- `getListsowned` - Get your Twitter lists -- `getCommunities` - Get communities you're in - -### Pinterest -- `getBoards` - Get your Pinterest boards -- `getBoardSections` - Get sections in a board - -## AI Agent Workflow - -For AI agents, this enables dynamic discovery and usage: - -```javascript -// 1. Get settings and tools -const settings = JSON.parse( - execSync(`postiz integrations:settings ${integrationId}`) -); - -// 2. Check if tools are needed -const tools = settings.output.tools || []; - -// 3. Call tools to get required data -for (const tool of tools) { - if (needsThisTool(tool)) { - const data = buildDataForTool(tool.dataSchema); - const result = JSON.parse( - execSync( - `postiz integrations:trigger ${integrationId} ${tool.methodName} -d '${JSON.stringify(data)}'` - ) - ); - - // Use result.output in your settings - updateSettings(result.output); - } -} - -// 4. Create post with complete settings -execSync(`postiz posts:create -c "${content}" --settings '${JSON.stringify(settings)}' -i "${integrationId}"`); -``` - -## Error Handling - -### Tool Not Found - -```bash -postiz integrations:trigger reddit-123 invalidMethod -# ❌ Failed to trigger tool: Tool not found -``` - -### Missing Required Data - -```bash -postiz integrations:trigger reddit-123 getFlairs -# ❌ Missing required parameter: subreddit -``` - -### Integration Not Found - -```bash -postiz integrations:trigger invalid-id getFlairs -# ❌ Failed to trigger tool: Integration not found -``` - -## Tips - -1. **Always check tools first** - Run `integrations:settings` to see available tools -2. **Read dataSchema** - Know what parameters each tool needs -3. **Parse JSON output** - Use `jq` or similar to extract data -4. **Cache results** - Tool results don't change often -5. **For AI agents** - Automate the entire workflow - -## Complete Example Script - -```bash -#!/bin/bash -export POSTIZ_API_KEY=your_key -INTEGRATION_ID="reddit-abc123" - -# 1. Get settings -echo "📋 Getting settings..." -SETTINGS=$(postiz integrations:settings $INTEGRATION_ID) -echo $SETTINGS | jq '.output.tools' - -# 2. Get flairs -echo "" -echo "🏷️ Getting flairs..." -FLAIRS=$(postiz integrations:trigger $INTEGRATION_ID getFlairs -d '{"subreddit":"programming"}') -FLAIR_ID=$(echo $FLAIRS | jq -r '.output[0].id') -FLAIR_NAME=$(echo $FLAIRS | jq -r '.output[0].name') - -echo "Selected flair: $FLAIR_NAME ($FLAIR_ID)" - -# 3. Create post -echo "" -echo "📝 Creating post..." -postiz posts:create \ - -c "My post content" \ - -p reddit \ - --settings "{ - \"subreddit\": [{ - \"value\": { - \"subreddit\": \"programming\", - \"title\": \"My Post Title\", - \"type\": \"text\", - \"url\": \"\", - \"is_flair_required\": true, - \"flair\": { - \"id\": \"$FLAIR_ID\", - \"name\": \"$FLAIR_NAME\" - } - } - }] - }" \ - -i "$INTEGRATION_ID" - -echo "✅ Done!" -``` - -## Summary - -✅ **Discover available tools** with `integrations:settings` -✅ **Call tools** to fetch required data with `integrations:trigger` -✅ **Use tool results** in post settings -✅ **Complete workflow** from discovery to posting -✅ **Perfect for AI agents** - fully automated -✅ **No guesswork** - know exactly what data you need - -**The CLI now supports the complete integration tools workflow!** 🎉 diff --git a/apps/cli/PROJECT_STRUCTURE.md b/apps/cli/PROJECT_STRUCTURE.md deleted file mode 100644 index 30daaa16..00000000 --- a/apps/cli/PROJECT_STRUCTURE.md +++ /dev/null @@ -1,338 +0,0 @@ -# Postiz CLI - Project Structure - -## Overview - -The Postiz CLI is a complete command-line interface package for interacting with the Postiz social media scheduling API. It's designed for developers and AI agents to automate social media posting. - -## Directory Structure - -``` -apps/cli/ -├── src/ # Source code -│ ├── index.ts # Main CLI entry point -│ ├── api.ts # API client for Postiz API -│ ├── config.ts # Configuration and environment handling -│ └── commands/ # Command implementations -│ ├── posts.ts # Posts management commands -│ ├── integrations.ts # Integrations listing -│ └── upload.ts # Media upload command -│ -├── examples/ # Usage examples -│ ├── basic-usage.sh # Shell script example -│ └── ai-agent-example.js # Node.js AI agent example -│ -├── dist/ # Build output (generated) -│ ├── index.js # Compiled CLI executable -│ └── index.js.map # Source map -│ -├── package.json # Package configuration -├── tsconfig.json # TypeScript configuration -├── tsup.config.ts # Build configuration -│ -├── README.md # Main documentation -├── SKILL.md # AI agent usage guide -├── QUICK_START.md # Quick start guide -├── CHANGELOG.md # Version history -├── PROJECT_STRUCTURE.md # This file -│ -├── .gitignore # Git ignore rules -└── .npmignore # npm publish ignore rules -``` - -## File Descriptions - -### Source Files - -#### `src/index.ts` -- Main entry point for the CLI -- Uses `yargs` for command parsing -- Defines all available commands and their options -- Contains help text and usage examples - -#### `src/api.ts` -- API client class `PostizAPI` -- Handles all HTTP requests to the Postiz API -- Methods for: - - Creating posts - - Listing posts - - Deleting posts - - Uploading files - - Listing integrations -- Error handling and response parsing - -#### `src/config.ts` -- Configuration management -- Environment variable handling -- Validates required settings (API key) -- Provides default values - -#### `src/commands/posts.ts` -- Post management commands implementation -- `createPost()` - Create new social media posts -- `listPosts()` - List posts with filters -- `deletePost()` - Delete posts by ID - -#### `src/commands/integrations.ts` -- Integration management -- `listIntegrations()` - Show connected accounts - -#### `src/commands/upload.ts` -- Media upload functionality -- `uploadFile()` - Upload images to Postiz - -### Configuration Files - -#### `package.json` -- Package name: `postiz` -- Version: `1.0.0` -- Executable bin: `postiz` → `dist/index.js` -- Scripts: `dev`, `build`, `start`, `publish` -- Repository and metadata information - -#### `tsconfig.json` -- Extends base config from monorepo -- Target: ES2017 -- Module: CommonJS -- Enables decorators and source maps - -#### `tsup.config.ts` -- Build tool configuration -- Entry point: `src/index.ts` -- Output format: CommonJS -- Adds shebang for Node.js execution -- Generates source maps - -### Documentation Files - -#### `README.md` -- Main package documentation -- Installation instructions -- Usage examples -- API reference -- Development guide - -#### `SKILL.md` -- Comprehensive guide for AI agents -- Usage patterns and workflows -- Command examples -- Best practices -- Error handling - -#### `QUICK_START.md` -- Fast onboarding guide -- Installation steps -- Basic commands -- Common workflows -- Troubleshooting - -#### `CHANGELOG.md` -- Version history -- Release notes -- Feature additions -- Bug fixes - -### Example Files - -#### `examples/basic-usage.sh` -- Bash script example -- Demonstrates basic CLI workflow -- Shows integration listing, post creation, and deletion - -#### `examples/ai-agent-example.js` -- Node.js script for AI agents -- Programmatic CLI usage -- Batch post creation -- JSON parsing examples - -## Build Process - -### Development Build - -```bash -pnpm run dev -``` - -- Watches for file changes -- Rebuilds automatically -- Useful during development - -### Production Build - -```bash -pnpm run build -``` - -1. Cleans `dist/` directory -2. Compiles TypeScript → JavaScript -3. Bundles dependencies -4. Adds shebang for executable -5. Generates source maps -6. Makes output executable - -### Output - -- `dist/index.js` - Main executable (~490KB) -- `dist/index.js.map` - Source map (~920KB) - -## Commands Architecture - -### Command Flow - -``` -User Input - ↓ -index.ts (yargs parser) - ↓ -Command Handler (posts.ts, integrations.ts, upload.ts) - ↓ -config.ts (get API key) - ↓ -api.ts (make API request) - ↓ -Response / Error - ↓ -Output to console -``` - -### Available Commands - -1. **posts:create** - - Options: `--content`, `--integrations`, `--schedule`, `--image` - - Handler: `commands/posts.ts::createPost()` - -2. **posts:list** - - Options: `--page`, `--limit`, `--search` - - Handler: `commands/posts.ts::listPosts()` - -3. **posts:delete** - - Positional: `` - - Handler: `commands/posts.ts::deletePost()` - -4. **integrations:list** - - No options - - Handler: `commands/integrations.ts::listIntegrations()` - -5. **upload** - - Positional: `` - - Handler: `commands/upload.ts::uploadFile()` - -## Environment Variables - -| Variable | Required | Default | Usage | -|----------|----------|---------|-------| -| `POSTIZ_API_KEY` | ✅ Yes | - | Authentication token | -| `POSTIZ_API_URL` | ❌ No | `https://api.postiz.com` | Custom API endpoint | - -## Dependencies - -### Runtime Dependencies (from root) -- `yargs` - CLI argument parsing -- `node-fetch` - HTTP requests -- Standard Node.js modules (`fs`, `path`) - -### Dev Dependencies -- `tsup` - TypeScript bundler -- `typescript` - Type checking -- `@types/yargs` - TypeScript types - -## Integration Points - -### With Monorepo - -1. **Build Scripts** - - Added to root `package.json` - - `pnpm run build:cli` - Build the CLI - - `pnpm run publish-cli` - Publish to npm - -2. **TypeScript Config** - - Extends `tsconfig.base.json` - - Shares common compiler options - -3. **Dependencies** - - Uses shared dependencies from root - - No duplicate packages - -### With Postiz API - -1. **Endpoints Used** - - `POST /public/v1/posts` - Create post - - `GET /public/v1/posts` - List posts - - `DELETE /public/v1/posts/:id` - Delete post - - `GET /public/v1/integrations` - List integrations - - `POST /public/v1/upload` - Upload media - -2. **Authentication** - - API key via `Authorization` header - - Configured through environment variable - -## Publishing - -### To npm - -```bash -pnpm run publish-cli -``` - -This will: -1. Build the package -2. Publish to npm with public access -3. Include only `dist/`, `README.md`, and `SKILL.md` - -### Package Contents (via .npmignore) - -**Included:** -- `dist/` - Compiled code -- `README.md` - Documentation - -**Excluded:** -- `src/` - Source code -- `examples/` - Examples -- Config files -- Other markdown files - -## Testing - -### Manual Testing - -```bash -# Test help -node dist/index.js --help - -# Test without API key (should error) -node dist/index.js posts:list - -# Test with API key (requires valid key) -POSTIZ_API_KEY=test node dist/index.js integrations:list -``` - -### Automated Testing (Future) - -- Unit tests for API client -- Integration tests for commands -- E2E tests with mock API - -## Future Enhancements - -1. **More Commands** - - Analytics retrieval - - Team management - - Settings configuration - -2. **Features** - - Interactive mode - - Config file support (~/.postizrc) - - Output formatting (JSON, table, CSV) - - Verbose/debug mode - - Batch operations from file - -3. **Developer Experience** - - TypeScript types export - - Programmatic API - - Plugin system - - Custom integrations - -## Support - -- **Issues:** https://github.com/gitroomhq/postiz-app/issues -- **Docs:** See README.md, SKILL.md, QUICK_START.md -- **Website:** https://postiz.com diff --git a/apps/cli/PROVIDER_SETTINGS.md b/apps/cli/PROVIDER_SETTINGS.md deleted file mode 100644 index a01c5e82..00000000 --- a/apps/cli/PROVIDER_SETTINGS.md +++ /dev/null @@ -1,472 +0,0 @@ -# Provider-Specific Settings - -The Postiz CLI supports platform-specific settings for each integration. Different platforms have different options and requirements. - -## How to Use Provider Settings - -### Method 1: Command Line Flags - -```bash -postiz posts:create \ - -c "Your content" \ - -p \ - --settings '' \ - -i "integration-id" -``` - -### Method 2: JSON File - -```bash -postiz posts:create --json post-with-settings.json -``` - -In the JSON file, specify settings per integration: - -```json -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { "id": "reddit-123" }, - "value": [{ "content": "Post content", "image": [] }], - "settings": { - "__type": "reddit", - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "My Post Title", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - } - }] -} -``` - -## Supported Platforms & Settings - -### Reddit (`reddit`) - -**Settings:** -- `subreddit` (required): Subreddit name -- `title` (required): Post title -- `type` (required): `"text"` or `"link"` -- `url` (required for links): URL if type is "link" -- `is_flair_required` (boolean): Whether flair is required -- `flair` (optional): Flair object with `id` and `name` - -**Example:** -```bash -postiz posts:create \ - -c "Post content here" \ - -p reddit \ - --settings '{ - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Check out this cool project", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - }' \ - -i "reddit-123" -``` - -### YouTube (`youtube`) - -**Settings:** -- `title` (required): Video title (2-100 characters) -- `type` (required): `"public"`, `"private"`, or `"unlisted"` -- `selfDeclaredMadeForKids` (optional): `"yes"` or `"no"` -- `thumbnail` (optional): Thumbnail MediaDto object -- `tags` (optional): Array of tag objects with `value` and `label` - -**Example:** -```bash -postiz posts:create \ - -c "Video description here" \ - -p youtube \ - --settings '{ - "title": "My Awesome Video", - "type": "public", - "selfDeclaredMadeForKids": "no", - "tags": [ - {"value": "tech", "label": "Tech"}, - {"value": "tutorial", "label": "Tutorial"} - ] - }' \ - -i "youtube-123" -``` - -### X / Twitter (`x`) - -**Settings:** -- `community` (optional): X community URL (format: `https://x.com/i/communities/1234567890`) -- `who_can_reply_post` (required): Who can reply - - `"everyone"` - Anyone can reply - - `"following"` - Only people you follow - - `"mentionedUsers"` - Only mentioned users - - `"subscribers"` - Only subscribers - - `"verified"` - Only verified users - -**Example:** -```bash -postiz posts:create \ - -c "Tweet content" \ - -p x \ - --settings '{ - "who_can_reply_post": "everyone" - }' \ - -i "twitter-123" -``` - -**With Community:** -```bash -postiz posts:create \ - -c "Community tweet" \ - -p x \ - --settings '{ - "community": "https://x.com/i/communities/1493446837214187523", - "who_can_reply_post": "everyone" - }' \ - -i "twitter-123" -``` - -### LinkedIn (`linkedin`) - -**Settings:** -- `post_as_images_carousel` (boolean): Post as image carousel -- `carousel_name` (optional): Carousel name if posting as carousel - -**Example:** -```bash -postiz posts:create \ - -c "LinkedIn post" \ - -m "img1.jpg,img2.jpg,img3.jpg" \ - -p linkedin \ - --settings '{ - "post_as_images_carousel": true, - "carousel_name": "Product Showcase" - }' \ - -i "linkedin-123" -``` - -### Instagram (`instagram`) - -**Settings:** -- `post_type` (required): `"post"` or `"story"` -- `is_trial_reel` (optional): Boolean -- `graduation_strategy` (optional): `"MANUAL"` or `"SS_PERFORMANCE"` -- `collaborators` (optional): Array of collaborator objects with `label` - -**Example:** -```bash -postiz posts:create \ - -c "Instagram post" \ - -m "photo.jpg" \ - -p instagram \ - --settings '{ - "post_type": "post", - "is_trial_reel": false - }' \ - -i "instagram-123" -``` - -**Story Example:** -```bash -postiz posts:create \ - -c "Story content" \ - -m "story-image.jpg" \ - -p instagram \ - --settings '{ - "post_type": "story" - }' \ - -i "instagram-123" -``` - -### TikTok (`tiktok`) - -**Settings:** -- `title` (optional): Video title (max 90 characters) -- `privacy_level` (required): Privacy level - - `"PUBLIC_TO_EVERYONE"` - - `"MUTUAL_FOLLOW_FRIENDS"` - - `"FOLLOWER_OF_CREATOR"` - - `"SELF_ONLY"` -- `duet` (boolean): Allow duets -- `stitch` (boolean): Allow stitch -- `comment` (boolean): Allow comments -- `autoAddMusic` (required): `"yes"` or `"no"` -- `brand_content_toggle` (boolean): Brand content toggle -- `brand_organic_toggle` (boolean): Brand organic toggle -- `video_made_with_ai` (optional): Boolean -- `content_posting_method` (required): `"DIRECT_POST"` or `"UPLOAD"` - -**Example:** -```bash -postiz posts:create \ - -c "TikTok video description" \ - -m "video.mp4" \ - -p tiktok \ - --settings '{ - "title": "Check this out!", - "privacy_level": "PUBLIC_TO_EVERYONE", - "duet": true, - "stitch": true, - "comment": true, - "autoAddMusic": "no", - "brand_content_toggle": false, - "brand_organic_toggle": false, - "content_posting_method": "DIRECT_POST" - }' \ - -i "tiktok-123" -``` - -### Facebook (`facebook`) - -Settings available - check the DTO for specifics. - -### Pinterest (`pinterest`) - -Settings available - check the DTO for specifics. - -### Discord (`discord`) - -Settings available - check the DTO for specifics. - -### Slack (`slack`) - -Settings available - check the DTO for specifics. - -### Medium (`medium`) - -Settings available - check the DTO for specifics. - -### Dev.to (`devto`) - -Settings available - check the DTO for specifics. - -### Hashnode (`hashnode`) - -Settings available - check the DTO for specifics. - -### WordPress (`wordpress`) - -Settings available - check the DTO for specifics. - -## Platforms Without Specific Settings - -These platforms use the default `EmptySettings`: -- `threads` -- `mastodon` -- `bluesky` -- `telegram` -- `nostr` -- `vk` - -For these, you don't need to specify settings or can use: -```bash --p threads # or any of the above -``` - -## Using JSON Files for Complex Settings - -For complex settings, it's easier to use JSON files: - -### Reddit Example - -**reddit-post.json:** -```json -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { "id": "reddit-123" }, - "value": [{ - "content": "Check out this cool project!", - "image": [] - }], - "settings": { - "__type": "reddit", - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "My Cool Project - Built with TypeScript", - "type": "text", - "url": "", - "is_flair_required": true, - "flair": { - "id": "flair-123", - "name": "Project" - } - } - }] - } - }] -} -``` - -```bash -postiz posts:create --json reddit-post.json -``` - -### YouTube Example - -**youtube-video.json:** -```json -{ - "type": "schedule", - "date": "2024-12-25T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { "id": "youtube-123" }, - "value": [{ - "content": "Full video description with timestamps...", - "image": [{ - "id": "thumb1", - "path": "https://cdn.example.com/thumbnail.jpg" - }] - }], - "settings": { - "__type": "youtube", - "title": "How to Build a CLI Tool", - "type": "public", - "selfDeclaredMadeForKids": "no", - "tags": [ - { "value": "programming", "label": "Programming" }, - { "value": "typescript", "label": "TypeScript" }, - { "value": "tutorial", "label": "Tutorial" } - ] - } - }] -} -``` - -```bash -postiz posts:create --json youtube-video.json -``` - -### Multi-Platform with Different Settings - -**multi-platform-campaign.json:** -```json -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [ - { - "integration": { "id": "reddit-123" }, - "value": [{ "content": "Reddit-specific content", "image": [] }], - "settings": { - "__type": "reddit", - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Post Title", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - } - }, - { - "integration": { "id": "twitter-123" }, - "value": [{ "content": "Twitter-specific content", "image": [] }], - "settings": { - "__type": "x", - "who_can_reply_post": "everyone" - } - }, - { - "integration": { "id": "linkedin-123" }, - "value": [ - { - "content": "LinkedIn post", - "image": [ - { "id": "1", "path": "img1.jpg" }, - { "id": "2", "path": "img2.jpg" } - ] - } - ], - "settings": { - "__type": "linkedin", - "post_as_images_carousel": true, - "carousel_name": "Product Launch" - } - } - ] -} -``` - -## Tips - -1. **Use JSON files for complex settings** - Command-line JSON strings get messy fast -2. **Validate your settings** - The API will return errors if settings are invalid -3. **Check required fields** - Each platform has different required fields -4. **Platform-specific content** - Different platforms may need different content/media -5. **Test with drafts first** - Use `"type": "draft"` to test without posting - -## Finding Your Provider Type - -To find the correct provider type for your integration: - -```bash -postiz integrations:list -``` - -This will show the `provider` field for each integration, which corresponds to the `__type` in settings. - -## Common Errors - -### Missing __type - -```json -{ - "settings": { - "title": "My Video" // ❌ Missing __type - } -} -``` - -**Fix:** -```json -{ - "settings": { - "__type": "youtube", // ✅ Add __type - "title": "My Video" - } -} -``` - -### Wrong Provider Type - -```bash -# ❌ Wrong --p twitter # Should be "x" - -# ✅ Correct --p x -``` - -### Invalid Settings for Platform - -Each platform validates its own settings. Check the error message and refer to the platform's required fields above. - -## See Also - -- **EXAMPLES.md** - General usage examples -- **COMMAND_LINE_GUIDE.md** - Command-line syntax -- **SKILL.md** - AI agent patterns -- Source DTOs in `libraries/nestjs-libraries/src/dtos/posts/providers-settings/` diff --git a/apps/cli/PROVIDER_SETTINGS_SUMMARY.md b/apps/cli/PROVIDER_SETTINGS_SUMMARY.md deleted file mode 100644 index 4b7cb48a..00000000 --- a/apps/cli/PROVIDER_SETTINGS_SUMMARY.md +++ /dev/null @@ -1,220 +0,0 @@ -# Provider-Specific Settings - Quick Reference - -## ✅ What's Supported - -The CLI now supports **platform-specific settings** for all 28+ integrations! - -## Supported Platforms - -### Platforms with Specific Settings - -| Platform | Type | Key Settings | -|----------|------|--------------| -| **Reddit** | `reddit` | subreddit, title, type, url, flair | -| **YouTube** | `youtube` | title, type (public/private/unlisted), tags, thumbnail | -| **X (Twitter)** | `x` | who_can_reply_post, community | -| **LinkedIn** | `linkedin` | post_as_images_carousel, carousel_name | -| **Instagram** | `instagram` | post_type (post/story), collaborators | -| **TikTok** | `tiktok` | title, privacy_level, duet, stitch, comment, autoAddMusic | -| **Facebook** | `facebook` | Platform-specific settings | -| **Pinterest** | `pinterest` | Platform-specific settings | -| **Discord** | `discord` | Platform-specific settings | -| **Slack** | `slack` | Platform-specific settings | -| **Medium** | `medium` | Platform-specific settings | -| **Dev.to** | `devto` | Platform-specific settings | -| **Hashnode** | `hashnode` | Platform-specific settings | -| **WordPress** | `wordpress` | Platform-specific settings | -| And 15+ more... | | See PROVIDER_SETTINGS.md | - -### Platforms with Default Settings - -These use `EmptySettings` (no special configuration needed): -- Threads, Mastodon, Bluesky, Telegram, Nostr, VK - -## Usage - -### Method 1: Command Line - -```bash -postiz posts:create \ - -c "Content" \ - -p \ - --settings '' \ - -i "integration-id" -``` - -### Method 2: JSON File - -```json -{ - "posts": [{ - "integration": { "id": "integration-id" }, - "value": [...], - "settings": { - "__type": "provider-type", - ... - } - }] -} -``` - -## Quick Examples - -### Reddit Post - -```bash -postiz posts:create \ - -c "Check out this project!" \ - -p reddit \ - --settings '{ - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "My Cool Project", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - }' \ - -i "reddit-123" -``` - -### YouTube Video - -```bash -postiz posts:create \ - -c "Full video description..." \ - -p youtube \ - --settings '{ - "title": "How to Build a CLI", - "type": "public", - "tags": [ - {"value": "tech", "label": "Tech"}, - {"value": "tutorial", "label": "Tutorial"} - ] - }' \ - -i "youtube-123" -``` - -### Twitter/X with Reply Controls - -```bash -postiz posts:create \ - -c "Important announcement!" \ - -p x \ - --settings '{ - "who_can_reply_post": "verified" - }' \ - -i "twitter-123" -``` - -### LinkedIn Carousel - -```bash -postiz posts:create \ - -c "Product showcase" \ - -m "img1.jpg,img2.jpg,img3.jpg" \ - -p linkedin \ - --settings '{ - "post_as_images_carousel": true, - "carousel_name": "Product Launch" - }' \ - -i "linkedin-123" -``` - -### Instagram Story - -```bash -postiz posts:create \ - -c "Story content" \ - -m "story-image.jpg" \ - -p instagram \ - --settings '{ - "post_type": "story" - }' \ - -i "instagram-123" -``` - -### TikTok Video - -```bash -postiz posts:create \ - -c "TikTok description #fyp" \ - -m "video.mp4" \ - -p tiktok \ - --settings '{ - "privacy_level": "PUBLIC_TO_EVERYONE", - "duet": true, - "stitch": true, - "comment": true, - "autoAddMusic": "no", - "brand_content_toggle": false, - "brand_organic_toggle": false, - "content_posting_method": "DIRECT_POST" - }' \ - -i "tiktok-123" -``` - -## JSON File Examples - -We've created example JSON files for you: - -- **`reddit-post.json`** - Reddit post with subreddit settings -- **`youtube-video.json`** - YouTube video with title, tags, thumbnail -- **`tiktok-video.json`** - TikTok video with full settings -- **`multi-platform-with-settings.json`** - Multi-platform campaign with different settings per platform - -## Finding Provider Types - -```bash -postiz integrations:list -``` - -Look at the `provider` field - this is your provider type! - -## Common Provider Types - -- `reddit` - Reddit -- `youtube` - YouTube -- `x` - X (Twitter) -- `linkedin` or `linkedin-page` - LinkedIn -- `instagram` or `instagram-standalone` - Instagram -- `tiktok` - TikTok -- `facebook` - Facebook -- `pinterest` - Pinterest -- `discord` - Discord -- `slack` - Slack -- `threads` - Threads (no specific settings) -- `bluesky` - Bluesky (no specific settings) -- `mastodon` - Mastodon (no specific settings) - -## Documentation - -📖 **[PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md)** - Complete documentation with all platform settings - -Includes: -- All available settings for each platform -- Required vs optional fields -- Validation rules -- More examples -- Common errors and solutions - -## Tips - -1. **Use JSON files for complex settings** - Easier to manage than command-line strings -2. **Different settings per platform** - Each platform in a multi-platform post can have different settings -3. **Validate before posting** - Use `"type": "draft"` to test -4. **Check examples** - See `examples/` directory for working templates -5. **Provider type matters** - Make sure `__type` matches your integration's provider - -## Summary - -✅ **28+ platforms supported** -✅ **Platform-specific settings for Reddit, YouTube, TikTok, X, LinkedIn, Instagram, and more** -✅ **Easy command-line interface** -✅ **JSON file support for complex configs** -✅ **Full type validation** -✅ **Comprehensive examples included** - -**The CLI now supports the full power of each platform!** 🚀 diff --git a/apps/cli/PUBLISHING.md b/apps/cli/PUBLISHING.md deleted file mode 100644 index 5c4d5d34..00000000 --- a/apps/cli/PUBLISHING.md +++ /dev/null @@ -1,377 +0,0 @@ -# Publishing the Postiz CLI to npm - -## Quick Publish (Current Name: "postiz") - -```bash -# From apps/cli directory -pnpm run build -pnpm publish --access public -``` - -Then users can install: -```bash -npm install -g postiz -# or -pnpm install -g postiz - -# And use: -postiz --help -``` - -## Publishing with a Different Package Name - -If you want to publish as a different npm package name (e.g., "agent-postiz"): - -### 1. Change Package Name - -Edit `apps/cli/package.json`: - -```json -{ - "name": "agent-postiz", // ← Changed package name - "version": "1.0.0", - "bin": { - "postiz": "./dist/index.js" // ← Keep command name! - } -} -``` - -**Important:** The `bin` field determines the command name, NOT the package name! - -### 2. Publish - -```bash -cd apps/cli -pnpm run build -pnpm publish --access public -``` - -### 3. Users Install - -```bash -npm install -g agent-postiz -# or -pnpm install -g agent-postiz -``` - -### 4. Users Use - -Even though the package is called "agent-postiz", the command is still: - -```bash -postiz --help # ← Command name from "bin" field -postiz posts:create -c "Hello!" -i "twitter-123" -``` - -## Package Name vs Command Name - -| Field | Purpose | Example | -|-------|---------|---------| -| `"name"` | npm package name (what you install) | `"agent-postiz"` | -| `"bin"` | Command name (what you type) | `"postiz"` | - -**Examples:** - -1. **Same name:** - ```json - "name": "postiz", - "bin": { "postiz": "./dist/index.js" } - ``` - Install: `npm i -g postiz` - Use: `postiz` - -2. **Different names:** - ```json - "name": "agent-postiz", - "bin": { "postiz": "./dist/index.js" } - ``` - Install: `npm i -g agent-postiz` - Use: `postiz` - -3. **Multiple commands:** - ```json - "name": "agent-postiz", - "bin": { - "postiz": "./dist/index.js", - "pz": "./dist/index.js" - } - ``` - Install: `npm i -g agent-postiz` - Use: `postiz` or `pz` - -## Publishing Checklist - -### Before First Publish - -- [ ] Verify package name is available on npm - ```bash - npm view postiz - # If error "404 Not Found" - name is available! - ``` - -- [ ] Update version if needed - ```json - "version": "1.0.0" - ``` - -- [ ] Review files to include - ```json - "files": [ - "dist", - "README.md", - "SKILL.md" - ] - ``` - -- [ ] Build the package - ```bash - pnpm run build - ``` - -- [ ] Test locally - ```bash - pnpm link --global - postiz --help - ``` - -### Publish to npm - -```bash -# Login to npm (first time only) -npm login - -# From apps/cli -pnpm run build -pnpm publish --access public - -# Or use the root script -cd /path/to/monorepo/root -pnpm run publish-cli -``` - -### After Publishing - -Verify it's published: -```bash -npm view postiz -# Should show your package info -``` - -Test installation: -```bash -npm install -g postiz -postiz --version -``` - -## Using from Monorepo Root - -The root `package.json` already has: - -```json -{ - "scripts": { - "publish-cli": "pnpm run --filter ./apps/cli publish" - } -} -``` - -So you can publish from the root: - -```bash -# From monorepo root -pnpm run publish-cli -``` - -## Version Updates - -### Patch Release (1.0.0 → 1.0.1) - -```bash -cd apps/cli -npm version patch -pnpm publish --access public -``` - -### Minor Release (1.0.0 → 1.1.0) - -```bash -cd apps/cli -npm version minor -pnpm publish --access public -``` - -### Major Release (1.0.0 → 2.0.0) - -```bash -cd apps/cli -npm version major -pnpm publish --access public -``` - -## Scoped Packages - -If you want to publish under an organization scope: - -```json -{ - "name": "@yourorg/postiz", - "bin": { - "postiz": "./dist/index.js" - } -} -``` - -Install: -```bash -npm install -g @yourorg/postiz -``` - -Use: -```bash -postiz --help -``` - -## Testing Before Publishing - -### Test the Build - -```bash -pnpm run build -node dist/index.js --help -``` - -### Test Linking - -```bash -pnpm link --global -postiz --help -pnpm unlink --global -``` - -### Test Publishing (Dry Run) - -```bash -npm publish --dry-run -# Shows what would be published -``` - -### Test with `npm pack` - -```bash -npm pack -# Creates a .tgz file - -# Test installing the tarball -npm install -g ./postiz-1.0.0.tgz -postiz --help -npm uninstall -g postiz -``` - -## Continuous Publishing - -### Using GitHub Actions - -Create `.github/workflows/publish-cli.yml`: - -```yaml -name: Publish CLI to npm - -on: - push: - tags: - - 'cli-v*' - -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: pnpm/action-setup@v2 - - uses: actions/setup-node@v3 - with: - node-version: '20' - registry-url: 'https://registry.npmjs.org' - - - run: pnpm install - - run: pnpm run build:cli - - - name: Publish to npm - run: pnpm --filter ./apps/cli publish --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -``` - -Then publish with: -```bash -git tag cli-v1.0.0 -git push origin cli-v1.0.0 -``` - -## Common Issues - -### "You do not have permission to publish" - -- Make sure you're logged in: `npm login` -- Check package name isn't taken: `npm view postiz` -- If scoped, ensure org access: `npm org ls yourorg` - -### "Package name too similar to existing package" - -- Choose a more unique name -- Or use a scoped package: `@yourorg/postiz` - -### "Missing required files" - -- Check `"files"` field in package.json -- Run `npm pack` to see what would be included -- Make sure `dist/` exists and is built - -### Command not found after install - -- Check `"bin"` field is correct -- Ensure `dist/index.js` has shebang: `#!/usr/bin/env node` -- Try reinstalling: `npm uninstall -g postiz && npm install -g postiz` - -## Recommended Names - -If "postiz" is taken, consider: - -- `@postiz/cli` -- `postiz-cli` -- `postiz-agent` -- `agent-postiz` -- `@yourorg/postiz` - -Remember: The package name is just for installation. The command can still be `postiz`! - -## Summary - -✅ Current setup works perfectly! -✅ `bin` field defines the command name -✅ `name` field defines the npm package name -✅ They can be different! - -**To publish now:** - -```bash -cd apps/cli -pnpm run build -pnpm publish --access public -``` - -**Users install:** - -```bash -npm install -g postiz -# or -pnpm install -g postiz -``` - -**Users use:** - -```bash -postiz --help -postiz posts:create -c "Hello!" -i "twitter-123" -``` - -🚀 **Ready to publish!** diff --git a/apps/cli/QUICK_START.md b/apps/cli/QUICK_START.md deleted file mode 100644 index b1539e2d..00000000 --- a/apps/cli/QUICK_START.md +++ /dev/null @@ -1,284 +0,0 @@ -# Postiz CLI - Quick Start Guide - -## Installation - -### From Source (Development) - -```bash -# Navigate to the monorepo root -cd /path/to/gitroom - -# Install dependencies -pnpm install - -# Build the CLI -pnpm run build:cli - -# Test locally -node apps/cli/dist/index.js --help -``` - -### Global Installation (Development) - -```bash -# From the CLI directory -cd apps/cli - -# Link globally -pnpm link --global - -# Now you can use 'postiz' anywhere -postiz --help -``` - -### From npm (Coming Soon) - -```bash -# Once published -npm install -g postiz - -# Or with pnpm -pnpm add -g postiz -``` - -## Setup - -### 1. Get Your API Key - -1. Log in to your Postiz account at https://postiz.com -2. Navigate to Settings → API Keys -3. Generate a new API key - -### 2. Set Environment Variable - -```bash -# Bash/Zsh -export POSTIZ_API_KEY=your_api_key_here - -# Fish -set -x POSTIZ_API_KEY your_api_key_here - -# PowerShell -$env:POSTIZ_API_KEY="your_api_key_here" -``` - -To make it permanent, add it to your shell profile: - -```bash -# ~/.bashrc or ~/.zshrc -echo 'export POSTIZ_API_KEY=your_api_key_here' >> ~/.bashrc -source ~/.bashrc -``` - -### 3. Verify Installation - -```bash -postiz --help -``` - -## Basic Commands - -### Create a Post - -```bash -# Simple post -postiz posts:create -c "Hello World!" -i "twitter-123" - -# Post with multiple images -postiz posts:create \ - -c "Check these out!" \ - -m "img1.jpg,img2.jpg" \ - -i "twitter-123" - -# Post with comments (each can have different media!) -postiz posts:create \ - -c "Main post" -m "main.jpg" \ - -c "First comment" -m "comment1.jpg" \ - -c "Second comment" -m "comment2.jpg" \ - -i "twitter-123" - -# Scheduled post -postiz posts:create \ - -c "Future post" \ - -s "2024-12-31T12:00:00Z" \ - -i "twitter-123" -``` - -### List Posts - -```bash -# List all posts -postiz posts:list - -# With pagination -postiz posts:list -p 2 -l 20 - -# Search -postiz posts:list -s "keyword" -``` - -### Delete a Post - -```bash -postiz posts:delete abc123xyz -``` - -### List Integrations - -```bash -postiz integrations:list -``` - -### Upload Media - -```bash -postiz upload ./path/to/image.png -``` - -## Common Workflows - -### 1. Check What's Connected - -```bash -# See all your connected social media accounts -postiz integrations:list -``` - -The output will show integration IDs like: -```json -[ - { "id": "twitter-123", "provider": "twitter" }, - { "id": "linkedin-456", "provider": "linkedin" } -] -``` - -### 2. Create Multi-Platform Post - -```bash -# Use the integration IDs from step 1 -postiz posts:create \ - -c "Posting to multiple platforms!" \ - -i "twitter-123,linkedin-456,facebook-789" -``` - -### 3. Schedule Multiple Posts - -```bash -# Morning post -postiz posts:create -c "Good morning!" -s "2024-01-15T09:00:00Z" - -# Afternoon post -postiz posts:create -c "Lunch time update!" -s "2024-01-15T12:00:00Z" - -# Evening post -postiz posts:create -c "Good night!" -s "2024-01-15T20:00:00Z" -``` - -### 4. Upload and Post Image - -```bash -# First upload the image -postiz upload ./my-image.png - -# Copy the URL from the response, then create post -postiz posts:create -c "Check out this image!" --image "url-from-upload" -``` - -## Tips & Tricks - -### Using with jq for JSON Parsing - -```bash -# Get just the post IDs -postiz posts:list | jq '.[] | .id' - -# Get integration names -postiz integrations:list | jq '.[] | .provider' -``` - -### Script Automation - -```bash -#!/bin/bash -# Create a batch of posts - -for hour in 09 12 15 18; do - postiz posts:create \ - -c "Automated post at ${hour}:00" \ - -s "2024-01-15T${hour}:00:00Z" - echo "Created post for ${hour}:00" -done -``` - -### Environment Variables - -```bash -# Custom API endpoint (for self-hosted) -export POSTIZ_API_URL=https://your-instance.com - -# Use the CLI with custom endpoint -postiz posts:list -``` - -## Troubleshooting - -### API Key Not Set - -``` -❌ Error: POSTIZ_API_KEY environment variable is required -``` - -**Solution:** Set the environment variable: -```bash -export POSTIZ_API_KEY=your_key -``` - -### Command Not Found - -``` -postiz: command not found -``` - -**Solution:** Either: -1. Use the full path: `node apps/cli/dist/index.js` -2. Link globally: `cd apps/cli && pnpm link --global` -3. Add to PATH: `export PATH=$PATH:/path/to/apps/cli/dist` - -### API Errors - -``` -❌ API Error (401): Unauthorized -``` - -**Solution:** Check your API key is valid and has proper permissions. - -``` -❌ API Error (404): Not Found -``` - -**Solution:** Verify the post ID exists when deleting. - -## Getting Help - -```bash -# General help -postiz --help - -# Command-specific help -postiz posts:create --help -postiz posts:list --help -postiz posts:delete --help -``` - -## Next Steps - -- Read the full [README.md](./README.md) for detailed documentation -- Check [SKILL.md](./SKILL.md) for AI agent integration patterns -- See [examples/](./examples/) for more usage examples - -## Links - -- [Postiz Website](https://postiz.com) -- [API Documentation](https://postiz.com/api-docs) -- [GitHub Repository](https://github.com/gitroomhq/postiz-app) -- [Report Issues](https://github.com/gitroomhq/postiz-app/issues) diff --git a/apps/cli/README.md b/apps/cli/README.md deleted file mode 100644 index 1c7983d8..00000000 --- a/apps/cli/README.md +++ /dev/null @@ -1,643 +0,0 @@ -# Postiz CLI - -**Social media automation CLI for AI agents** - Schedule posts across 28+ platforms programmatically. - -The Postiz CLI provides a command-line interface to the Postiz API, enabling developers and AI agents to automate social media posting, manage content, and handle media uploads across platforms like Twitter/X, LinkedIn, Reddit, YouTube, TikTok, Instagram, Facebook, and more. - ---- - -## Installation - -### From npm (Recommended) - -```bash -npm install -g postiz -# or -pnpm install -g postiz -``` - -### From Source - -```bash -git clone https://github.com/gitroomhq/postiz-app.git -cd postiz-app/apps/cli -pnpm install -pnpm run build -pnpm link --global -``` - -### For Development - -```bash -cd apps/cli -pnpm install -pnpm run build -pnpm link --global - -# Or run directly without linking -pnpm run start -- posts:list -``` - ---- - -## Setup - -**Required:** Set your Postiz API key - -```bash -export POSTIZ_API_KEY=your_api_key_here -``` - -**Optional:** Custom API endpoint - -```bash -export POSTIZ_API_URL=https://your-custom-api.com -``` - ---- - -## Commands - -### Discovery & Settings - -**List all connected integrations** -```bash -postiz integrations:list -``` - -Returns integration IDs, provider names, and metadata. - -**Get integration settings schema** -```bash -postiz integrations:settings -``` - -Returns character limits, required settings, and available tools for fetching dynamic data. - -**Trigger integration tools** -```bash -postiz integrations:trigger -postiz integrations:trigger -d '{"key":"value"}' -``` - -Fetch dynamic data like Reddit flairs, YouTube playlists, LinkedIn companies, etc. - -**Examples:** -```bash -# Get Reddit flairs -postiz integrations:trigger reddit-123 getFlairs -d '{"subreddit":"programming"}' - -# Get YouTube playlists -postiz integrations:trigger youtube-456 getPlaylists - -# Get LinkedIn companies -postiz integrations:trigger linkedin-789 getCompanies -``` - ---- - -### Creating Posts - -**Simple scheduled post** -```bash -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "integration-id" -``` - -**Draft post** -```bash -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -t draft -i "integration-id" -``` - -**Post with media** -```bash -postiz posts:create -c "Content" -m "img1.jpg,img2.jpg" -s "2024-12-31T12:00:00Z" -i "integration-id" -``` - -**Post with comments** (each comment can have its own media) -```bash -postiz posts:create \ - -c "Main post" -m "main.jpg" \ - -c "First comment" -m "comment1.jpg" \ - -c "Second comment" -m "comment2.jpg,comment3.jpg" \ - -s "2024-12-31T12:00:00Z" \ - -i "integration-id" -``` - -**Multi-platform post** -```bash -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "twitter-id,linkedin-id,facebook-id" -``` - -**Platform-specific settings** -```bash -postiz posts:create \ - -c "Content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"Post Title","type":"text"}}]}' \ - -i "reddit-id" -``` - -**Complex post from JSON file** -```bash -postiz posts:create --json post.json -``` - -**Options:** -- `-c, --content` - Post/comment content (use multiple times for posts with comments) -- `-s, --date` - Schedule date in ISO 8601 format (REQUIRED) -- `-t, --type` - Post type: "schedule" or "draft" (default: "schedule") -- `-m, --media` - Comma-separated media URLs for corresponding `-c` -- `-i, --integrations` - Comma-separated integration IDs (required) -- `-d, --delay` - Delay between comments in milliseconds (default: 5000) -- `--settings` - Platform-specific settings as JSON string -- `-j, --json` - Path to JSON file with full post structure -- `--shortLink` - Use short links (default: true) - ---- - -### Managing Posts - -**List posts** -```bash -postiz posts:list -postiz posts:list --startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z" -postiz posts:list --customer "customer-id" -``` - -Defaults to last 30 days to next 30 days if dates not specified. - -**Delete post** -```bash -postiz posts:delete -``` - ---- - -### Media Upload - -**Upload file and get URL** -```bash -postiz upload -``` - -**⚠️ IMPORTANT: Upload Files Before Posting** - -You **must** upload media files to Postiz before using them in posts. Many platforms (especially TikTok, Instagram, and YouTube) require verified/trusted URLs and will reject external links. - -**Workflow:** -1. Upload your file using `postiz upload` -2. Extract the returned URL -3. Use that URL in your post's `-m` parameter - -**Supported formats:** -- **Images:** PNG, JPG, JPEG, GIF, WEBP, SVG, BMP, ICO -- **Videos:** MP4, MOV, AVI, MKV, WEBM, FLV, WMV, M4V, MPEG, MPG, 3GP -- **Audio:** MP3, WAV, OGG, AAC, FLAC, M4A -- **Documents:** PDF, DOC, DOCX - -**Example:** -```bash -# 1. Upload the file first -RESULT=$(postiz upload video.mp4) -PATH=$(echo "$RESULT" | jq -r '.path') - -# 2. Use the Postiz URL in your post -postiz posts:create -c "Check out my video!" -s "2024-12-31T12:00:00Z" -m "$PATH" -i "tiktok-id" -``` - -**Why this is required:** -- **TikTok, Instagram, YouTube** only accept URLs from trusted domains -- **Security:** Platforms verify media sources to prevent abuse -- **Reliability:** Postiz ensures your media is always accessible - ---- - -## Platform-Specific Features - -### Reddit -```bash -# Get available flairs -postiz integrations:trigger reddit-id getFlairs -d '{"subreddit":"programming"}' - -# Post with subreddit and flair -postiz posts:create \ - -c "Content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Post","type":"text","is_flair_required":true,"flair":{"id":"flair-123","name":"Discussion"}}}]}' \ - -i "reddit-id" -``` - -### YouTube -```bash -# Get playlists -postiz integrations:trigger youtube-id getPlaylists - -# Upload video FIRST (required!) -VIDEO=$(postiz upload video.mp4) -VIDEO_URL=$(echo "$VIDEO" | jq -r '.path') - -# Post with uploaded video URL -postiz posts:create \ - -c "Video description" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"title":"Video Title","type":"public","tags":[{"value":"tech","label":"Tech"}],"playlistId":"playlist-id"}' \ - -m "$VIDEO_URL" \ - -i "youtube-id" -``` - -### TikTok -```bash -# Upload video FIRST (TikTok only accepts verified URLs!) -VIDEO=$(postiz upload video.mp4) -VIDEO_URL=$(echo "$VIDEO" | jq -r '.path') - -# Post with uploaded video URL -postiz posts:create \ - -c "Video caption #fyp" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"privacy":"PUBLIC_TO_EVERYONE","duet":true,"stitch":true}' \ - -m "$VIDEO_URL" \ - -i "tiktok-id" -``` - -### LinkedIn -```bash -# Get companies you can post to -postiz integrations:trigger linkedin-id getCompanies - -# Post as company -postiz posts:create \ - -c "Company announcement" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"companyId":"company-123"}' \ - -i "linkedin-id" -``` - -### X (Twitter) -```bash -# Create thread -postiz posts:create \ - -c "Thread 1/3 🧵" \ - -c "Thread 2/3" \ - -c "Thread 3/3" \ - -s "2024-12-31T12:00:00Z" \ - -d 2000 \ - -i "twitter-id" - -# With reply settings -postiz posts:create \ - -c "Tweet content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"who_can_reply_post":"everyone"}' \ - -i "twitter-id" -``` - -### Instagram -```bash -# Upload image FIRST (Instagram requires verified URLs!) -IMAGE=$(postiz upload image.jpg) -IMAGE_URL=$(echo "$IMAGE" | jq -r '.path') - -# Regular post -postiz posts:create \ - -c "Caption #hashtag" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"post_type":"post"}' \ - -m "$IMAGE_URL" \ - -i "instagram-id" - -# Story (upload first) -STORY=$(postiz upload story.jpg) -STORY_URL=$(echo "$STORY" | jq -r '.path') - -postiz posts:create \ - -c "" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"post_type":"story"}' \ - -m "$STORY_URL" \ - -i "instagram-id" -``` - -**See [PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md) for all 28+ platforms.** - ---- - -## Features for AI Agents - -### Discovery Workflow -The CLI enables dynamic discovery of integration capabilities: - -1. **List integrations** - Get available social media accounts -2. **Get settings** - Retrieve character limits, required fields, and available tools -3. **Trigger tools** - Fetch dynamic data (flairs, playlists, boards, etc.) -4. **Create posts** - Use discovered data in posts - -This allows AI agents to adapt to different platforms without hardcoded knowledge. - -### JSON Mode -For complex posts with multiple platforms and settings: - -```bash -postiz posts:create --json complex-post.json -``` - -JSON structure: -```json -{ - "integrations": ["twitter-123", "linkedin-456"], - "posts": [ - { - "provider": "twitter", - "post": [ - { - "content": "Tweet version", - "image": ["twitter-image.jpg"] - } - ] - }, - { - "provider": "linkedin", - "post": [ - { - "content": "LinkedIn version with more context...", - "image": ["linkedin-image.jpg"] - } - ], - "settings": { - "__type": "linkedin", - "companyId": "company-123" - } - } - ] -} -``` - -### All Output is JSON -Every command outputs JSON for easy parsing: - -```bash -INTEGRATIONS=$(postiz integrations:list | jq -r '.') -REDDIT_ID=$(echo "$INTEGRATIONS" | jq -r '.[] | select(.identifier=="reddit") | .id') -``` - -### Threading Support -Comments are automatically converted to threads/replies based on platform: -- **Twitter/X**: Thread of tweets -- **Reddit**: Comment replies -- **LinkedIn**: Comment on post -- **Instagram**: First comment - -```bash -postiz posts:create \ - -c "Main post" \ - -c "Comment 1" \ - -c "Comment 2" \ - -i "integration-id" -``` - ---- - -## Common Workflows - -### Reddit Post with Flair -```bash -#!/bin/bash -REDDIT_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="reddit") | .id') -FLAIRS=$(postiz integrations:trigger "$REDDIT_ID" getFlairs -d '{"subreddit":"programming"}') -FLAIR_ID=$(echo "$FLAIRS" | jq -r '.output[0].id') - -postiz posts:create \ - -c "My post content" \ - -s "2024-12-31T12:00:00Z" \ - --settings "{\"subreddit\":[{\"value\":{\"subreddit\":\"programming\",\"title\":\"Post Title\",\"type\":\"text\",\"is_flair_required\":true,\"flair\":{\"id\":\"$FLAIR_ID\",\"name\":\"Discussion\"}}}]}" \ - -i "$REDDIT_ID" -``` - -### YouTube Video Upload -```bash -#!/bin/bash -VIDEO=$(postiz upload video.mp4) -VIDEO_PATH=$(echo "$VIDEO" | jq -r '.path') - -postiz posts:create \ - -c "Video description..." \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"title":"My Video","type":"public","tags":[{"value":"tech","label":"Tech"}]}' \ - -m "$VIDEO_PATH" \ - -i "youtube-id" -``` - -### Multi-Platform Campaign -```bash -#!/bin/bash -postiz posts:create \ - -c "Same content everywhere" \ - -s "2024-12-31T12:00:00Z" \ - -m "image.jpg" \ - -i "twitter-id,linkedin-id,facebook-id" -``` - -### Batch Scheduling -```bash -#!/bin/bash -DATES=("2024-02-14T09:00:00Z" "2024-02-15T09:00:00Z" "2024-02-16T09:00:00Z") -CONTENT=("Monday motivation 💪" "Tuesday tips 💡" "Wednesday wisdom 🧠") - -for i in "${!DATES[@]}"; do - postiz posts:create \ - -c "${CONTENT[$i]}" \ - -s "${DATES[$i]}" \ - -i "twitter-id" -done -``` - ---- - -## Documentation - -**For AI Agents:** -- **[SKILL.md](./SKILL.md)** - Complete skill reference with patterns and examples - -**Deep-Dive Guides:** -- **[HOW_TO_RUN.md](./HOW_TO_RUN.md)** - Installation and setup methods -- **[COMMAND_LINE_GUIDE.md](./COMMAND_LINE_GUIDE.md)** - Complete command syntax reference -- **[PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md)** - All platform settings schemas -- **[INTEGRATION_TOOLS_WORKFLOW.md](./INTEGRATION_TOOLS_WORKFLOW.md)** - Tools workflow guide -- **[INTEGRATION_SETTINGS_DISCOVERY.md](./INTEGRATION_SETTINGS_DISCOVERY.md)** - Settings discovery -- **[SUPPORTED_FILE_TYPES.md](./SUPPORTED_FILE_TYPES.md)** - Media format reference -- **[PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md)** - Code architecture -- **[PUBLISHING.md](./PUBLISHING.md)** - npm publishing guide - -**Examples:** -- **[examples/EXAMPLES.md](./examples/EXAMPLES.md)** - Comprehensive examples -- **[examples/](./examples/)** - Ready-to-use scripts and JSON files - ---- - -## API Endpoints - -The CLI interacts with these Postiz API endpoints: - -| Endpoint | Method | Purpose | -|----------|--------|---------| -| `/public/v1/posts` | POST | Create a post | -| `/public/v1/posts` | GET | List posts | -| `/public/v1/posts/:id` | DELETE | Delete a post | -| `/public/v1/integrations` | GET | List integrations | -| `/public/v1/integration-settings/:id` | GET | Get integration settings | -| `/public/v1/integration-trigger/:id` | POST | Trigger integration tool | -| `/public/v1/upload` | POST | Upload media | - ---- - -## Environment Variables - -| Variable | Required | Default | Description | -|----------|----------|---------|-------------| -| `POSTIZ_API_KEY` | ✅ Yes | - | Your Postiz API key | -| `POSTIZ_API_URL` | No | `https://api.postiz.com` | Custom API endpoint | - ---- - -## Error Handling - -The CLI provides clear error messages with exit codes: - -- **Exit code 0**: Success -- **Exit code 1**: Error occurred - -**Common errors:** - -| Error | Solution | -|-------|----------| -| `POSTIZ_API_KEY is not set` | Set environment variable: `export POSTIZ_API_KEY=key` | -| `Integration not found` | Run `integrations:list` to get valid IDs | -| `startDate/endDate required` | Use ISO 8601 format: `"2024-12-31T12:00:00Z"` | -| `Invalid settings` | Check `integrations:settings` for required fields | -| `Tool not found` | Check available tools in `integrations:settings` output | -| `Upload failed` | Verify file exists and format is supported | - ---- - -## Development - -### Project Structure - -``` -apps/cli/ -├── src/ -│ ├── index.ts # CLI entry point with yargs -│ ├── api.ts # PostizAPI client class -│ ├── config.ts # Environment configuration -│ └── commands/ -│ ├── posts.ts # Post management commands -│ ├── integrations.ts # Integration commands -│ └── upload.ts # Media upload command -├── examples/ # Example scripts and JSON files -├── package.json -├── tsconfig.json -├── tsup.config.ts # Build configuration -├── README.md # This file -└── SKILL.md # AI agent reference -``` - -### Scripts - -```bash -pnpm run dev # Watch mode for development -pnpm run build # Build the CLI -pnpm run start # Run the built CLI -``` - -### Building - -The CLI uses `tsup` for bundling: - -```bash -pnpm run build -``` - -Output in `dist/`: -- `index.js` - Bundled executable with shebang -- `index.js.map` - Source map - ---- - -## Quick Reference - -```bash -# Environment setup -export POSTIZ_API_KEY=your_key - -# Discovery -postiz integrations:list # List integrations -postiz integrations:settings # Get settings -postiz integrations:trigger -d '{}' # Fetch data - -# Posting (date is required) -postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -i "id" # Simple -postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -t draft -i "id" # Draft -postiz posts:create -c "text" -m "img.jpg" -s "2024-12-31T12:00:00Z" -i "id" # With media -postiz posts:create -c "main" -c "comment" -s "2024-12-31T12:00:00Z" -i "id" # With comment -postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" --settings '{}' -i "id" # Platform-specific -postiz posts:create --json file.json # Complex - -# Management -postiz posts:list # List posts -postiz posts:delete # Delete post -postiz upload # Upload media - -# Help -postiz --help # Show help -postiz posts:create --help # Command help -``` - ---- - -## Contributing - -This CLI is part of the [Postiz monorepo](https://github.com/gitroomhq/postiz-app). - -To contribute: -1. Fork the repository -2. Create a feature branch -3. Make your changes in `apps/cli/` -4. Run tests: `pnpm run build` -5. Submit a pull request - ---- - -## License - -AGPL-3.0 - ---- - -## Links - -- **Website:** [postiz.com](https://postiz.com) -- **API Docs:** [postiz.com/api-docs](https://postiz.com/api-docs) -- **GitHub:** [gitroomhq/postiz-app](https://github.com/gitroomhq/postiz-app) -- **Issues:** [Report bugs](https://github.com/gitroomhq/postiz-app/issues) - ---- - -## Supported Platforms - -28+ platforms including: - -| Platform | Integration Tools | Settings | -|----------|------------------|----------| -| Twitter/X | getLists, getCommunities | who_can_reply_post | -| LinkedIn | getCompanies | companyId, carousel | -| Reddit | getFlairs, searchSubreddits | subreddit, title, flair | -| YouTube | getPlaylists, getCategories | title, type, tags, playlistId | -| TikTok | - | privacy, duet, stitch | -| Instagram | - | post_type (post/story) | -| Facebook | getPages | - | -| Pinterest | getBoards, getBoardSections | - | -| Discord | getChannels | - | -| Slack | getChannels | - | -| And 18+ more... | | | - -**See [PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md) for complete documentation.** diff --git a/apps/cli/SKILL.md b/apps/cli/SKILL.md deleted file mode 100644 index fea39a91..00000000 --- a/apps/cli/SKILL.md +++ /dev/null @@ -1,607 +0,0 @@ -| Property | Value | -|----------|-------| -| **name** | postiz | -| **description** | Social media automation CLI for scheduling posts across 28+ platforms | -| **allowed-tools** | Bash(postiz:*) | - ---- - -## Core Workflow - -The fundamental pattern for using Postiz CLI: - -1. **Discover** - List integrations and get their settings -2. **Fetch** - Use integration tools to retrieve dynamic data (flairs, playlists, companies) -3. **Prepare** - Upload media files if needed -4. **Post** - Create posts with content, media, and platform-specific settings - -```bash -# 1. Discover -postiz integrations:list -postiz integrations:settings - -# 2. Fetch (if needed) -postiz integrations:trigger -d '{"key":"value"}' - -# 3. Prepare -postiz upload image.jpg - -# 4. Post -postiz posts:create -c "Content" -m "image.jpg" -i "" -``` - ---- - -## Essential Commands - -### Setup - -```bash -# Required environment variable -export POSTIZ_API_KEY=your_api_key_here - -# Optional custom API URL -export POSTIZ_API_URL=https://custom-api-url.com -``` - -### Integration Discovery - -```bash -# List all connected integrations -postiz integrations:list - -# Get settings schema for specific integration -postiz integrations:settings - -# Trigger integration tool to fetch dynamic data -postiz integrations:trigger -postiz integrations:trigger -d '{"param":"value"}' -``` - -### Creating Posts - -```bash -# Simple post (date is REQUIRED) -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "integration-id" - -# Draft post -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -t draft -i "integration-id" - -# Post with media -postiz posts:create -c "Content" -m "img1.jpg,img2.jpg" -s "2024-12-31T12:00:00Z" -i "integration-id" - -# Post with comments (each with own media) -postiz posts:create \ - -c "Main post" -m "main.jpg" \ - -c "First comment" -m "comment1.jpg" \ - -c "Second comment" -m "comment2.jpg,comment3.jpg" \ - -s "2024-12-31T12:00:00Z" \ - -i "integration-id" - -# Multi-platform post -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "twitter-id,linkedin-id,facebook-id" - -# Platform-specific settings -postiz posts:create \ - -c "Content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Post","type":"text"}}]}' \ - -i "reddit-id" - -# Complex post from JSON file -postiz posts:create --json post.json -``` - -### Managing Posts - -```bash -# List posts (defaults to last 30 days to next 30 days) -postiz posts:list - -# List posts in date range -postiz posts:list --startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z" - -# Delete post -postiz posts:delete -``` - -### Media Upload - -**⚠️ IMPORTANT:** Always upload files to Postiz before using them in posts. Many platforms (TikTok, Instagram, YouTube) **require verified URLs** and will reject external links. - -```bash -# Upload file and get URL -postiz upload image.jpg - -# Supports: images (PNG, JPG, GIF, WEBP, SVG), videos (MP4, MOV, AVI, MKV, WEBM), -# audio (MP3, WAV, OGG, AAC), documents (PDF, DOC, DOCX) - -# Workflow: Upload → Extract URL → Use in post -VIDEO=$(postiz upload video.mp4) -VIDEO_PATH=$(echo "$VIDEO" | jq -r '.path') -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -m "$VIDEO_PATH" -i "tiktok-id" -``` - ---- - -## Common Patterns - -### Pattern 1: Discover & Use Integration Tools - -**Reddit - Get flairs for a subreddit:** -```bash -# Get Reddit integration ID -REDDIT_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="reddit") | .id') - -# Fetch available flairs -FLAIRS=$(postiz integrations:trigger "$REDDIT_ID" getFlairs -d '{"subreddit":"programming"}') -FLAIR_ID=$(echo "$FLAIRS" | jq -r '.output[0].id') - -# Use in post -postiz posts:create \ - -c "My post content" \ - -s "2024-12-31T12:00:00Z" \ - --settings "{\"subreddit\":[{\"value\":{\"subreddit\":\"programming\",\"title\":\"Post Title\",\"type\":\"text\",\"is_flair_required\":true,\"flair\":{\"id\":\"$FLAIR_ID\",\"name\":\"Discussion\"}}}]}" \ - -i "$REDDIT_ID" -``` - -**YouTube - Get playlists:** -```bash -YOUTUBE_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="youtube") | .id') -PLAYLISTS=$(postiz integrations:trigger "$YOUTUBE_ID" getPlaylists) -PLAYLIST_ID=$(echo "$PLAYLISTS" | jq -r '.output[0].id') - -postiz posts:create \ - -c "Video description" \ - -s "2024-12-31T12:00:00Z" \ - --settings "{\"title\":\"My Video\",\"type\":\"public\",\"playlistId\":\"$PLAYLIST_ID\"}" \ - -m "video.mp4" \ - -i "$YOUTUBE_ID" -``` - -**LinkedIn - Post as company:** -```bash -LINKEDIN_ID=$(postiz integrations:list | jq -r '.[] | select(.identifier=="linkedin") | .id') -COMPANIES=$(postiz integrations:trigger "$LINKEDIN_ID" getCompanies) -COMPANY_ID=$(echo "$COMPANIES" | jq -r '.output[0].id') - -postiz posts:create \ - -c "Company announcement" \ - -s "2024-12-31T12:00:00Z" \ - --settings "{\"companyId\":\"$COMPANY_ID\"}" \ - -i "$LINKEDIN_ID" -``` - -### Pattern 2: Upload Media Before Posting - -```bash -# Upload multiple files -VIDEO_RESULT=$(postiz upload video.mp4) -VIDEO_PATH=$(echo "$VIDEO_RESULT" | jq -r '.path') - -THUMB_RESULT=$(postiz upload thumbnail.jpg) -THUMB_PATH=$(echo "$THUMB_RESULT" | jq -r '.path') - -# Use in post -postiz posts:create \ - -c "Check out my video!" \ - -s "2024-12-31T12:00:00Z" \ - -m "$VIDEO_PATH" \ - -i "tiktok-id" -``` - -### Pattern 3: Twitter Thread - -```bash -postiz posts:create \ - -c "🧵 Thread starter (1/4)" -m "intro.jpg" \ - -c "Point one (2/4)" -m "point1.jpg" \ - -c "Point two (3/4)" -m "point2.jpg" \ - -c "Conclusion (4/4)" -m "outro.jpg" \ - -s "2024-12-31T12:00:00Z" \ - -d 2000 \ - -i "twitter-id" -``` - -### Pattern 4: Multi-Platform Campaign - -```bash -# Create JSON file with platform-specific content -cat > campaign.json << 'EOF' -{ - "integrations": ["twitter-123", "linkedin-456", "facebook-789"], - "posts": [ - { - "provider": "twitter", - "post": [ - { - "content": "Short tweet version #tech", - "image": ["twitter-image.jpg"] - } - ] - }, - { - "provider": "linkedin", - "post": [ - { - "content": "Professional LinkedIn version with more context...", - "image": ["linkedin-image.jpg"] - } - ] - } - ] -} -EOF - -postiz posts:create --json campaign.json -``` - -### Pattern 5: Validate Settings Before Posting - -```javascript -const { execSync } = require('child_process'); - -function validateAndPost(content, integrationId, settings) { - // Get integration settings - const settingsResult = execSync( - `postiz integrations:settings ${integrationId}`, - { encoding: 'utf-8' } - ); - const schema = JSON.parse(settingsResult); - - // Check character limit - if (content.length > schema.output.maxLength) { - console.warn(`Content exceeds ${schema.output.maxLength} chars, truncating...`); - content = content.substring(0, schema.output.maxLength - 3) + '...'; - } - - // Create post - const result = execSync( - `postiz posts:create -c "${content}" -s "2024-12-31T12:00:00Z" --settings '${JSON.stringify(settings)}' -i "${integrationId}"`, - { encoding: 'utf-8' } - ); - - return JSON.parse(result); -} -``` - -### Pattern 6: Batch Scheduling - -```bash -#!/bin/bash - -# Schedule posts for the week -DATES=( - "2024-02-14T09:00:00Z" - "2024-02-15T09:00:00Z" - "2024-02-16T09:00:00Z" -) - -CONTENT=( - "Monday motivation 💪" - "Tuesday tips 💡" - "Wednesday wisdom 🧠" -) - -for i in "${!DATES[@]}"; do - postiz posts:create \ - -c "${CONTENT[$i]}" \ - -s "${DATES[$i]}" \ - -i "twitter-id" \ - -m "post-${i}.jpg" - echo "Scheduled: ${CONTENT[$i]} for ${DATES[$i]}" -done -``` - -### Pattern 7: Error Handling & Retry - -```javascript -const { execSync } = require('child_process'); - -async function postWithRetry(content, integrationId, date, maxRetries = 3) { - for (let attempt = 1; attempt <= maxRetries; attempt++) { - try { - const result = execSync( - `postiz posts:create -c "${content}" -s "${date}" -i "${integrationId}"`, - { encoding: 'utf-8', stdio: 'pipe' } - ); - console.log('✅ Post created successfully'); - return JSON.parse(result); - } catch (error) { - console.error(`❌ Attempt ${attempt} failed: ${error.message}`); - - if (attempt < maxRetries) { - const delay = Math.pow(2, attempt) * 1000; // Exponential backoff - console.log(`⏳ Retrying in ${delay}ms...`); - await new Promise(resolve => setTimeout(resolve, delay)); - } else { - throw new Error(`Failed after ${maxRetries} attempts`); - } - } - } -} -``` - ---- - -## Technical Concepts - -### Integration Tools Workflow - -Many integrations require dynamic data (IDs, tags, playlists) that can't be hardcoded. The tools workflow enables discovery and usage: - -1. **Check available tools** - `integrations:settings` returns a `tools` array -2. **Review tool schema** - Each tool has `methodName`, `description`, and `dataSchema` -3. **Trigger tool** - Call `integrations:trigger` with required parameters -4. **Use output** - Tool returns data to use in post settings - -**Example tools by platform:** -- **Reddit**: `getFlairs`, `searchSubreddits`, `getSubreddits` -- **YouTube**: `getPlaylists`, `getCategories`, `getChannels` -- **LinkedIn**: `getCompanies`, `getOrganizations` -- **Twitter/X**: `getListsowned`, `getCommunities` -- **Pinterest**: `getBoards`, `getBoardSections` - -### Provider Settings Structure - -Platform-specific settings use a discriminator pattern with `__type` field: - -```json -{ - "posts": [ - { - "provider": "reddit", - "post": [{ "content": "...", "image": [...] }], - "settings": { - "__type": "reddit", - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Post Title", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - } - } - ] -} -``` - -Pass settings directly: -```bash -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" --settings '{"subreddit":[...]}' -i "reddit-id" -# Backend automatically adds "__type" based on integration ID -``` - -### Comments and Threading - -Posts can have comments (threads on Twitter/X, replies elsewhere). Each comment can have its own media: - -```bash -# Using multiple -c and -m flags -postiz posts:create \ - -c "Main post" -m "image1.jpg,image2.jpg" \ - -c "Comment 1" -m "comment-img.jpg" \ - -c "Comment 2" -m "another.jpg,more.jpg" \ - -s "2024-12-31T12:00:00Z" \ - -d 5000 \ # Delay between comments in ms - -i "integration-id" -``` - -Internally creates: -```json -{ - "posts": [{ - "value": [ - { "content": "Main post", "image": ["image1.jpg", "image2.jpg"] }, - { "content": "Comment 1", "image": ["comment-img.jpg"], "delay": 5000 }, - { "content": "Comment 2", "image": ["another.jpg", "more.jpg"], "delay": 5000 } - ] - }] -} -``` - -### Date Handling - -All dates use ISO 8601 format: -- Schedule posts: `-s "2024-12-31T12:00:00Z"` -- List posts: `--startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z"` -- Defaults: `posts:list` uses 30 days ago to 30 days from now - -### Media Upload Response - -Upload returns JSON with path and metadata: -```json -{ - "path": "https://cdn.postiz.com/uploads/abc123.jpg", - "size": 123456, - "type": "image/jpeg" -} -``` - -Extract path for use in posts: -```bash -RESULT=$(postiz upload image.jpg) -PATH=$(echo "$RESULT" | jq -r '.path') -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -m "$PATH" -i "integration-id" -``` - -### JSON Mode vs CLI Flags - -**CLI flags** - Quick posts: -```bash -postiz posts:create -c "Content" -m "img.jpg" -i "twitter-id" -``` - -**JSON mode** - Complex posts with multiple platforms and settings: -```bash -postiz posts:create --json post.json -``` - -JSON mode supports: -- Multiple platforms with different content per platform -- Complex provider-specific settings -- Scheduled posts -- Posts with many comments -- Custom delay between comments - ---- - -## Platform-Specific Examples - -### Reddit -```bash -postiz posts:create \ - -c "Post content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"subreddit":[{"value":{"subreddit":"programming","title":"My Title","type":"text","url":"","is_flair_required":false}}]}' \ - -i "reddit-id" -``` - -### YouTube -```bash -# Upload video first (required!) -VIDEO=$(postiz upload video.mp4) -VIDEO_URL=$(echo "$VIDEO" | jq -r '.path') - -postiz posts:create \ - -c "Video description" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"title":"Video Title","type":"public","tags":[{"value":"tech","label":"Tech"}]}' \ - -m "$VIDEO_URL" \ - -i "youtube-id" -``` - -### TikTok -```bash -# Upload video first (TikTok only accepts verified URLs!) -VIDEO=$(postiz upload video.mp4) -VIDEO_URL=$(echo "$VIDEO" | jq -r '.path') - -postiz posts:create \ - -c "Video caption #fyp" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"privacy":"PUBLIC_TO_EVERYONE","duet":true,"stitch":true}' \ - -m "$VIDEO_URL" \ - -i "tiktok-id" -``` - -### X (Twitter) -```bash -postiz posts:create \ - -c "Tweet content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"who_can_reply_post":"everyone"}' \ - -i "twitter-id" -``` - -### LinkedIn -```bash -# Personal post -postiz posts:create -c "Content" -s "2024-12-31T12:00:00Z" -i "linkedin-id" - -# Company post -postiz posts:create \ - -c "Content" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"companyId":"company-123"}' \ - -i "linkedin-id" -``` - -### Instagram -```bash -# Upload image first (Instagram requires verified URLs!) -IMAGE=$(postiz upload image.jpg) -IMAGE_URL=$(echo "$IMAGE" | jq -r '.path') - -# Regular post -postiz posts:create \ - -c "Caption #hashtag" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"post_type":"post"}' \ - -m "$IMAGE_URL" \ - -i "instagram-id" - -# Story -STORY=$(postiz upload story.jpg) -STORY_URL=$(echo "$STORY" | jq -r '.path') - -postiz posts:create \ - -c "" \ - -s "2024-12-31T12:00:00Z" \ - --settings '{"post_type":"story"}' \ - -m "$STORY_URL" \ - -i "instagram-id" -``` - ---- - -## Supporting Resources - -**Deep-dive documentation:** -- [HOW_TO_RUN.md](./HOW_TO_RUN.md) - Installation and setup methods -- [COMMAND_LINE_GUIDE.md](./COMMAND_LINE_GUIDE.md) - Complete command syntax reference -- [PROVIDER_SETTINGS.md](./PROVIDER_SETTINGS.md) - All 28+ platform settings schemas -- [INTEGRATION_TOOLS_WORKFLOW.md](./INTEGRATION_TOOLS_WORKFLOW.md) - Complete tools workflow guide -- [INTEGRATION_SETTINGS_DISCOVERY.md](./INTEGRATION_SETTINGS_DISCOVERY.md) - Settings discovery workflow -- [SUPPORTED_FILE_TYPES.md](./SUPPORTED_FILE_TYPES.md) - All supported media formats -- [PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md) - Code architecture -- [PUBLISHING.md](./PUBLISHING.md) - npm publishing guide - -**Ready-to-use examples:** -- [examples/EXAMPLES.md](./examples/EXAMPLES.md) - Comprehensive examples -- [examples/basic-usage.sh](./examples/basic-usage.sh) - Shell script basics -- [examples/ai-agent-example.js](./examples/ai-agent-example.js) - Node.js agent -- [examples/post-with-comments.json](./examples/post-with-comments.json) - Threading example -- [examples/multi-platform-with-settings.json](./examples/multi-platform-with-settings.json) - Campaign example -- [examples/youtube-video.json](./examples/youtube-video.json) - YouTube with tags -- [examples/reddit-post.json](./examples/reddit-post.json) - Reddit with subreddit -- [examples/tiktok-video.json](./examples/tiktok-video.json) - TikTok with privacy - ---- - -## Common Gotchas - -1. **API Key not set** - Always `export POSTIZ_API_KEY=key` before using CLI -2. **Invalid integration ID** - Run `integrations:list` to get current IDs -3. **Settings schema mismatch** - Check `integrations:settings` for required fields -4. **Media MUST be uploaded to Postiz first** - ⚠️ **CRITICAL:** TikTok, Instagram, YouTube, and many platforms only accept verified URLs. Upload files via `postiz upload` first, then use the returned URL in `-m`. External URLs will be rejected! -5. **JSON escaping in shell** - Use single quotes for JSON: `--settings '{...}'` -6. **Date format** - Must be ISO 8601: `"2024-12-31T12:00:00Z"` and is REQUIRED -7. **Tool not found** - Check available tools in `integrations:settings` output -8. **Character limits** - Each platform has different limits, check `maxLength` in settings -9. **Required settings** - Some platforms require specific settings (Reddit needs title, YouTube needs title) -10. **Media MIME types** - CLI auto-detects from file extension, ensure correct extension - ---- - -## Quick Reference - -```bash -# Environment -export POSTIZ_API_KEY=key - -# Discovery -postiz integrations:list # Get integration IDs -postiz integrations:settings # Get settings schema -postiz integrations:trigger -d '{}' # Fetch dynamic data - -# Posting (date is REQUIRED) -postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -i "id" # Simple -postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" -t draft -i "id" # Draft -postiz posts:create -c "text" -m "img.jpg" -s "2024-12-31T12:00:00Z" -i "id" # With media -postiz posts:create -c "main" -c "comment" -s "2024-12-31T12:00:00Z" -i "id" # With comment -postiz posts:create -c "text" -s "2024-12-31T12:00:00Z" --settings '{}' -i "id" # Platform-specific -postiz posts:create --json file.json # Complex - -# Management -postiz posts:list # List posts -postiz posts:delete # Delete post -postiz upload # Upload media - -# Help -postiz --help # Show help -postiz posts:create --help # Command help -``` diff --git a/apps/cli/SUMMARY.md b/apps/cli/SUMMARY.md deleted file mode 100644 index aeac2c09..00000000 --- a/apps/cli/SUMMARY.md +++ /dev/null @@ -1,281 +0,0 @@ -# Postiz CLI - Creation Summary - -## ✅ What Was Created - -A complete, production-ready CLI package for the Postiz API has been successfully created at `apps/cli/`. - -### Package Details - -- **Package Name:** `postiz` -- **Version:** 1.0.0 -- **Executable:** `postiz` command -- **Lines of Code:** 359 lines -- **Build Size:** ~491KB (compressed) -- **License:** AGPL-3.0 - -## 📦 Package Structure - -``` -apps/cli/ -├── src/ # Source code (359 lines) -│ ├── index.ts # CLI entry point with yargs -│ ├── api.ts # Postiz API client -│ ├── config.ts # Environment configuration -│ └── commands/ -│ ├── posts.ts # Post management -│ ├── integrations.ts # Integration listing -│ └── upload.ts # Media upload -│ -├── examples/ # Usage examples -│ ├── basic-usage.sh # Bash example -│ └── ai-agent-example.js # AI agent example -│ -├── Documentation (5 files) -│ ├── README.md # Main documentation -│ ├── SKILL.md # AI agent guide -│ ├── QUICK_START.md # Quick start guide -│ ├── CHANGELOG.md # Version history -│ └── PROJECT_STRUCTURE.md # Architecture docs -│ -└── Configuration - ├── package.json # Package config - ├── tsconfig.json # TypeScript config - ├── tsup.config.ts # Build config - ├── .gitignore # Git ignore - └── .npmignore # npm ignore -``` - -## 🚀 Features Implemented - -### Commands - -1. **posts:create** - Create social media posts - - ✅ Content input - - ✅ Integration selection - - ✅ Scheduled posting - - ✅ Image attachment - -2. **posts:list** - List all posts - - ✅ Pagination support - - ✅ Search functionality - - ✅ Filtering options - -3. **posts:delete** - Delete posts by ID - - ✅ ID-based deletion - - ✅ Confirmation messages - -4. **integrations:list** - Show connected accounts - - ✅ List all integrations - - ✅ Show provider info - -5. **upload** - Upload media files - - ✅ Image upload support - - ✅ Multiple formats (PNG, JPG, GIF) - -### Technical Features - -- ✅ Environment variable configuration (POSTIZ_API_KEY) -- ✅ Custom API URL support (POSTIZ_API_URL) -- ✅ Comprehensive error handling -- ✅ User-friendly error messages with emojis -- ✅ JSON output for programmatic parsing -- ✅ Executable shebang for direct execution -- ✅ TypeScript with proper types -- ✅ Source maps for debugging -- ✅ Build optimization with tsup - -## 📚 Documentation Created - -1. **README.md** (Primary documentation) - - Installation instructions - - Usage examples - - API reference - - Development guide - -2. **SKILL.md** (AI Agent Guide) - - Comprehensive patterns for AI agents - - Usage examples - - Workflow suggestions - - Best practices - - Error handling - -3. **QUICK_START.md** - - Fast onboarding - - Common workflows - - Troubleshooting - - Tips & tricks - -4. **CHANGELOG.md** - - Version 1.0.0 release notes - - Feature list - -5. **PROJECT_STRUCTURE.md** - - Architecture overview - - File descriptions - - Build process - - Integration points - -## 🔧 Build System Integration - -### Root package.json Scripts Added - -```json -{ - "build:cli": "rm -rf apps/cli/dist && pnpm --filter ./apps/cli run build", - "publish-cli": "pnpm run --filter ./apps/cli publish" -} -``` - -### CLI Package Scripts - -```json -{ - "dev": "tsup --watch", - "build": "tsup", - "start": "node ./dist/index.js", - "publish": "tsup && pnpm publish --access public" -} -``` - -## 🎯 Usage Examples - -### Basic Usage - -```bash -# Set API key -export POSTIZ_API_KEY=your_api_key - -# Create a post -postiz posts:create -c "Hello World!" -i "twitter-123" - -# List posts -postiz posts:list - -# Upload media -postiz upload ./image.png -``` - -### AI Agent Usage - -```javascript -const { execSync } = require('child_process'); - -function postToSocial(content) { - return execSync(`postiz posts:create -c "${content}"`, { - env: { ...process.env, POSTIZ_API_KEY: 'your_key' } - }); -} -``` - -## ✨ Example Files - -1. **basic-usage.sh** - - Shell script demonstration - - Complete workflow example - - Error handling - -2. **ai-agent-example.js** - - Node.js agent implementation - - Batch post creation - - JSON parsing - -## 🧪 Testing - -### Manual Testing Completed - -```bash -✅ Build successful (173ms) -✅ Help command works -✅ Version command works (1.0.0) -✅ Error handling works (API key validation) -✅ All commands have help text -✅ Examples are valid -``` - -### Test Results - -``` -✅ pnpm run build:cli - SUCCESS -✅ postiz --help - SUCCESS -✅ postiz --version - SUCCESS -✅ postiz posts:create --help - SUCCESS -✅ Error without API key - WORKS AS EXPECTED -``` - -## 📋 Checklist - -- ✅ CLI package created in apps/cli -- ✅ Package name is "postiz" -- ✅ Uses POSTIZ_API_KEY environment variable -- ✅ Integrates with Postiz public API -- ✅ Built for AI agent usage -- ✅ SKILL.md created with comprehensive guide -- ✅ README.md with full documentation -- ✅ Build system configured -- ✅ TypeScript compilation working -- ✅ Executable binary generated -- ✅ Examples provided -- ✅ Error handling implemented -- ✅ Help documentation complete - -## 🚦 Next Steps - -### To Use Locally - -```bash -# Build the CLI -pnpm run build:cli - -# Test it -node apps/cli/dist/index.js --help - -# Link globally (optional) -cd apps/cli -pnpm link --global - -# Use anywhere -postiz --help -``` - -### To Publish to npm - -```bash -# From monorepo root -pnpm run publish-cli - -# Or from apps/cli -cd apps/cli -pnpm run publish -``` - -### To Use in AI Agents - -1. Install: `npm install -g postiz` -2. Set API key: `export POSTIZ_API_KEY=your_key` -3. Use commands programmatically -4. Parse JSON output -5. See SKILL.md for patterns - -## 📊 Statistics - -- **Total Files Created:** 18 -- **Source Code Files:** 6 -- **Documentation Files:** 5 -- **Example Files:** 2 -- **Config Files:** 5 -- **Total Lines of Code:** 359 -- **Build Time:** ~170ms -- **Output Size:** 491KB - -## 🎉 Summary - -A complete, production-ready CLI tool for Postiz has been created with: - -- ✅ All requested features implemented -- ✅ Comprehensive documentation for users and AI agents -- ✅ Working examples -- ✅ Proper build system -- ✅ Ready for npm publishing -- ✅ Integrated into monorepo - -The CLI is ready to use and can be published to npm whenever you're ready! diff --git a/apps/cli/SUPPORTED_FILE_TYPES.md b/apps/cli/SUPPORTED_FILE_TYPES.md deleted file mode 100644 index e0610013..00000000 --- a/apps/cli/SUPPORTED_FILE_TYPES.md +++ /dev/null @@ -1,305 +0,0 @@ -# Supported File Types for Upload - -The Postiz CLI now correctly detects and uploads various media types. - -## How It Works - -The CLI automatically detects the MIME type based on the file extension: - -```bash -postiz upload video.mp4 -# ✅ Detected as: video/mp4 - -postiz upload image.png -# ✅ Detected as: image/png - -postiz upload audio.mp3 -# ✅ Detected as: audio/mpeg -``` - -## Supported File Types - -### Images - -| Extension | MIME Type | Supported | -|-----------|-----------|-----------| -| `.png` | `image/png` | ✅ Yes | -| `.jpg`, `.jpeg` | `image/jpeg` | ✅ Yes | -| `.gif` | `image/gif` | ✅ Yes | -| `.webp` | `image/webp` | ✅ Yes | -| `.svg` | `image/svg+xml` | ✅ Yes | -| `.bmp` | `image/bmp` | ✅ Yes | -| `.ico` | `image/x-icon` | ✅ Yes | - -**Examples:** -```bash -postiz upload photo.jpg -postiz upload logo.png -postiz upload animation.gif -postiz upload icon.svg -``` - -### Videos - -| Extension | MIME Type | Supported | -|-----------|-----------|-----------| -| `.mp4` | `video/mp4` | ✅ Yes | -| `.mov` | `video/quicktime` | ✅ Yes | -| `.avi` | `video/x-msvideo` | ✅ Yes | -| `.mkv` | `video/x-matroska` | ✅ Yes | -| `.webm` | `video/webm` | ✅ Yes | -| `.flv` | `video/x-flv` | ✅ Yes | -| `.wmv` | `video/x-ms-wmv` | ✅ Yes | -| `.m4v` | `video/x-m4v` | ✅ Yes | -| `.mpeg`, `.mpg` | `video/mpeg` | ✅ Yes | -| `.3gp` | `video/3gpp` | ✅ Yes | - -**Examples:** -```bash -postiz upload video.mp4 -postiz upload clip.mov -postiz upload recording.webm -postiz upload movie.mkv -``` - -### Audio - -| Extension | MIME Type | Supported | -|-----------|-----------|-----------| -| `.mp3` | `audio/mpeg` | ✅ Yes | -| `.wav` | `audio/wav` | ✅ Yes | -| `.ogg` | `audio/ogg` | ✅ Yes | -| `.aac` | `audio/aac` | ✅ Yes | -| `.flac` | `audio/flac` | ✅ Yes | -| `.m4a` | `audio/mp4` | ✅ Yes | - -**Examples:** -```bash -postiz upload podcast.mp3 -postiz upload song.wav -postiz upload audio.ogg -``` - -### Documents - -| Extension | MIME Type | Supported | -|-----------|-----------|-----------| -| `.pdf` | `application/pdf` | ✅ Yes | -| `.doc` | `application/msword` | ✅ Yes | -| `.docx` | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` | ✅ Yes | - -**Examples:** -```bash -postiz upload document.pdf -postiz upload report.docx -``` - -### Other Files - -For file types not listed above, the CLI uses: -- MIME type: `application/octet-stream` -- This is a generic binary file type - -## Usage Examples - -### Upload an Image - -```bash -postiz upload ./images/photo.jpg -``` - -Response: -```json -{ - "id": "upload-123", - "path": "https://cdn.postiz.com/uploads/photo.jpg", - "url": "https://cdn.postiz.com/uploads/photo.jpg" -} -``` - -### Upload a Video (MP4) - -```bash -postiz upload ./videos/promo.mp4 -``` - -Response: -```json -{ - "id": "upload-456", - "path": "https://cdn.postiz.com/uploads/promo.mp4", - "url": "https://cdn.postiz.com/uploads/promo.mp4" -} -``` - -### Upload and Use in Post - -```bash -# 1. Upload the file -RESULT=$(postiz upload video.mp4) -echo $RESULT - -# 2. Extract the path (you'll need jq or similar) -PATH=$(echo $RESULT | jq -r '.path') - -# 3. Use in a post -postiz posts:create \ - -c "Check out my video!" \ - -m "$PATH" \ - -i "tiktok-123" -``` - -### Upload Multiple Files - -```bash -# Upload images -postiz upload image1.jpg -postiz upload image2.png -postiz upload image3.gif - -# Upload videos -postiz upload video1.mp4 -postiz upload video2.mov -``` - -## What Changed (Fix) - -### Before (❌ Bug) - -```bash -postiz upload video.mp4 -# ❌ Was detected as: image/jpeg (WRONG!) -``` - -The problem: The CLI defaulted to `image/jpeg` for any unknown file type. - -### After (✅ Fixed) - -```bash -postiz upload video.mp4 -# ✅ Correctly detected as: video/mp4 - -postiz upload audio.mp3 -# ✅ Correctly detected as: audio/mpeg - -postiz upload document.pdf -# ✅ Correctly detected as: application/pdf -``` - -## Platform-Specific Notes - -### TikTok -- Supports: MP4, MOV, WEBM -- Recommended: MP4 - -### YouTube -- Supports: MP4, MOV, AVI, WMV, FLV, 3GP, WEBM -- Recommended: MP4 - -### Instagram -- Images: JPG, PNG -- Videos: MP4, MOV -- Recommended: MP4 for videos, JPG for images - -### Twitter/X -- Images: PNG, JPG, GIF, WEBP -- Videos: MP4, MOV -- Max video size: 512MB - -### LinkedIn -- Images: PNG, JPG, GIF -- Videos: MP4, MOV, AVI -- Documents: PDF, DOC, DOCX, PPT - -## Troubleshooting - -### "Upload failed: Unsupported file type" - -Some platforms may not accept certain file types. Check the platform's documentation. - -**Solution:** Convert the file to a supported format: - -```bash -# Convert video to MP4 -ffmpeg -i video.avi video.mp4 - -# Then upload -postiz upload video.mp4 -``` - -### File Size Limits - -Different platforms have different file size limits: - -- **Twitter/X**: Max 512MB for videos -- **Instagram**: Max 100MB for videos -- **TikTok**: Max 287.6MB for videos -- **YouTube**: Max 128GB (but 256GB for verified) - -### "MIME type mismatch" - -If you renamed a file with the wrong extension: - -```bash -# ❌ Wrong: PNG file renamed to .jpg -mv image.png image.jpg -postiz upload image.jpg # Might fail - -# ✅ Correct: Keep original extension -postiz upload image.png -``` - -## Testing File Upload - -```bash -# Set API key -export POSTIZ_API_KEY=your_key - -# Test image upload -postiz upload test-image.jpg - -# Test video upload -postiz upload test-video.mp4 - -# Test audio upload -postiz upload test-audio.mp3 -``` - -## Error Messages - -### File Not Found -``` -❌ ENOENT: no such file or directory -``` - -**Solution:** Check the file path is correct. - -### No Permission -``` -❌ EACCES: permission denied -``` - -**Solution:** Check file permissions: -```bash -chmod 644 your-file.mp4 -``` - -### Invalid API Key -``` -❌ Upload failed (401): Unauthorized -``` - -**Solution:** Set your API key: -```bash -export POSTIZ_API_KEY=your_key -``` - -## Summary - -✅ **30+ file types supported** -✅ **Automatic MIME type detection** -✅ **Images, videos, audio, documents** -✅ **Correct handling of MP4, MOV, MP3, etc.** -✅ **No more defaulting to JPEG!** - -**The upload bug is fixed!** 🎉 diff --git a/apps/cli/SYNTAX_UPGRADE.md b/apps/cli/SYNTAX_UPGRADE.md deleted file mode 100644 index 0642c888..00000000 --- a/apps/cli/SYNTAX_UPGRADE.md +++ /dev/null @@ -1,291 +0,0 @@ -# Postiz CLI - Improved Syntax! 🎉 - -## What Changed - -The CLI now supports a **much better** command-line syntax for creating posts with comments that have their own media. - -## New Syntax: Multiple `-c` and `-m` Flags - -Instead of using semicolon-separated strings (which break when you need semicolons in your content), you can now use multiple `-c` and `-m` flags: - -```bash -postiz posts:create \ - -c "main post content" -m "media1.png,media2.png" \ - -c "first comment" -m "media3.png" \ - -c "second comment; with semicolon!" -m "media4.png,media5.png" \ - -i "twitter-123" -``` - -## The Problem We Solved - -### ❌ Old Approach (Problematic) - -```bash -postiz posts:create \ - -c "Main post" \ - --comments "Comment 1;Comment 2;Comment 3" \ - -i "twitter-123" -``` - -**Issues:** -1. ❌ Can't use semicolons in comment text -2. ❌ Comments can't have their own media -3. ❌ Less intuitive syntax -4. ❌ Limited flexibility - -### ✅ New Approach (Better!) - -```bash -postiz posts:create \ - -c "Main post" -m "main.jpg" \ - -c "Comment 1; with semicolon!" -m "comment1.jpg" \ - -c "Comment 2" -m "comment2.jpg" \ - -c "Comment 3" \ - -i "twitter-123" -``` - -**Benefits:** -1. ✅ Semicolons work fine in content -2. ✅ Each comment can have different media -3. ✅ More readable and intuitive -4. ✅ Fully flexible - -## How It Works - -### Pairing Logic - -The CLI pairs `-c` and `-m` flags in order: - -```bash -postiz posts:create \ - -c "Content 1" -m "media-for-content-1.jpg" \ # Pair 1 - -c "Content 2" -m "media-for-content-2.jpg" \ # Pair 2 - -c "Content 3" -m "media-for-content-3.jpg" \ # Pair 3 - -i "twitter-123" -``` - -- **1st `-c`** = Main post -- **2nd `-c`** = First comment (posted after delay) -- **3rd `-c`** = Second comment (posted after delay) -- Each `-m` is paired with the corresponding `-c` (in order) - -### Media is Optional - -```bash -postiz posts:create \ - -c "Post with media" -m "image.jpg" \ - -c "Comment without media" \ - -c "Another comment" \ - -i "twitter-123" -``` - -Result: -- Post with image -- Text-only comment -- Another text-only comment - -### Multiple Media per Post/Comment - -```bash -postiz posts:create \ - -c "Main post" -m "img1.jpg,img2.jpg,img3.jpg" \ - -c "Comment" -m "img4.jpg,img5.jpg" \ - -i "twitter-123" -``` - -Result: -- Main post with 3 images -- Comment with 2 images - -## Real Examples - -### Example 1: Product Launch - -```bash -postiz posts:create \ - -c "🚀 Launching ProductX today!" \ - -m "hero.jpg,features.jpg" \ - -c "⭐ Key features you'll love..." \ - -m "features-detail.jpg" \ - -c "💰 Special offer: 50% off!" \ - -m "discount.jpg" \ - -i "twitter-123,linkedin-456" -``` - -### Example 2: Twitter Thread - -```bash -postiz posts:create \ - -c "🧵 Thread: How to X (1/5)" -m "intro.jpg" \ - -c "Step 1: ... (2/5)" -m "step1.jpg" \ - -c "Step 2: ... (3/5)" -m "step2.jpg" \ - -c "Step 3: ... (4/5)" -m "step3.jpg" \ - -c "Conclusion (5/5)" -m "done.jpg" \ - -d 2000 \ - -i "twitter-123" -``` - -### Example 3: Tutorial with Screenshots - -```bash -postiz posts:create \ - -c "Tutorial: Feature X 📖" \ - -m "tutorial-cover.jpg" \ - -c "1. Open settings" \ - -m "settings-screenshot.jpg" \ - -c "2. Enable feature X" \ - -m "enable-screenshot.jpg" \ - -c "3. You're done! 🎉" \ - -m "success-screenshot.jpg" \ - -i "twitter-123" -``` - -### Example 4: Content with Special Characters - -```bash -postiz posts:create \ - -c "Main post about programming" \ - -c "First tip: Use const; avoid var" \ - -c "Second tip: Functions should do one thing; keep it simple" \ - -c "Third tip: Comments should explain 'why'; not 'what'" \ - -i "twitter-123" -``` - -**No escaping needed!** Semicolons work perfectly. - -## Options Reference - -| Option | Alias | Multiple? | Description | -|--------|-------|-----------|-------------| -| `--content` | `-c` | ✅ Yes | Post/comment content | -| `--media` | `-m` | ✅ Yes | Comma-separated media URLs | -| `--integrations` | `-i` | ❌ No | Integration IDs | -| `--schedule` | `-s` | ❌ No | ISO 8601 date | -| `--delay` | `-d` | ❌ No | Delay between comments (ms, default: 5000) | -| `--shortLink` | - | ❌ No | Use URL shortener (default: true) | -| `--json` | `-j` | ❌ No | Load from JSON file | - -## Delay Between Comments - -Use `-d` to control the delay between comments: - -```bash -postiz posts:create \ - -c "Main" \ - -c "Comment 1" \ - -c "Comment 2" \ - -d 10000 \ # 10 seconds between each - -i "twitter-123" -``` - -**Default:** 5000ms (5 seconds) - -## Command Line vs JSON - -### Use Command Line When: -- ✅ Quick posts -- ✅ Same content for all platforms -- ✅ Simple structure -- ✅ Dynamic/scripted content - -### Use JSON When: -- ✅ Different content per platform -- ✅ Very complex structures -- ✅ Reusable templates -- ✅ Integration with other tools - -## For AI Agents - -### Generating Commands - -```javascript -function buildPostCommand(posts, integrationId) { - const parts = ['postiz posts:create']; - - posts.forEach(post => { - parts.push(`-c "${post.content.replace(/"/g, '\\"')}"`); - if (post.media && post.media.length > 0) { - parts.push(`-m "${post.media.join(',')}"`); - } - }); - - parts.push(`-i "${integrationId}"`); - - return parts.join(' \\\n '); -} - -// Usage -const posts = [ - { content: "Main post", media: ["img1.jpg", "img2.jpg"] }, - { content: "Comment; with semicolon!", media: ["img3.jpg"] }, - { content: "Another comment", media: [] } -]; - -const command = buildPostCommand(posts, "twitter-123"); -console.log(command); -``` - -Output: -```bash -postiz posts:create \ - -c "Main post" \ - -m "img1.jpg,img2.jpg" \ - -c "Comment; with semicolon!" \ - -m "img3.jpg" \ - -c "Another comment" \ - -i "twitter-123" -``` - -## Migration Guide - -If you have existing scripts using the old syntax: - -### Before: -```bash -postiz posts:create \ - -c "Main post" \ - --comments "Comment 1;Comment 2" \ - --image "main-image.jpg" \ - -i "twitter-123" -``` - -### After: -```bash -postiz posts:create \ - -c "Main post" -m "main-image.jpg" \ - -c "Comment 1" \ - -c "Comment 2" \ - -i "twitter-123" -``` - -## Documentation - -See these files for more details: - -- **COMMAND_LINE_GUIDE.md** - Comprehensive command-line guide -- **command-line-examples.sh** - Executable examples -- **EXAMPLES.md** - Full usage patterns -- **SKILL.md** - AI agent integration -- **README.md** - General documentation - -## Summary - -### ✅ You Can Now: - -1. **Use multiple `-c` flags** for main post + comments -2. **Use multiple `-m` flags** to pair media with each `-c` -3. **Use semicolons freely** in your content -4. **Create complex threads** easily from command line -5. **Each comment has its own media** array -6. **More intuitive syntax** overall - -### 🎯 Perfect For: - -- Twitter threads -- Product launches with follow-ups -- Tutorials with screenshots -- Event coverage -- Multi-step announcements -- Any post with comments that need their own media! - -**The CLI is now much more powerful and user-friendly!** 🚀 diff --git a/apps/cli/examples/COMMAND_LINE_GUIDE.md b/apps/cli/examples/COMMAND_LINE_GUIDE.md deleted file mode 100644 index 796fb3a7..00000000 --- a/apps/cli/examples/COMMAND_LINE_GUIDE.md +++ /dev/null @@ -1,358 +0,0 @@ -# Postiz CLI - Command Line Guide - -## New Syntax: Multiple `-c` and `-m` Flags - -The CLI now supports a much more intuitive syntax for creating posts with comments that have their own media. - -## Basic Syntax - -```bash -postiz posts:create \ - -c "content" -m "media" \ # Can be repeated multiple times - -c "content" -m "media" \ # Each pair = one post/comment - -i "integration-id" -``` - -### How It Works - -- **First `-c`**: Main post content -- **Subsequent `-c`**: Comments/replies -- **Each `-m`**: Media for the corresponding `-c` -- `-m` is optional (text-only posts/comments) -- Order matters: `-c` and `-m` are paired in order - -## Examples - -### 1. Simple Post - -```bash -postiz posts:create \ - -c "Hello World!" \ - -i "twitter-123" -``` - -### 2. Post with Multiple Images - -```bash -postiz posts:create \ - -c "Check out these photos!" \ - -m "photo1.jpg,photo2.jpg,photo3.jpg" \ - -i "twitter-123" -``` - -**Result:** -- Main post with 3 images - -### 3. Post with Comments, Each Having Their Own Media - -```bash -postiz posts:create \ - -c "Main post 🚀" \ - -m "main-image1.jpg,main-image2.jpg" \ - -c "First comment 📸" \ - -m "comment1-image.jpg" \ - -c "Second comment 🎨" \ - -m "comment2-img1.jpg,comment2-img2.jpg" \ - -i "twitter-123" -``` - -**Result:** -- Main post with 2 images -- First comment (posted 5s later) with 1 image -- Second comment (posted 10s later) with 2 images - -### 4. Comments Can Contain Semicolons! 🎉 - -```bash -postiz posts:create \ - -c "Main post" \ - -c "First comment; with a semicolon!" \ - -c "Second comment; with multiple; semicolons; works fine!" \ - -i "twitter-123" -``` - -**No escaping needed!** Each `-c` is a separate argument, so special characters work perfectly. - -### 5. Twitter Thread - -```bash -postiz posts:create \ - -c "🧵 Thread about X (1/5)" \ - -m "thread1.jpg" \ - -c "Key point 1 (2/5)" \ - -m "thread2.jpg" \ - -c "Key point 2 (3/5)" \ - -m "thread3.jpg" \ - -c "Key point 3 (4/5)" \ - -m "thread4.jpg" \ - -c "Conclusion 🎉 (5/5)" \ - -m "thread5.jpg" \ - -d 2000 \ - -i "twitter-123" -``` - -**Result:** 5-part thread with 2-second delays between tweets - -### 6. Mix: Some with Media, Some Without - -```bash -postiz posts:create \ - -c "Amazing sunset! 🌅" \ - -m "sunset.jpg" \ - -c "Taken at 6:30 PM" \ - -c "Location: Santa Monica Beach" \ - -c "Camera: iPhone 15 Pro" \ - -i "twitter-123" -``` - -**Result:** -- Main post with 1 image -- 3 text-only comments - -### 7. Multi-Platform with Same Content - -```bash -postiz posts:create \ - -c "Big announcement! 🎉" \ - -m "announcement.jpg" \ - -c "More details coming soon..." \ - -i "twitter-123,linkedin-456,facebook-789" -``` - -**Result:** Same post + comment posted to all 3 platforms - -### 8. Scheduled Post with Follow-ups - -```bash -postiz posts:create \ - -c "Product launching today! 🚀" \ - -m "product-hero.jpg,product-features.jpg" \ - -c "Special launch offer: 50% off!" \ - -m "discount-banner.jpg" \ - -c "Limited to first 100 customers!" \ - -s "2024-12-25T09:00:00Z" \ - -i "twitter-123" -``` - -**Result:** Scheduled main post with 2 follow-up comments - -### 9. Product Tutorial - -```bash -postiz posts:create \ - -c "Tutorial: How to Use Feature X 📖" \ - -m "tutorial-intro.jpg" \ - -c "Step 1: Open the settings menu" \ - -m "step1-screenshot.jpg" \ - -c "Step 2: Toggle the feature on" \ - -m "step2-screenshot.jpg" \ - -c "Step 3: Customize your preferences" \ - -m "step3-screenshot.jpg" \ - -c "That's it! You're all set 🎉" \ - -d 3000 \ - -i "twitter-123" -``` - -## Options Reference - -| Flag | Alias | Description | Multiple? | -|------|-------|-------------|-----------| -| `--content` | `-c` | Post/comment content | ✅ Yes | -| `--media` | `-m` | Comma-separated media URLs | ✅ Yes | -| `--integrations` | `-i` | Comma-separated integration IDs | ❌ No | -| `--schedule` | `-s` | ISO 8601 date (schedule post) | ❌ No | -| `--delay` | `-d` | Delay between comments (ms) | ❌ No | -| `--shortLink` | - | Use URL shortener | ❌ No | -| `--json` | `-j` | Load from JSON file | ❌ No | - -## How `-c` and `-m` Pair Together - -```bash -postiz posts:create \ - -c "First content" -m "first-media.jpg" \ # Pair 1 → Main post - -c "Second content" -m "second-media.jpg" \ # Pair 2 → Comment 1 - -c "Third content" -m "third-media.jpg" \ # Pair 3 → Comment 2 - -i "twitter-123" -``` - -**Pairing logic:** -- 1st `-c` pairs with 1st `-m` (if provided) -- 2nd `-c` pairs with 2nd `-m` (if provided) -- 3rd `-c` pairs with 3rd `-m` (if provided) -- If no `-m` for a `-c`, it's text-only - -## Delay Between Comments - -Use `-d` or `--delay` to set the delay (in milliseconds) between comments: - -```bash -postiz posts:create \ - -c "Main post" \ - -c "Comment 1" \ - -c "Comment 2" \ - -d 10000 \ # 10 seconds between each - -i "twitter-123" -``` - -**Default:** 5000ms (5 seconds) - -## Comparison: Old vs New Syntax - -### ❌ Old Way (Limited) - -```bash -# Could only do simple comments without custom media -postiz posts:create \ - -c "Main post" \ - --comments "Comment 1;Comment 2;Comment 3" \ - --image "main-image.jpg" \ - -i "twitter-123" -``` - -**Problems:** -- Comments couldn't have their own media -- Semicolons in content would break it -- Less intuitive - -### ✅ New Way (Flexible) - -```bash -postiz posts:create \ - -c "Main post" -m "main.jpg" \ - -c "Comment 1; with semicolon!" -m "comment1.jpg" \ - -c "Comment 2" -m "comment2.jpg" \ - -i "twitter-123" -``` - -**Benefits:** -- ✅ Each comment can have its own media -- ✅ Semicolons work fine -- ✅ More readable -- ✅ More flexible - -## When to Use JSON vs Command Line - -### Use Command Line (`-c` and `-m`) When: -- ✅ Same content for all integrations -- ✅ Simple, straightforward posts -- ✅ Quick one-off posts -- ✅ Scripting with dynamic content - -### Use JSON (`--json`) When: -- ✅ Different content per platform -- ✅ Complex settings or metadata -- ✅ Reusable post templates -- ✅ Very long or formatted content - -## Tips for AI Agents - -### Generate Commands Programmatically - -```javascript -function createThreadCommand(tweets, integrationId) { - const parts = [ - 'postiz posts:create' - ]; - - tweets.forEach(tweet => { - parts.push(`-c "${tweet.content}"`); - if (tweet.media && tweet.media.length > 0) { - parts.push(`-m "${tweet.media.join(',')}"`); - } - }); - - parts.push(`-i "${integrationId}"`); - - return parts.join(' \\\n '); -} - -const thread = [ - { content: "Tweet 1/3", media: ["img1.jpg"] }, - { content: "Tweet 2/3", media: ["img2.jpg"] }, - { content: "Tweet 3/3", media: ["img3.jpg"] } -]; - -const command = createThreadCommand(thread, "twitter-123"); -console.log(command); -``` - -### Escape Special Characters - -In bash, you may need to escape some characters: - -```bash -# Single quotes prevent interpolation -postiz posts:create \ - -c 'Message with $variables and "quotes"' \ - -i "twitter-123" - -# Or use backslashes -postiz posts:create \ - -c "Message with \$variables and \"quotes\"" \ - -i "twitter-123" -``` - -## Error Handling - -### Missing Integration - -```bash -postiz posts:create -c "Post" -m "img.jpg" -# ❌ Error: --integrations is required when not using --json -``` - -**Fix:** Add `-i` flag - -### No Content - -```bash -postiz posts:create -i "twitter-123" -# ❌ Error: Either --content or --json is required -``` - -**Fix:** Add at least one `-c` flag - -### Mismatched Count (OK!) - -```bash -# This is fine! Extra -m flags are ignored -postiz posts:create \ - -c "Post 1" -m "img1.jpg" \ - -c "Post 2" \ - -c "Post 3" -m "img3.jpg" \ - -i "twitter-123" - -# Result: -# - Post 1 with img1.jpg -# - Post 2 with no media -# - Post 3 with img3.jpg -``` - -## Full Example: Product Launch - -```bash -#!/bin/bash - -export POSTIZ_API_KEY=your_key - -postiz posts:create \ - -c "🚀 Launching ProductX today!" \ - -m "https://cdn.example.com/hero.jpg,https://cdn.example.com/features.jpg" \ - -c "🎯 Key Features:\n• AI-powered\n• Cloud-native\n• Open source" \ - -m "https://cdn.example.com/features-detail.jpg" \ - -c "💰 Special launch pricing: 50% off for early adopters!" \ - -m "https://cdn.example.com/pricing.jpg" \ - -c "🔗 Get started: https://example.com/productx" \ - -s "2024-12-25T09:00:00Z" \ - -d 3600000 \ - -i "twitter-123,linkedin-456,facebook-789" - -echo "✅ Product launch scheduled!" -``` - -## See Also - -- **EXAMPLES.md** - JSON file examples -- **SKILL.md** - AI agent patterns -- **README.md** - Full documentation -- **examples/*.json** - Template files diff --git a/apps/cli/examples/EXAMPLES.md b/apps/cli/examples/EXAMPLES.md deleted file mode 100644 index 31abc3e6..00000000 --- a/apps/cli/examples/EXAMPLES.md +++ /dev/null @@ -1,316 +0,0 @@ -# Postiz CLI - Advanced Examples - -This directory contains examples demonstrating the full capabilities of the Postiz CLI, including posts with comments and multiple media. - -## Understanding the Post Structure - -The Postiz API supports a rich post structure: - -```typescript -{ - type: 'now' | 'schedule' | 'draft' | 'update', - date: string, // ISO 8601 date - shortLink: boolean, // Use URL shortener - tags: Tag[], // Post tags - posts: [ // Can post to multiple platforms at once - { - integration: { id: string }, // Platform integration ID - value: [ // Main post + comments/thread - { - content: string, // Post/comment text - image: MediaDto[], // Multiple media attachments - delay?: number // Delay in ms before posting (for comments) - }, - // ... more comments - ], - settings: { __type: 'EmptySettings' } - } - ] -} -``` - -## Simple Usage Examples - -### Basic Post - -```bash -postiz posts:create \ - -c "Hello World!" \ - -i "twitter-123" -``` - -### Post with Multiple Images - -```bash -postiz posts:create \ - -c "Check out these images!" \ - --image "https://example.com/img1.jpg,https://example.com/img2.jpg,https://example.com/img3.jpg" \ - -i "twitter-123" -``` - -### Post with Comments (Simple) - -```bash -postiz posts:create \ - -c "Main post content" \ - --comments "First comment;Second comment;Third comment" \ - -i "twitter-123" -``` - -### Scheduled Post - -```bash -postiz posts:create \ - -c "Future post" \ - -s "2024-12-31T12:00:00Z" \ - -i "twitter-123,linkedin-456" -``` - -## Advanced JSON Examples - -For complex posts with comments that have their own media, use JSON files: - -### 1. Post with Comments and Media - -**File:** `post-with-comments.json` - -```bash -postiz posts:create --json examples/post-with-comments.json -``` - -This creates: -- Main post with 2 images -- First comment with 1 image (posted 5s after main) -- Second comment with 2 images (posted 10s after main) - -### 2. Multi-Platform Campaign - -**File:** `multi-platform-post.json` - -```bash -postiz posts:create --json examples/multi-platform-post.json -``` - -This creates: -- Twitter post with main + comment -- LinkedIn post with single content -- Facebook post with main + comment -All scheduled for the same time with platform-specific content and media! - -### 3. Twitter Thread - -**File:** `thread-post.json` - -```bash -postiz posts:create --json examples/thread-post.json -``` - -This creates a 5-part Twitter thread, with each tweet having its own image and a 2-second delay between tweets. - -## JSON File Structure Explained - -### Basic Structure - -```json -{ - "type": "now", // "now", "schedule", "draft", "update" - "date": "2024-01-15T12:00:00Z", // When to post (ISO 8601) - "shortLink": true, // Enable URL shortening - "tags": [], // Array of tags - "posts": [...] // Array of posts -} -``` - -### Post Structure - -```json -{ - "integration": { - "id": "twitter-123" // Get this from integrations:list - }, - "value": [ // Array of content (main + comments) - { - "content": "Post text", // The actual content - "image": [ // Array of media - { - "id": "unique-id", // Unique identifier - "path": "https://..." // URL to the image - } - ], - "delay": 5000 // Optional delay in milliseconds - } - ], - "settings": { - "__type": "EmptySettings" // Platform-specific settings - } -} -``` - -## Use Cases - -### 1. Product Launch Campaign - -Create a coordinated multi-platform launch: - -```json -{ - "type": "schedule", - "date": "2024-03-15T09:00:00Z", - "posts": [ - { - "integration": { "id": "twitter-id" }, - "value": [ - { "content": "🚀 Launching today!", "image": [...] }, - { "content": "Special features:", "image": [...], "delay": 3600000 }, - { "content": "Get it now:", "image": [...], "delay": 7200000 } - ] - }, - { - "integration": { "id": "linkedin-id" }, - "value": [ - { "content": "Professional announcement...", "image": [...] } - ] - } - ] -} -``` - -### 2. Tutorial Series - -Create an educational thread: - -```json -{ - "type": "now", - "posts": [ - { - "integration": { "id": "twitter-id" }, - "value": [ - { "content": "🧵 How to X (1/5)", "image": [...] }, - { "content": "Step 1: ... (2/5)", "image": [...], "delay": 2000 }, - { "content": "Step 2: ... (3/5)", "image": [...], "delay": 2000 }, - { "content": "Step 3: ... (4/5)", "image": [...], "delay": 2000 }, - { "content": "Conclusion (5/5)", "image": [...], "delay": 2000 } - ] - } - ] -} -``` - -### 3. Event Coverage - -Live event updates with media: - -```json -{ - "type": "now", - "posts": [ - { - "integration": { "id": "twitter-id" }, - "value": [ - { - "content": "📍 Event starting now!", - "image": [ - { "id": "1", "path": "venue-photo.jpg" } - ] - }, - { - "content": "First speaker taking stage", - "image": [ - { "id": "2", "path": "speaker-photo.jpg" } - ], - "delay": 1800000 - } - ] - } - ] -} -``` - -## Getting Integration IDs - -Before creating posts, get your integration IDs: - -```bash -postiz integrations:list -``` - -Output: -```json -[ - { "id": "abc-123-twitter", "provider": "twitter", "name": "@myaccount" }, - { "id": "def-456-linkedin", "provider": "linkedin", "name": "My Company" } -] -``` - -Use these IDs in your `integration.id` fields. - -## Tips for AI Agents - -1. **Use JSON for complex posts** - If you need comments with media, always use JSON files -2. **Delays matter** - Use appropriate delays between comments (Twitter: 2-5s, others: 30s-1min) -3. **Image IDs** - Generate unique IDs for each image (can use UUIDs or random strings) -4. **Validate before sending** - Check that all integration IDs exist -5. **Test with "draft" type** - Use `"type": "draft"` to create without posting - -## Automation Scripts - -### Batch Create from Directory - -```bash -#!/bin/bash -# Create posts from all JSON files in a directory - -for file in posts/*.json; do - echo "Creating post from $file..." - postiz posts:create --json "$file" - sleep 2 -done -``` - -### Generate JSON Programmatically - -```javascript -const fs = require('fs'); - -function createThreadPost(tweets, integrationId) { - return { - type: 'now', - date: new Date().toISOString(), - shortLink: true, - tags: [], - posts: [{ - integration: { id: integrationId }, - value: tweets.map((tweet, i) => ({ - content: tweet.content, - image: tweet.images || [], - delay: i === 0 ? undefined : 2000 - })), - settings: { __type: 'EmptySettings' } - }] - }; -} - -const thread = createThreadPost([ - { content: 'Tweet 1', images: [...] }, - { content: 'Tweet 2', images: [...] }, - { content: 'Tweet 3', images: [...] } -], 'twitter-123'); - -fs.writeFileSync('thread.json', JSON.stringify(thread, null, 2)); -``` - -## Error Handling - -Common errors and solutions: - -1. **Invalid integration ID** - Run `integrations:list` to get valid IDs -2. **Invalid image path** - Ensure images are accessible URLs or uploaded to Postiz first -3. **Missing required fields** - Check that `type`, `date`, `shortLink`, `tags`, and `posts` are all present -4. **Invalid date format** - Use ISO 8601 format: `YYYY-MM-DDTHH:mm:ssZ` - -## Further Reading - -- See `SKILL.md` for AI agent patterns -- See `README.md` for installation and setup -- See `QUICK_START.md` for basic usage diff --git a/apps/cli/examples/ai-agent-example.js b/apps/cli/examples/ai-agent-example.js deleted file mode 100644 index d5f18933..00000000 --- a/apps/cli/examples/ai-agent-example.js +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env node - -/** - * Example: Using Postiz CLI from an AI Agent (Node.js) - * - * This demonstrates how AI agents can programmatically use the Postiz CLI - * to schedule social media posts. - */ - -const { execSync } = require('child_process'); - -// Configuration -const POSTIZ_API_KEY = process.env.POSTIZ_API_KEY; - -if (!POSTIZ_API_KEY) { - console.error('❌ POSTIZ_API_KEY environment variable is required'); - process.exit(1); -} - -/** - * Execute a Postiz CLI command - */ -function runPostizCommand(command) { - try { - const output = execSync(`postiz ${command}`, { - env: { ...process.env, POSTIZ_API_KEY }, - encoding: 'utf-8', - }); - return JSON.parse(output); - } catch (error) { - console.error(`Command failed: ${command}`); - console.error(error.message); - throw error; - } -} - -/** - * Main AI Agent workflow - */ -async function main() { - console.log('🤖 AI Agent: Starting social media scheduling workflow...\n'); - - try { - // Step 1: Get available integrations - console.log('📋 Fetching connected integrations...'); - const integrations = runPostizCommand('integrations:list'); - console.log(`Found ${integrations.length || 0} integrations\n`); - - // Step 2: Create multiple scheduled posts - const posts = [ - { - content: '🌅 Good morning! Starting the day with positive energy.', - schedule: getScheduledTime(9, 0), // 9 AM - }, - { - content: '☕ Midday motivation: Keep pushing towards your goals!', - schedule: getScheduledTime(12, 0), // 12 PM - }, - { - content: '🌙 Evening reflection: What did you accomplish today?', - schedule: getScheduledTime(20, 0), // 8 PM - }, - ]; - - console.log('📝 Creating scheduled posts...'); - for (let i = 0; i < posts.length; i++) { - const post = posts[i]; - console.log(` ${i + 1}. Creating post scheduled for ${post.schedule}...`); - - const command = `posts:create -c "${post.content}" -s "${post.schedule}"`; - const result = runPostizCommand(command); - - console.log(` ✅ Post created with ID: ${result.id || 'unknown'}`); - } - - console.log('\n📊 Checking created posts...'); - const postsList = runPostizCommand('posts:list -l 5'); - console.log(`Total recent posts: ${postsList.total || 0}\n`); - - console.log('✅ AI Agent workflow completed successfully!'); - } catch (error) { - console.error('\n❌ AI Agent workflow failed:', error.message); - process.exit(1); - } -} - -/** - * Helper: Get ISO 8601 timestamp for today at specific time - */ -function getScheduledTime(hours, minutes) { - const date = new Date(); - date.setHours(hours, minutes, 0, 0); - - // If time already passed today, schedule for tomorrow - if (date < new Date()) { - date.setDate(date.getDate() + 1); - } - - return date.toISOString(); -} - -// Run the agent -main().catch(console.error); diff --git a/apps/cli/examples/basic-usage.sh b/apps/cli/examples/basic-usage.sh deleted file mode 100755 index d94ef9c3..00000000 --- a/apps/cli/examples/basic-usage.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -# Basic Postiz CLI Usage Example -# Make sure to set your API key first: export POSTIZ_API_KEY=your_key - -echo "🚀 Postiz CLI Example Workflow" -echo "" - -# Check if API key is set -if [ -z "$POSTIZ_API_KEY" ]; then - echo "❌ POSTIZ_API_KEY is not set!" - echo "Set it with: export POSTIZ_API_KEY=your_api_key" - exit 1 -fi - -echo "✅ API key is set" -echo "" - -# 1. List integrations -echo "📋 Step 1: Listing connected integrations..." -postiz integrations:list -echo "" - -# 2. Create a post -echo "📝 Step 2: Creating a test post..." -postiz posts:create \ - -c "Hello from Postiz CLI! This is an automated test post." \ - -s "$(date -u -v+1H +%Y-%m-%dT%H:%M:%SZ)" # Schedule 1 hour from now -echo "" - -# 3. List posts -echo "📋 Step 3: Listing recent posts..." -postiz posts:list -l 5 -echo "" - -echo "✅ Example workflow completed!" -echo "" -echo "💡 Tips:" -echo " - Use -i flag to specify integrations when creating posts" -echo " - Upload images with: postiz upload ./path/to/image.png" -echo " - Delete posts with: postiz posts:delete " -echo " - Get help: postiz --help" diff --git a/apps/cli/examples/command-line-examples.sh b/apps/cli/examples/command-line-examples.sh deleted file mode 100755 index 65ce1eab..00000000 --- a/apps/cli/examples/command-line-examples.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash - -# Postiz CLI - Command Line Examples -# Demonstrating the new -c and -m flag syntax - -echo "🚀 Postiz CLI Command Line Examples" -echo "" - -# Make sure API key is set -if [ -z "$POSTIZ_API_KEY" ]; then - echo "❌ POSTIZ_API_KEY is not set!" - echo "Set it with: export POSTIZ_API_KEY=your_api_key" - exit 1 -fi - -echo "✅ API key is set" -echo "" - -# Example 1: Simple post -echo "📝 Example 1: Simple post" -echo "Command:" -echo 'postiz posts:create -c "Hello World!" -i "twitter-123"' -echo "" - -# Example 2: Post with multiple images -echo "📸 Example 2: Post with multiple images" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Check out these amazing photos!" \' -echo ' -m "photo1.jpg,photo2.jpg,photo3.jpg" \' -echo ' -i "twitter-123"' -echo "" - -# Example 3: Post with comments, each having their own media -echo "💬 Example 3: Post with comments, each having different media" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Main post content 🚀" \' -echo ' -m "main-image1.jpg,main-image2.jpg" \' -echo ' -c "First comment with its own image 📸" \' -echo ' -m "comment1-image.jpg" \' -echo ' -c "Second comment with different images 🎨" \' -echo ' -m "comment2-image1.jpg,comment2-image2.jpg" \' -echo ' -i "twitter-123"' -echo "" - -# Example 4: Comments with semicolons (no escaping needed!) -echo "🎯 Example 4: Comments can contain semicolons!" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Main post" \' -echo ' -c "First comment; notice the semicolon!" \' -echo ' -c "Second comment; with multiple; semicolons; works fine!" \' -echo ' -i "twitter-123"' -echo "" - -# Example 5: Twitter thread with custom delay -echo "🧵 Example 5: Twitter thread with 2-second delays" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "🧵 How to use Postiz CLI (1/5)" \' -echo ' -m "thread-intro.jpg" \' -echo ' -c "Step 1: Install the CLI (2/5)" \' -echo ' -m "step1-screenshot.jpg" \' -echo ' -c "Step 2: Set your API key (3/5)" \' -echo ' -m "step2-screenshot.jpg" \' -echo ' -c "Step 3: Create your first post (4/5)" \' -echo ' -m "step3-screenshot.jpg" \' -echo ' -c "You'\''re all set! 🎉 (5/5)" \' -echo ' -m "done.jpg" \' -echo ' -d 2000 \' -echo ' -i "twitter-123"' -echo "" - -# Example 6: Scheduled post with comments -echo "⏰ Example 6: Scheduled post with follow-up comments" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Product launch! 🚀" \' -echo ' -m "product-hero.jpg,product-features.jpg" \' -echo ' -c "Special launch offer - 50% off!" \' -echo ' -m "discount-banner.jpg" \' -echo ' -c "Limited time only!" \' -echo ' -s "2024-12-25T09:00:00Z" \' -echo ' -i "twitter-123,linkedin-456"' -echo "" - -# Example 7: Multi-platform with same content -echo "🌐 Example 7: Multi-platform posting" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Exciting announcement! 🎉" \' -echo ' -m "announcement.jpg" \' -echo ' -c "More details in the comments..." \' -echo ' -m "details-infographic.jpg" \' -echo ' -i "twitter-123,linkedin-456,facebook-789"' -echo "" - -# Example 8: Comments without media -echo "💭 Example 8: Main post with media, comments without media" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Check out this amazing view! 🏔️" \' -echo ' -m "mountain-photo.jpg" \' -echo ' -c "Taken at sunrise this morning" \' -echo ' -c "Location: Swiss Alps" \' -echo ' -i "twitter-123"' -echo "" - -# Example 9: Product tutorial series -echo "📚 Example 9: Product tutorial series" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Tutorial: Getting Started with Our Product 📖" \' -echo ' -m "tutorial-cover.jpg" \' -echo ' -c "1. First, download and install the app" \' -echo ' -m "install-screen.jpg" \' -echo ' -c "2. Create your account and set up your profile" \' -echo ' -m "signup-screen.jpg" \' -echo ' -c "3. You'\''re ready to go! Start creating your first project" \' -echo ' -m "dashboard-screen.jpg" \' -echo ' -d 3000 \' -echo ' -i "twitter-123"' -echo "" - -# Example 10: Event coverage -echo "📍 Example 10: Live event coverage" -echo "Command:" -echo 'postiz posts:create \' -echo ' -c "Conference 2024 is starting! 🎤" \' -echo ' -m "venue-photo.jpg" \' -echo ' -c "First speaker: Jane Doe talking about AI" \' -echo ' -m "speaker1-photo.jpg" \' -echo ' -c "Second speaker: John Smith on cloud architecture" \' -echo ' -m "speaker2-photo.jpg" \' -echo ' -c "Networking break! Great conversations happening" \' -echo ' -m "networking-photo.jpg" \' -echo ' -d 30000 \' -echo ' -i "twitter-123,linkedin-456"' -echo "" - -echo "💡 Tips:" -echo " - Use multiple -c flags for main post + comments" -echo " - Use -m flags to specify media for each -c" -echo " - First -c is the main post, subsequent ones are comments" -echo " - -m is optional, can be omitted for text-only comments" -echo " - Use -d to set delay between comments (in milliseconds)" -echo " - Semicolons and special characters work fine in -c content!" -echo "" -echo "📖 For more examples, see:" -echo " - examples/EXAMPLES.md - Comprehensive guide" -echo " - examples/*.json - JSON file examples" -echo " - SKILL.md - AI agent patterns" diff --git a/apps/cli/examples/multi-platform-post.json b/apps/cli/examples/multi-platform-post.json deleted file mode 100644 index acceb425..00000000 --- a/apps/cli/examples/multi-platform-post.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "type": "schedule", - "date": "2024-12-25T12:00:00Z", - "shortLink": true, - "tags": [ - { - "value": "holiday", - "label": "Holiday" - }, - { - "value": "marketing", - "label": "Marketing" - } - ], - "posts": [ - { - "integration": { - "id": "twitter-integration-id" - }, - "value": [ - { - "content": "Happy Holidays! 🎄 Check out our special offers!", - "image": [ - { - "id": "holiday1", - "path": "https://example.com/holiday-twitter.jpg" - } - ] - }, - { - "content": "Limited time offer - 50% off! 🎁", - "image": [], - "delay": 3600000 - } - ], - "settings": { - "__type": "EmptySettings" - } - }, - { - "integration": { - "id": "linkedin-integration-id" - }, - "value": [ - { - "content": "Season's greetings from our team! We're offering exclusive holiday promotions.", - "image": [ - { - "id": "holiday2", - "path": "https://example.com/holiday-linkedin.jpg" - } - ] - } - ], - "settings": { - "__type": "EmptySettings" - } - }, - { - "integration": { - "id": "facebook-integration-id" - }, - "value": [ - { - "content": "🎅 Happy Holidays! Special announcement in the comments!", - "image": [ - { - "id": "holiday3", - "path": "https://example.com/holiday-facebook-main.jpg" - } - ] - }, - { - "content": "Our holiday sale is now live! Visit our website for amazing deals 🎁", - "image": [ - { - "id": "holiday4", - "path": "https://example.com/holiday-sale-banner.jpg" - } - ], - "delay": 300000 - } - ], - "settings": { - "__type": "EmptySettings" - } - } - ] -} diff --git a/apps/cli/examples/multi-platform-with-settings.json b/apps/cli/examples/multi-platform-with-settings.json deleted file mode 100644 index 3aa9dff3..00000000 --- a/apps/cli/examples/multi-platform-with-settings.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "type": "schedule", - "date": "2024-03-15T09:00:00Z", - "shortLink": true, - "tags": [ - { "value": "product-launch", "label": "Product Launch" } - ], - "posts": [ - { - "integration": { "id": "reddit-integration-id" }, - "value": [{ - "content": "We're launching our new CLI tool today!\n\nIt's designed to make social media scheduling effortless for developers and AI agents. Built with TypeScript, supports 28+ platforms, and has a clean, intuitive API.\n\nFeatures:\n- Multi-platform posting\n- Thread creation\n- Scheduled posts\n- Comments with media\n- Provider-specific settings\n\nTry it out and let us know what you think!", - "image": [ - { "id": "r1", "path": "https://cdn.example.com/reddit-screenshot.jpg" } - ] - }], - "settings": { - "__type": "reddit", - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Launching Postiz CLI - Social Media Automation for Developers", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - } - }, - { - "integration": { "id": "twitter-integration-id" }, - "value": [ - { - "content": "🚀 Launching Postiz CLI today!\n\nFinally, a developer-friendly way to automate social media. Built with TypeScript, supports 28+ platforms.\n\n✨ Features in thread below 👇", - "image": [ - { "id": "t1", "path": "https://cdn.example.com/twitter-banner.jpg" } - ] - }, - { - "content": "1️⃣ Multi-platform posting\nPost to Twitter, LinkedIn, Reddit, TikTok, YouTube, and 23 more platforms with a single command", - "image": [ - { "id": "t2", "path": "https://cdn.example.com/multi-platform.jpg" } - ], - "delay": 3000 - }, - { - "content": "2️⃣ Thread creation\nEasily create Twitter threads, each tweet with its own media", - "image": [ - { "id": "t3", "path": "https://cdn.example.com/threads.jpg" } - ], - "delay": 3000 - }, - { - "content": "3️⃣ Provider-specific settings\nReddit subreddits, YouTube visibility, TikTok privacy - all configurable\n\nGet started: https://github.com/yourrepo", - "image": [], - "delay": 3000 - } - ], - "settings": { - "__type": "x", - "who_can_reply_post": "everyone" - } - }, - { - "integration": { "id": "linkedin-integration-id" }, - "value": [{ - "content": "Excited to announce the launch of Postiz CLI! 🎉\n\nAs developers, we know how time-consuming social media management can be. That's why we built a powerful CLI tool that makes scheduling posts across 28+ platforms effortless.\n\nKey features:\n• Multi-platform support (Twitter, LinkedIn, Reddit, TikTok, YouTube, and more)\n• Thread and carousel creation\n• Scheduled posting with precise timing\n• Provider-specific settings and customization\n• Built for AI agents and automation\n\nWhether you're managing a personal brand, running marketing campaigns, or building AI-powered social media tools, Postiz CLI has you covered.\n\nCheck it out and let us know your thoughts!", - "image": [ - { "id": "l1", "path": "https://cdn.example.com/linkedin-slide1.jpg" }, - { "id": "l2", "path": "https://cdn.example.com/linkedin-slide2.jpg" }, - { "id": "l3", "path": "https://cdn.example.com/linkedin-slide3.jpg" } - ] - }], - "settings": { - "__type": "linkedin", - "post_as_images_carousel": true, - "carousel_name": "Postiz CLI Launch" - } - }, - { - "integration": { "id": "instagram-integration-id" }, - "value": [{ - "content": "🚀 New launch alert!\n\nPostiz CLI is here - automate your social media like a pro.\n\n✨ 28+ platforms\n📅 Scheduled posting\n🧵 Thread creation\n⚙️ Full customization\n\nLink in bio! #developer #automation #socialmedia #tech", - "image": [ - { "id": "i1", "path": "https://cdn.example.com/instagram-post.jpg" } - ] - }], - "settings": { - "__type": "instagram", - "post_type": "post", - "is_trial_reel": false - } - } - ] -} diff --git a/apps/cli/examples/post-with-comments.json b/apps/cli/examples/post-with-comments.json deleted file mode 100644 index dd2e92bc..00000000 --- a/apps/cli/examples/post-with-comments.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [ - { - "integration": { - "id": "your-integration-id-here" - }, - "value": [ - { - "content": "This is the main post content 🚀", - "image": [ - { - "id": "img1", - "path": "https://example.com/main-image.jpg" - }, - { - "id": "img2", - "path": "https://example.com/secondary-image.jpg" - } - ] - }, - { - "content": "This is the first comment with its own media 📸", - "image": [ - { - "id": "img3", - "path": "https://example.com/comment1-image.jpg" - } - ], - "delay": 5000 - }, - { - "content": "This is the second comment with different media 🎨", - "image": [ - { - "id": "img4", - "path": "https://example.com/comment2-image1.jpg" - }, - { - "id": "img5", - "path": "https://example.com/comment2-image2.jpg" - } - ], - "delay": 10000 - } - ], - "settings": { - "__type": "EmptySettings" - } - } - ] -} diff --git a/apps/cli/examples/reddit-post.json b/apps/cli/examples/reddit-post.json deleted file mode 100644 index c55d4f31..00000000 --- a/apps/cli/examples/reddit-post.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { - "id": "your-reddit-integration-id" - }, - "value": [{ - "content": "I built a CLI tool for Postiz that makes social media scheduling super easy!\n\nYou can create posts, schedule them, and even post to multiple platforms at once. It supports comments with their own media, threads, and much more.\n\nCheck it out and let me know what you think!", - "image": [] - }], - "settings": { - "__type": "reddit", - "subreddit": [{ - "value": { - "subreddit": "programming", - "title": "Built a CLI tool for social media scheduling with TypeScript", - "type": "text", - "url": "", - "is_flair_required": false - } - }] - } - }] -} diff --git a/apps/cli/examples/thread-post.json b/apps/cli/examples/thread-post.json deleted file mode 100644 index f2cf9435..00000000 --- a/apps/cli/examples/thread-post.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [ - { - "integration": { - "id": "twitter-integration-id" - }, - "value": [ - { - "content": "🧵 Thread: How to use Postiz CLI for automated social media posting (1/5)", - "image": [ - { - "id": "tutorial1", - "path": "https://example.com/tutorial-intro.jpg" - } - ] - }, - { - "content": "Step 1: Install the CLI and set your API key\n\nexport POSTIZ_API_KEY=your_key\npnpm install -g postiz (2/5)", - "image": [ - { - "id": "tutorial2", - "path": "https://example.com/tutorial-install.jpg" - } - ], - "delay": 2000 - }, - { - "content": "Step 2: List your connected integrations to get their IDs\n\npostiz integrations:list (3/5)", - "image": [ - { - "id": "tutorial3", - "path": "https://example.com/tutorial-integrations.jpg" - } - ], - "delay": 2000 - }, - { - "content": "Step 3: Create your first post\n\npostiz posts:create -c \"Hello World!\" -i \"twitter-123\" (4/5)", - "image": [ - { - "id": "tutorial4", - "path": "https://example.com/tutorial-create.jpg" - } - ], - "delay": 2000 - }, - { - "content": "That's it! You can now automate your social media posts with ease. Check out our docs for more advanced features! 🚀 (5/5)", - "image": [ - { - "id": "tutorial5", - "path": "https://example.com/tutorial-done.jpg" - } - ], - "delay": 2000 - } - ], - "settings": { - "__type": "EmptySettings" - } - } - ] -} diff --git a/apps/cli/examples/tiktok-video.json b/apps/cli/examples/tiktok-video.json deleted file mode 100644 index cc5bd062..00000000 --- a/apps/cli/examples/tiktok-video.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "now", - "date": "2024-01-15T12:00:00Z", - "shortLink": true, - "tags": [], - "posts": [{ - "integration": { - "id": "your-tiktok-integration-id" - }, - "value": [{ - "content": "Quick tip: Automate your social media with this CLI tool! 🚀\n\n#coding #programming #typescript #developer #tech", - "image": [{ - "id": "video1", - "path": "https://cdn.example.com/tiktok-video.mp4" - }] - }], - "settings": { - "__type": "tiktok", - "title": "Automate Social Media with CLI", - "privacy_level": "PUBLIC_TO_EVERYONE", - "duet": true, - "stitch": true, - "comment": true, - "autoAddMusic": "no", - "brand_content_toggle": false, - "brand_organic_toggle": false, - "video_made_with_ai": false, - "content_posting_method": "DIRECT_POST" - } - }] -} diff --git a/apps/cli/examples/youtube-video.json b/apps/cli/examples/youtube-video.json deleted file mode 100644 index aa6cf3f2..00000000 --- a/apps/cli/examples/youtube-video.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "type": "schedule", - "date": "2024-12-25T09:00:00Z", - "shortLink": true, - "tags": [ - { "value": "tutorial", "label": "Tutorial" }, - { "value": "tech", "label": "Tech" } - ], - "posts": [{ - "integration": { - "id": "your-youtube-integration-id" - }, - "value": [{ - "content": "In this video, I'll show you how to build a powerful CLI tool for social media automation.\n\n⏱️ Timestamps:\n0:00 - Introduction\n2:15 - Setting up the project\n5:30 - Building the API client\n10:45 - Creating commands\n15:20 - Testing and deployment\n\n📚 Resources:\n- GitHub: https://github.com/yourrepo\n- Documentation: https://docs.example.com\n\n🔔 Subscribe for more TypeScript tutorials!", - "image": [{ - "id": "thumbnail1", - "path": "https://cdn.example.com/thumbnail.jpg" - }] - }], - "settings": { - "__type": "youtube", - "title": "Building a Social Media CLI Tool with TypeScript", - "type": "public", - "selfDeclaredMadeForKids": "no", - "tags": [ - { "value": "typescript", "label": "TypeScript" }, - { "value": "cli", "label": "CLI" }, - { "value": "tutorial", "label": "Tutorial" }, - { "value": "programming", "label": "Programming" }, - { "value": "nodejs", "label": "Node.js" } - ] - } - }] -} diff --git a/apps/cli/package.json b/apps/cli/package.json deleted file mode 100644 index 8fb64cc4..00000000 --- a/apps/cli/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "postiz", - "version": "2.0.5", - "description": "Postiz CLI - Command line interface for the Postiz social media scheduling API", - "main": "dist/index.js", - "bin": { - "postiz": "./dist/index.js" - }, - "scripts": { - "dev": "tsup --watch", - "build": "tsup", - "start": "node ./dist/index.js", - "publish": "tsup && pnpm publish --access public --no-git-checks" - }, - "files": [ - "dist", - "README.md", - "SKILL.md" - ], - "keywords": [ - "postiz", - "cli", - "social media", - "scheduling", - "automation", - "ai-agent", - "command-line" - ], - "author": "Nevo David", - "license": "AGPL-3.0", - "repository": { - "type": "git", - "url": "https://github.com/gitroomhq/postiz-app.git", - "directory": "apps/cli" - }, - "homepage": "https://postiz.com", - "bugs": { - "url": "https://github.com/gitroomhq/postiz-app/issues" - } -} diff --git a/apps/cli/src/api.ts b/apps/cli/src/api.ts deleted file mode 100644 index 0daa21c6..00000000 --- a/apps/cli/src/api.ts +++ /dev/null @@ -1,162 +0,0 @@ -import fetch, { FormData } from 'node-fetch'; - -export interface PostizConfig { - apiKey: string; - apiUrl?: string; -} - -export class PostizAPI { - private apiKey: string; - private apiUrl: string; - - constructor(config: PostizConfig) { - this.apiKey = config.apiKey; - this.apiUrl = config.apiUrl || 'https://api.postiz.com'; - } - - private async request(endpoint: string, options: any = {}) { - const url = `${this.apiUrl}${endpoint}`; - const headers = { - 'Content-Type': 'application/json', - Authorization: this.apiKey, - ...options.headers, - }; - - try { - const response = await fetch(url, { - ...options, - headers, - }); - - if (!response.ok) { - const error = await response.text(); - throw new Error(`API Error (${response.status}): ${error}`); - } - - return await response.json(); - } catch (error: any) { - throw new Error(`Request failed: ${error.message}`); - } - } - - async createPost(data: any) { - return this.request('/public/v1/posts', { - method: 'POST', - body: JSON.stringify(data), - }); - } - - async listPosts(filters: any = {}) { - const queryString = new URLSearchParams( - Object.entries(filters).reduce((acc, [key, value]) => { - if (value !== undefined && value !== null) { - acc[key] = String(value); - } - return acc; - }, {} as Record) - ).toString(); - - const endpoint = queryString - ? `/public/v1/posts?${queryString}` - : '/public/v1/posts'; - - return this.request(endpoint, { - method: 'GET', - }); - } - - async deletePost(id: string) { - return this.request(`/public/v1/posts/${id}`, { - method: 'DELETE', - }); - } - - async upload(file: Buffer, filename: string) { - const formData = new FormData(); - const extension = filename.split('.').pop()?.toLowerCase() || ''; - - // Determine MIME type based on file extension - const mimeTypes: Record = { - // Images - 'png': 'image/png', - 'jpg': 'image/jpeg', - 'jpeg': 'image/jpeg', - 'gif': 'image/gif', - 'webp': 'image/webp', - 'svg': 'image/svg+xml', - 'bmp': 'image/bmp', - 'ico': 'image/x-icon', - - // Videos - 'mp4': 'video/mp4', - 'mov': 'video/quicktime', - 'avi': 'video/x-msvideo', - 'mkv': 'video/x-matroska', - 'webm': 'video/webm', - 'flv': 'video/x-flv', - 'wmv': 'video/x-ms-wmv', - 'm4v': 'video/x-m4v', - 'mpeg': 'video/mpeg', - 'mpg': 'video/mpeg', - '3gp': 'video/3gpp', - - // Audio - 'mp3': 'audio/mpeg', - 'wav': 'audio/wav', - 'ogg': 'audio/ogg', - 'aac': 'audio/aac', - 'flac': 'audio/flac', - 'm4a': 'audio/mp4', - - // Documents - 'pdf': 'application/pdf', - 'doc': 'application/msword', - 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - }; - - const type = mimeTypes[extension] || 'application/octet-stream'; - - const blob = new Blob([file], { type }); - formData.append('file', blob, filename); - - const url = `${this.apiUrl}/public/v1/upload`; - const response = await fetch(url, { - method: 'POST', - // @ts-ignore - body: formData, - headers: { - Authorization: this.apiKey, - }, - }); - - if (!response.ok) { - const error = await response.text(); - throw new Error(`Upload failed (${response.status}): ${error}`); - } - - return await response.json(); - } - - async listIntegrations() { - return this.request('/public/v1/integrations', { - method: 'GET', - }); - } - - async getIntegrationSettings(integrationId: string) { - return this.request(`/public/v1/integration-settings/${integrationId}`, { - method: 'GET', - }); - } - - async triggerIntegrationTool( - integrationId: string, - methodName: string, - data: Record - ) { - return this.request(`/public/v1/integration-trigger/${integrationId}`, { - method: 'POST', - body: JSON.stringify({ methodName, data }), - }); - } -} diff --git a/apps/cli/src/commands/integrations.ts b/apps/cli/src/commands/integrations.ts deleted file mode 100644 index 60cdc203..00000000 --- a/apps/cli/src/commands/integrations.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { PostizAPI } from '../api'; -import { getConfig } from '../config'; - -export async function listIntegrations() { - const config = getConfig(); - const api = new PostizAPI(config); - - try { - const result = await api.listIntegrations(); - console.log('🔌 Connected Integrations:'); - console.log(JSON.stringify(result, null, 2)); - return result; - } catch (error: any) { - console.error('❌ Failed to list integrations:', error.message); - process.exit(1); - } -} - -export async function getIntegrationSettings(args: any) { - const config = getConfig(); - const api = new PostizAPI(config); - - if (!args.id) { - console.error('❌ Integration ID is required'); - process.exit(1); - } - - try { - const result = await api.getIntegrationSettings(args.id); - console.log(`⚙️ Settings for integration: ${args.id}`); - console.log(JSON.stringify(result, null, 2)); - return result; - } catch (error: any) { - console.error('❌ Failed to get integration settings:', error.message); - process.exit(1); - } -} - -export async function triggerIntegrationTool(args: any) { - const config = getConfig(); - const api = new PostizAPI(config); - - if (!args.id) { - console.error('❌ Integration ID is required'); - process.exit(1); - } - - if (!args.method) { - console.error('❌ Method name is required'); - process.exit(1); - } - - // Parse data from JSON string or use empty object - let data: Record = {}; - if (args.data) { - try { - data = JSON.parse(args.data); - } catch (error: any) { - console.error('❌ Failed to parse data JSON:', error.message); - process.exit(1); - } - } - - try { - const result = await api.triggerIntegrationTool(args.id, args.method, data); - console.log(`🔧 Tool result for ${args.method}:`); - console.log(JSON.stringify(result, null, 2)); - return result; - } catch (error: any) { - console.error('❌ Failed to trigger tool:', error.message); - process.exit(1); - } -} diff --git a/apps/cli/src/commands/posts.ts b/apps/cli/src/commands/posts.ts deleted file mode 100644 index 2cc9c316..00000000 --- a/apps/cli/src/commands/posts.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { PostizAPI } from '../api'; -import { getConfig } from '../config'; -import { readFileSync, existsSync } from 'fs'; - -export async function createPost(args: any) { - const config = getConfig(); - const api = new PostizAPI(config); - - // Support both simple and complex post creation - let postData: any; - - if (args.json) { - // Load from JSON file for complex posts with comments and media - try { - const jsonPath = args.json; - if (!existsSync(jsonPath)) { - console.error(`❌ JSON file not found: ${jsonPath}`); - process.exit(1); - } - const jsonContent = readFileSync(jsonPath, 'utf-8'); - postData = JSON.parse(jsonContent); - } catch (error: any) { - console.error('❌ Failed to parse JSON file:', error.message); - process.exit(1); - } - } else { - const integrations = args.integrations - ? args.integrations.split(',').map((id: string) => id.trim()) - : []; - - if (integrations.length === 0) { - console.error('❌ At least one integration ID is required'); - console.error('Use -i or --integrations to specify integration IDs'); - console.error('Run "postiz integrations:list" to see available integrations'); - process.exit(1); - } - - // Support multiple -c and -m flags - // Normalize to arrays - const contents = Array.isArray(args.content) ? args.content : [args.content]; - const medias = Array.isArray(args.media) ? args.media : (args.media ? [args.media] : []); - - if (!contents[0]) { - console.error('❌ At least one -c/--content is required'); - process.exit(1); - } - - // Build value array by pairing contents with their media - const values = contents.map((content: string, index: number) => { - const mediaForThisContent = medias[index]; - const images = mediaForThisContent - ? mediaForThisContent.split(',').map((img: string) => ({ - id: Math.random().toString(36).substring(7), - path: img.trim(), - })) - : []; - - return { - content: content, - image: images, - // Add delay for all items except the first (main post) - ...(index > 0 && { delay: args.delay || 5000 }), - }; - }); - - // Parse provider-specific settings if provided - // Note: __type is automatically added by the backend based on integration ID - let settings: any = undefined; - - if (args.settings) { - try { - settings = typeof args.settings === 'string' - ? JSON.parse(args.settings) - : args.settings; - } catch (error: any) { - console.error('❌ Failed to parse settings JSON:', error.message); - process.exit(1); - } - } - - // Build the proper post structure - postData = { - type: args.type || 'schedule', // 'schedule' or 'draft' - date: args.date, // Required date field - shortLink: args.shortLink !== false, - tags: [], - posts: integrations.map((integrationId: string) => ({ - integration: { id: integrationId }, - value: values, - settings: settings, - })), - }; - } - - try { - const result = await api.createPost(postData); - console.log('✅ Post created successfully!'); - console.log(JSON.stringify(result, null, 2)); - return result; - } catch (error: any) { - console.error('❌ Failed to create post:', error.message); - process.exit(1); - } -} - -export async function listPosts(args: any) { - const config = getConfig(); - const api = new PostizAPI(config); - - // Set default date range: last 30 days to 30 days in the future - const defaultStartDate = new Date(); - defaultStartDate.setDate(defaultStartDate.getDate() - 30); - - const defaultEndDate = new Date(); - defaultEndDate.setDate(defaultEndDate.getDate() + 30); - - // Only send fields that are in GetPostsDto - const filters: any = { - startDate: args.startDate || defaultStartDate.toISOString(), - endDate: args.endDate || defaultEndDate.toISOString(), - }; - - // customer is optional in the DTO - if (args.customer) { - filters.customer = args.customer; - } - - try { - const result = await api.listPosts(filters); - console.log('📋 Posts:'); - console.log(JSON.stringify(result, null, 2)); - return result; - } catch (error: any) { - console.error('❌ Failed to list posts:', error.message); - process.exit(1); - } -} - -export async function deletePost(args: any) { - const config = getConfig(); - const api = new PostizAPI(config); - - if (!args.id) { - console.error('❌ Post ID is required'); - process.exit(1); - } - - try { - await api.deletePost(args.id); - console.log(`✅ Post ${args.id} deleted successfully!`); - } catch (error: any) { - console.error('❌ Failed to delete post:', error.message); - process.exit(1); - } -} diff --git a/apps/cli/src/commands/upload.ts b/apps/cli/src/commands/upload.ts deleted file mode 100644 index 6773fbdd..00000000 --- a/apps/cli/src/commands/upload.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { PostizAPI } from '../api'; -import { getConfig } from '../config'; -import { readFileSync } from 'fs'; - -export async function uploadFile(args: any) { - const config = getConfig(); - const api = new PostizAPI(config); - - if (!args.file) { - console.error('❌ File path is required'); - process.exit(1); - } - - try { - const fileBuffer = readFileSync(args.file); - const filename = args.file.split('/').pop() || 'file'; - - const result = await api.upload(fileBuffer, filename); - console.log('✅ File uploaded successfully!'); - console.log(JSON.stringify(result, null, 2)); - return result; - } catch (error: any) { - console.error('❌ Failed to upload file:', error.message); - process.exit(1); - } -} diff --git a/apps/cli/src/config.ts b/apps/cli/src/config.ts deleted file mode 100644 index 3813e8cf..00000000 --- a/apps/cli/src/config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PostizConfig } from './api'; - -export function getConfig(): PostizConfig { - const apiKey = process.env.POSTIZ_API_KEY; - const apiUrl = process.env.POSTIZ_API_URL; - - if (!apiKey) { - console.error('❌ Error: POSTIZ_API_KEY environment variable is required'); - console.error('Please set it using: export POSTIZ_API_KEY=your_api_key'); - process.exit(1); - } - - return { - apiKey, - apiUrl, - }; -} diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts deleted file mode 100644 index 3de9dd76..00000000 --- a/apps/cli/src/index.ts +++ /dev/null @@ -1,240 +0,0 @@ -import yargs from 'yargs'; -import { hideBin } from 'yargs/helpers'; -import { createPost, listPosts, deletePost } from './commands/posts'; -import { listIntegrations, getIntegrationSettings, triggerIntegrationTool } from './commands/integrations'; -import { uploadFile } from './commands/upload'; -import type { Argv } from 'yargs'; - -yargs(hideBin(process.argv)) - .scriptName('postiz') - .usage('$0 [options]') - .command( - 'posts:create', - 'Create a new post', - (yargs: Argv) => { - return yargs - .option('content', { - alias: 'c', - describe: 'Post/comment content (can be used multiple times)', - type: 'string', - }) - .option('media', { - alias: 'm', - describe: 'Comma-separated media URLs for the corresponding -c (can be used multiple times)', - type: 'string', - }) - .option('integrations', { - alias: 'i', - describe: 'Comma-separated list of integration IDs', - type: 'string', - }) - .option('date', { - alias: 's', - describe: 'Schedule date (ISO 8601 format) - REQUIRED', - type: 'string', - }) - .option('type', { - alias: 't', - describe: 'Post type: "schedule" or "draft"', - type: 'string', - choices: ['schedule', 'draft'], - default: 'schedule', - }) - .option('delay', { - alias: 'd', - describe: 'Delay in milliseconds between comments (default: 5000)', - type: 'number', - default: 5000, - }) - .option('json', { - alias: 'j', - describe: 'Path to JSON file with full post structure', - type: 'string', - }) - .option('shortLink', { - describe: 'Use short links', - type: 'boolean', - default: true, - }) - .option('settings', { - describe: 'Platform-specific settings as JSON string', - type: 'string', - }) - .check((argv) => { - if (!argv.json && !argv.content) { - throw new Error('Either --content or --json is required'); - } - if (!argv.json && !argv.integrations) { - throw new Error('--integrations is required when not using --json'); - } - if (!argv.json && !argv.date) { - throw new Error('--date is required when not using --json'); - } - return true; - }) - .example( - '$0 posts:create -c "Hello World!" -s "2024-12-31T12:00:00Z" -i "twitter-123"', - 'Simple scheduled post' - ) - .example( - '$0 posts:create -c "Draft post" -s "2024-12-31T12:00:00Z" -t draft -i "twitter-123"', - 'Create draft post' - ) - .example( - '$0 posts:create -c "Main post" -m "img1.jpg,img2.jpg" -s "2024-12-31T12:00:00Z" -i "twitter-123"', - 'Post with multiple images' - ) - .example( - '$0 posts:create -c "Main post" -m "img1.jpg" -c "First comment" -m "img2.jpg" -c "Second comment" -m "img3.jpg,img4.jpg" -s "2024-12-31T12:00:00Z" -i "twitter-123"', - 'Post with comments, each having their own media' - ) - .example( - '$0 posts:create -c "Main" -c "Comment with semicolon; see?" -c "Another!" -s "2024-12-31T12:00:00Z" -i "twitter-123"', - 'Comments can contain semicolons' - ) - .example( - '$0 posts:create -c "Thread 1/3" -c "Thread 2/3" -c "Thread 3/3" -d 2000 -s "2024-12-31T12:00:00Z" -i "twitter-123"', - 'Twitter thread with 2s delay' - ) - .example( - '$0 posts:create --json ./post.json', - 'Complex post from JSON file' - ) - .example( - '$0 posts:create -c "Post to subreddit" -s "2024-12-31T12:00:00Z" --settings \'{"subreddit":[{"value":{"subreddit":"programming","title":"My Title","type":"text","url":"","is_flair_required":false}}]}\' -i "reddit-123"', - 'Reddit post with specific subreddit settings' - ) - .example( - '$0 posts:create -c "Video description" -s "2024-12-31T12:00:00Z" --settings \'{"title":"My Video","type":"public","tags":[{"value":"tech","label":"Tech"}]}\' -i "youtube-123"', - 'YouTube post with title and tags' - ) - .example( - '$0 posts:create -c "Tweet content" -s "2024-12-31T12:00:00Z" --settings \'{"who_can_reply_post":"everyone"}\' -i "twitter-123"', - 'X (Twitter) post with reply settings' - ); - }, - createPost as any - ) - .command( - 'posts:list', - 'List all posts', - (yargs: Argv) => { - return yargs - .option('startDate', { - describe: 'Start date (ISO 8601 format). Default: 30 days ago', - type: 'string', - }) - .option('endDate', { - describe: 'End date (ISO 8601 format). Default: 30 days from now', - type: 'string', - }) - .option('customer', { - describe: 'Customer ID (optional)', - type: 'string', - }) - .example('$0 posts:list', 'List all posts (last 30 days to next 30 days)') - .example( - '$0 posts:list --startDate "2024-01-01T00:00:00Z" --endDate "2024-12-31T23:59:59Z"', - 'List posts for a specific date range' - ) - .example( - '$0 posts:list --customer "customer-id"', - 'List posts for a specific customer' - ); - }, - listPosts as any - ) - .command( - 'posts:delete ', - 'Delete a post', - (yargs: Argv) => { - return yargs - .positional('id', { - describe: 'Post ID to delete', - type: 'string', - }) - .example('$0 posts:delete abc123', 'Delete post with ID abc123'); - }, - deletePost as any - ) - .command( - 'integrations:list', - 'List all connected integrations', - {}, - listIntegrations as any - ) - .command( - 'integrations:settings ', - 'Get settings schema for a specific integration', - (yargs: Argv) => { - return yargs - .positional('id', { - describe: 'Integration ID', - type: 'string', - }) - .example( - '$0 integrations:settings reddit-123', - 'Get settings schema for Reddit integration' - ) - .example( - '$0 integrations:settings youtube-456', - 'Get settings schema for YouTube integration' - ); - }, - getIntegrationSettings as any - ) - .command( - 'integrations:trigger ', - 'Trigger an integration tool to fetch additional data', - (yargs: Argv) => { - return yargs - .positional('id', { - describe: 'Integration ID', - type: 'string', - }) - .positional('method', { - describe: 'Method name from the integration tools', - type: 'string', - }) - .option('data', { - alias: 'd', - describe: 'Data to pass to the tool as JSON string', - type: 'string', - }) - .example( - '$0 integrations:trigger reddit-123 getSubreddits', - 'Get list of subreddits' - ) - .example( - '$0 integrations:trigger reddit-123 searchSubreddits -d \'{"query":"programming"}\'', - 'Search for subreddits' - ) - .example( - '$0 integrations:trigger youtube-123 getPlaylists', - 'Get YouTube playlists' - ); - }, - triggerIntegrationTool as any - ) - .command( - 'upload ', - 'Upload a file', - (yargs: Argv) => { - return yargs - .positional('file', { - describe: 'File path to upload', - type: 'string', - }) - .example('$0 upload ./image.png', 'Upload an image'); - }, - uploadFile as any - ) - .demandCommand(1, 'You need at least one command') - .help() - .alias('h', 'help') - .version() - .alias('v', 'version') - .epilogue( - 'For more information, visit: https://postiz.com\n\nSet your API key: export POSTIZ_API_KEY=your_api_key' - ) - .parse(); diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json deleted file mode 100644 index 1df422c5..00000000 --- a/apps/cli/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "module": "commonjs", - "declaration": true, - "removeComments": true, - "allowSyntheticDefaultImports": true, - "target": "es2017", - "sourceMap": true, - "esModuleInterop": true, - "rootDir": "../../", - "incremental": false - }, - "include": ["src"] -} diff --git a/apps/cli/tsup.config.ts b/apps/cli/tsup.config.ts deleted file mode 100644 index 68035c7c..00000000 --- a/apps/cli/tsup.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from 'tsup'; - -export default defineConfig({ - entry: ['src/index.ts'], - format: ['cjs'], - dts: false, // Disable DTS generation to avoid type issues - splitting: false, - sourcemap: true, - clean: true, - outDir: 'dist', - banner: { - js: '#!/usr/bin/env node', - }, -}); diff --git a/libraries/nestjs-libraries/src/chat/start.mcp.ts b/libraries/nestjs-libraries/src/chat/start.mcp.ts index 3b4d4b42..31231715 100644 --- a/libraries/nestjs-libraries/src/chat/start.mcp.ts +++ b/libraries/nestjs-libraries/src/chat/start.mcp.ts @@ -60,6 +60,13 @@ export const startMcp = async (app: INestApplication) => { mcpPath: '/mcp-oauth', }); + if (process.env.OPENAI_APP_CHALLANGE) { + app.use('/.well-known/openai-apps-challenge', (req: Request, res: Response) => { + res.setHeader('Content-Type', 'text/plain'); + res.send(process.env.OPENAI_APP_CHALLANGE); + }); + } + app.use('/.well-known/oauth-protected-resource', async (req: Request, res: Response) => { const url = new URL('/.well-known/oauth-protected-resource', process.env.NEXT_PUBLIC_BACKEND_URL); await oauthMiddleware(req, res, url); diff --git a/package.json b/package.json index fd6640ab..27e4b543 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "dev-backend": "pnpm run --filter ./apps/backend --filter ./apps/frontend --parallel dev", "pm2": "pnpm run pm2-run", "publish-sdk": "pnpm run --filter ./apps/sdk publish", - "publish-cli": "pnpm run --filter ./apps/cli publish", "pm2-run": "pm2 delete all || true && pnpm run prisma-db-push && pnpm run --parallel pm2 && pm2 logs", "dev:stripe": "pnpm dlx concurrently \"stripe listen --forward-to localhost:3000/stripe\" \"pnpm run dev\"", "build": "pnpm -r --workspace-concurrency=1 --filter ./apps/frontend --filter ./apps/backend --filter ./apps/orchestrator run build", @@ -23,7 +22,6 @@ "build:frontend": "rm -rf apps/frontend/dist && pnpm --filter ./apps/frontend run build", "build:orchestrator": "rm -rf apps/orchestrator/dist && pnpm --filter ./apps/orchestrator run build", "build:extension": "rm -rf apps/extension/dist && pnpm --filter ./apps/extension run build", - "build:cli": "rm -rf apps/cli/dist && pnpm --filter ./apps/cli run build", "dev:backend": "rm -rf apps/backend/dist && pnpm --filter ./apps/backend run dev", "dev:frontend": "rm -rf apps/frontend/dist && pnpm --filter ./apps/frontend run dev", "dev:orchestrator": "rm -rf apps/orchestrator/dist && pnpm --filter ./apps/orchestrator run dev", From af8d04002c709981b70b8711621ce3fb2698da8d Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sat, 4 Apr 2026 12:46:50 +0200 Subject: [PATCH 11/80] feat: gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9ad2f651..0d7684f2 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ node_modules .vscode/* # IDE - VSCode -.vscode/* +.vscode/ !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json From 943293dc7dcdfcae7b58e77957fc348a166890af Mon Sep 17 00:00:00 2001 From: swaraj017 Date: Mon, 6 Apr 2026 23:33:26 +0530 Subject: [PATCH 12/80] fix(youtube): preserve existing refresh token to avoid daily re-auth --- .../src/integrations/social/youtube.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/youtube.provider.ts b/libraries/nestjs-libraries/src/integrations/social/youtube.provider.ts index 0254c429..1a7f33fa 100644 --- a/libraries/nestjs-libraries/src/integrations/social/youtube.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/youtube.provider.ts @@ -150,7 +150,7 @@ export class YoutubeProvider extends SocialAbstract implements SocialProvider { return { accessToken: credentials.access_token!, expiresIn: unixTimestamp!, - refreshToken: credentials.refresh_token!, + refreshToken: credentials.refresh_token ?? refresh_token, id: data.id!, name: data.name!, picture: data?.picture || '', From c7867ab05eaec1659cb76d29ee2e4b4426cbcee7 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Tue, 7 Apr 2026 18:05:30 +0700 Subject: [PATCH 13/80] feat: download invoices --- .../src/components/layout/impersonate.tsx | 31 +++++++++++++++++++ .../src/services/stripe.service.ts | 28 ++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/components/layout/impersonate.tsx b/apps/frontend/src/components/layout/impersonate.tsx index d50f3e06..7f9bf46d 100644 --- a/apps/frontend/src/components/layout/impersonate.tsx +++ b/apps/frontend/src/components/layout/impersonate.tsx @@ -22,6 +22,8 @@ interface Charge { refunded: boolean; amount_refunded: number; description: string | null; + receipt_url: string | null; + invoice_pdf: string | null; } const useCharges = () => { @@ -124,6 +126,7 @@ const ChargesModal: FC<{ close: () => void }> = ({ close }) => { {t('date', 'Date')} {t('amount', 'Amount')} {t('status', 'Status')} + @@ -178,6 +181,34 @@ const ChargesModal: FC<{ close: () => void }> = ({ close }) => { )} + + {(charge.invoice_pdf || charge.receipt_url) && ( + e.stopPropagation()} + className="inline-flex items-center justify-center w-[28px] h-[28px] rounded-[4px] hover:bg-tableBorder transition-colors" + title={charge.invoice_pdf ? t('download_invoice', 'Download Invoice') : t('view_receipt', 'View Receipt')} + > + + + + + + + )} + ))} diff --git a/libraries/nestjs-libraries/src/services/stripe.service.ts b/libraries/nestjs-libraries/src/services/stripe.service.ts index 05fa74df..f21bd66c 100644 --- a/libraries/nestjs-libraries/src/services/stripe.service.ts +++ b/libraries/nestjs-libraries/src/services/stripe.service.ts @@ -856,7 +856,7 @@ export class StripeService { limit: 100, }); - return charges.data + const chargeList = charges.data .filter((f) => f.status === 'succeeded') .map((charge) => ({ id: charge.id, @@ -867,7 +867,33 @@ export class StripeService { refunded: charge.refunded, amount_refunded: charge.amount_refunded, description: charge.description, + receipt_url: charge.receipt_url || null, + invoice: (charge as any).invoice || null, })); + + const invoiceIds = chargeList + .map((c) => c.invoice) + .filter((id): id is string => !!id && typeof id === 'string'); + + const invoicePdfMap: Record = {}; + for (const invoiceId of invoiceIds) { + try { + const inv = await stripe.invoices.retrieve(invoiceId); + if (inv.invoice_pdf) { + invoicePdfMap[invoiceId] = inv.invoice_pdf; + } + } catch { + // ignore if invoice can't be fetched + } + } + + return chargeList.map((charge) => ({ + ...charge, + invoice_pdf: + charge.invoice && invoicePdfMap[charge.invoice as string] + ? invoicePdfMap[charge.invoice as string] + : null, + })); } async refundCharges(organizationId: string, chargeIds: string[]) { From a8918a628437d90e527be6ff445c49064d5f856b Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Wed, 8 Apr 2026 12:24:30 +0200 Subject: [PATCH 14/80] feat: update pr quality --- .github/workflows/pr-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-quality.yml b/.github/workflows/pr-quality.yml index 10768ebb..e5efb65b 100644 --- a/.github/workflows/pr-quality.yml +++ b/.github/workflows/pr-quality.yml @@ -42,7 +42,7 @@ jobs: # Exemptions exempt-author-association: "OWNER,MEMBER,COLLABORATOR" - exempt-users: "nevo-david,egelhaus" + exempt-users: "nevo-david,egelhaus,postiz-agent,postiz-agent[bot]" exempt-bots: true # Actions From 59e535e2583574407e8f07cc84b87d46d976f7d4 Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Wed, 8 Apr 2026 12:25:49 +0200 Subject: [PATCH 15/80] fix: pr quality --- .github/workflows/pr-quality.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-quality.yml b/.github/workflows/pr-quality.yml index e5efb65b..3fdc958b 100644 --- a/.github/workflows/pr-quality.yml +++ b/.github/workflows/pr-quality.yml @@ -42,8 +42,8 @@ jobs: # Exemptions exempt-author-association: "OWNER,MEMBER,COLLABORATOR" - exempt-users: "nevo-david,egelhaus,postiz-agent,postiz-agent[bot]" - exempt-bots: true + exempt-users: "nevo-david,egelhaus" + exempt-bots: "postiz-agent[bot]" # Actions exempt-label: "exempt" From 30e8b777098157362769226d1b46d83ad616cb06 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Thu, 9 Apr 2026 18:11:07 +0700 Subject: [PATCH 16/80] feat: security fixes --- .../src/api/routes/public.controller.ts | 63 +++--- .../backend/src/services/auth/auth.service.ts | 3 + .../dtos/webhooks/webhook.url.validator.ts | 194 +++++++++--------- 3 files changed, 142 insertions(+), 118 deletions(-) diff --git a/apps/backend/src/api/routes/public.controller.ts b/apps/backend/src/api/routes/public.controller.ts index 018ad0f4..698f5c75 100644 --- a/apps/backend/src/api/routes/public.controller.ts +++ b/apps/backend/src/api/routes/public.controller.ts @@ -10,7 +10,6 @@ import { StreamableFile, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; -import { AgenciesService } from '@gitroom/nestjs-libraries/database/prisma/agencies/agencies.service'; import { PostsService } from '@gitroom/nestjs-libraries/database/prisma/posts/posts.service'; import { TrackService } from '@gitroom/nestjs-libraries/track/track.service'; import { RealIP } from 'nestjs-real-ip'; @@ -27,6 +26,7 @@ import { pricing } from '@gitroom/nestjs-libraries/database/prisma/subscriptions import { Readable, pipeline } from 'stream'; import { promisify } from 'util'; import { OnlyURL } from '@gitroom/nestjs-libraries/dtos/webhooks/webhooks.dto'; +import { isSafePublicHttpsUrl } from '@gitroom/nestjs-libraries/dtos/webhooks/webhook.url.validator'; const pump = promisify(pipeline); @@ -34,7 +34,6 @@ const pump = promisify(pipeline); @Controller('/public') export class PublicController { constructor( - private _agenciesService: AgenciesService, private _trackService: TrackService, private _agentGraphInsertService: AgentGraphInsertService, private _postsService: PostsService, @@ -53,26 +52,6 @@ export class PublicController { return this._agentGraphInsertService.newPost(body.text); } - @Get('/agencies-list') - async getAgencyByUser() { - return this._agenciesService.getAllAgencies(); - } - - @Get('/agencies-list-slug') - async getAgencySlug() { - return this._agenciesService.getAllAgenciesSlug(); - } - - @Get('/agencies-information/:agency') - async getAgencyInformation(@Param('agency') agency: string) { - return this._agenciesService.getAgencyInformation(agency); - } - - @Get('/agencies-list-count') - async getAgenciesCount() { - return this._agenciesService.getCount(); - } - @Get(`/posts/:id`) async getPreview(@Param('id') id: string) { return (await this._postsService.getPostsRecursively(id, true)).map( @@ -198,7 +177,45 @@ export class PublicController { req.on('aborted', onClose); res.on('close', onClose); - const r = await fetch(url, { signal: ac.signal }); + // Manually follow redirects so every hop is re-validated against + // the SSRF blocklist (see GHSA-34w8-5j2v-h6ww). `fetch` defaults to + // `redirect: 'follow'`, which bypasses the DTO-level URL check. + const MAX_REDIRECTS = 5; + let currentUrl = url; + let r: globalThis.Response | undefined; + for (let hop = 0; hop <= MAX_REDIRECTS; hop++) { + if (!(await isSafePublicHttpsUrl(currentUrl))) { + return res.status(400).send('Blocked URL'); + } + + r = await fetch(currentUrl, { + signal: ac.signal, + redirect: 'manual', + }); + + if (r.status >= 300 && r.status < 400) { + const location = r.headers.get('location'); + if (!location) { + return res.status(502).send('Redirect without Location'); + } + try { + currentUrl = new URL(location, currentUrl).toString(); + } catch { + return res.status(400).send('Invalid redirect target'); + } + continue; + } + + break; + } + + if (!r) { + return res.status(502).send('No upstream response'); + } + + if (r.status >= 300 && r.status < 400) { + return res.status(508).send('Too many redirects'); + } if (!r.ok && r.status !== 206) { res.status(r.status); diff --git a/apps/backend/src/services/auth/auth.service.ts b/apps/backend/src/services/auth/auth.service.ts index e8e37fa0..5d4dd818 100644 --- a/apps/backend/src/services/auth/auth.service.ts +++ b/apps/backend/src/services/auth/auth.service.ts @@ -309,6 +309,9 @@ export class AuthService { } private async jwt(user: User) { + if (user.password) { + delete user.password; + } return AuthChecker.signJWT(user); } } diff --git a/libraries/nestjs-libraries/src/dtos/webhooks/webhook.url.validator.ts b/libraries/nestjs-libraries/src/dtos/webhooks/webhook.url.validator.ts index 3ce28433..d79be0e6 100644 --- a/libraries/nestjs-libraries/src/dtos/webhooks/webhook.url.validator.ts +++ b/libraries/nestjs-libraries/src/dtos/webhooks/webhook.url.validator.ts @@ -9,109 +9,113 @@ import { URL } from 'node:url'; import dns from 'node:dns/promises'; import net from 'node:net'; +export function isBlockedIPv4(ip: string): boolean { + const [a, b] = ip.split('.').map(Number); + + if ([a, b].some((n) => Number.isNaN(n))) return true; + + return ( + a === 0 || // 0.0.0.0/8 + a === 10 || // 10.0.0.0/8 + a === 127 || // 127.0.0.0/8 + (a === 169 && b === 254) || // 169.254.0.0/16 + (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 + (a === 192 && b === 168) || // 192.168.0.0/16 + (a === 100 && b >= 64 && b <= 127) || // 100.64.0.0/10 + (a === 198 && (b === 18 || b === 19)) || // 198.18.0.0/15 + a >= 224 // multicast/reserved + ); +} + +export function isBlockedIPv6(ip: string): boolean { + const normalized = ip.toLowerCase(); + + return ( + normalized === '::1' || // loopback + normalized === '::' || // unspecified + normalized.startsWith('fe80:') || // link-local + normalized.startsWith('fc') || // unique local fc00::/7 + normalized.startsWith('fd') || // unique local fd00::/7 + normalized.startsWith('ff') // multicast + ); +} + +export function isBlockedIp(ip: string): boolean { + const version = net.isIP(ip); + if (version === 4) { + return isBlockedIPv4(ip); + } + if (version === 6) { + // IPv4-mapped IPv6 (::ffff:a.b.c.d) — extract and check as IPv4 + const mapped = ip.toLowerCase().match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/); + if (mapped) { + return isBlockedIPv4(mapped[1]); + } + return isBlockedIPv6(ip); + } + return true; +} + +export async function isSafePublicHttpsUrl(value: unknown): Promise { + if (typeof value !== 'string' || !value.trim()) { + return false; + } + + let parsed: URL; + try { + parsed = new URL(value); + } catch { + return false; + } + + if (parsed.protocol !== 'https:') { + return false; + } + + if (!parsed.hostname) { + return false; + } + + const hostname = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, ''); + + if (hostname === 'localhost') { + return false; + } + + // If user supplied a literal IP directly, validate it immediately + const literalIpVersion = net.isIP(hostname); + if (literalIpVersion) { + return !isBlockedIp(hostname); + } + + try { + const records = await dns.lookup(hostname, { all: true }); + + if (!records.length) { + return false; + } + + for (const record of records) { + if (isBlockedIp(record.address)) { + return false; + } + } + + return true; + } catch { + return false; + } +} + @ValidatorConstraint({ name: 'IsSafeWebhookUrl', async: true }) export class IsSafeWebhookUrlConstraint implements ValidatorConstraintInterface { async validate(value: unknown, _args: ValidationArguments): Promise { - if (typeof value !== 'string' || !value.trim()) { - return false; - } - - let parsed: URL; - try { - parsed = new URL(value); - } catch { - return false; - } - - if (parsed.protocol !== 'https:') { - return false; - } - - if (!parsed.hostname) { - return false; - } - - const hostname = parsed.hostname.toLowerCase(); - - if (hostname === 'localhost') { - return false; - } - - // Optional: block explicit ports other than 443 - // if (parsed.port && parsed.port !== '443') { - // return false; - // } - - // If user supplied a literal IP directly, validate it immediately - const literalIpVersion = net.isIP(hostname); - if (literalIpVersion) { - return !this.isBlockedIp(hostname); - } - - try { - const records = await dns.lookup(hostname, { all: true }); - - if (!records.length) { - return false; - } - - for (const record of records) { - if (this.isBlockedIp(record.address)) { - return false; - } - } - - return true; - } catch { - return false; - } + return isSafePublicHttpsUrl(value); } defaultMessage(_args: ValidationArguments): string { return 'URL must be a public HTTPS URL and must not resolve to localhost, private, loopback, or link-local addresses'; } - - private isBlockedIp(ip: string): boolean { - const version = net.isIP(ip); - if (version === 4) { - return this.isBlockedIPv4(ip); - } - if (version === 6) { - return this.isBlockedIPv6(ip); - } - return true; - } - - private isBlockedIPv4(ip: string): boolean { - const [a, b] = ip.split('.').map(Number); - - if ([a, b].some((n) => Number.isNaN(n))) return true; - - return ( - a === 0 || // 0.0.0.0/8 - a === 10 || // 10.0.0.0/8 - a === 127 || // 127.0.0.0/8 - (a === 169 && b === 254) || // 169.254.0.0/16 - (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 - (a === 192 && b === 168) || // 192.168.0.0/16 - (a === 100 && b >= 64 && b <= 127) || // 100.64.0.0/10 - (a === 198 && (b === 18 || b === 19)) || // 198.18.0.0/15 - a >= 224 // multicast/reserved - ); - } - - private isBlockedIPv6(ip: string): boolean { - const normalized = ip.toLowerCase(); - - return ( - normalized === '::1' || // loopback - normalized === '::' || // unspecified - normalized.startsWith('fe80:') || // link-local - normalized.startsWith('fc') || // unique local fc00::/7 - normalized.startsWith('fd') || // unique local fd00::/7 - normalized.startsWith('ff') // multicast - ); - } } export function IsSafeWebhookUrl(validationOptions?: ValidationOptions) { From 3e8a0ab817ea50475f319797b1256ae9eba0e704 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Thu, 9 Apr 2026 18:28:44 +0700 Subject: [PATCH 17/80] feat: langchain upgrade --- .../src/agent/agent.graph.service.ts | 4 +- package.json | 9 +- pnpm-lock.yaml | 902 ++++++++++++++---- tsconfig.base.json | 1 + 4 files changed, 716 insertions(+), 200 deletions(-) diff --git a/libraries/nestjs-libraries/src/agent/agent.graph.service.ts b/libraries/nestjs-libraries/src/agent/agent.graph.service.ts index d4697e37..8a149fea 100644 --- a/libraries/nestjs-libraries/src/agent/agent.graph.service.ts +++ b/libraries/nestjs-libraries/src/agent/agent.graph.service.ts @@ -6,7 +6,7 @@ import { } from '@langchain/core/messages'; import { END, START, StateGraph } from '@langchain/langgraph'; import { ChatOpenAI, DallEAPIWrapper } from '@langchain/openai'; -import { TavilySearchResults } from '@langchain/community/tools/tavily_search'; +import { TavilySearch } from '@langchain/tavily'; import { ToolNode } from '@langchain/langgraph/prebuilt'; import { ChatPromptTemplate } from '@langchain/core/prompts'; import dayjs from 'dayjs'; @@ -18,7 +18,7 @@ import { GeneratorDto } from '@gitroom/nestjs-libraries/dtos/generator/generator const tools = !process.env.TAVILY_API_KEY ? [] - : [new TavilySearchResults({ maxResults: 3 })]; + : [new TavilySearch({ maxResults: 3 })]; const toolNode = new ToolNode(tools); const model = new ChatOpenAI({ diff --git a/package.json b/package.json index 27e4b543..5686470d 100644 --- a/package.json +++ b/package.json @@ -52,10 +52,11 @@ "@copilotkit/runtime": "1.10.6", "@dub/analytics": "^0.0.32", "@hookform/resolvers": "^3.3.4", - "@langchain/community": "^0.3.40", - "@langchain/core": "^0.3.44", - "@langchain/langgraph": "^0.2.63", - "@langchain/openai": "^0.5.5", + "@langchain/community": "^1.1.27", + "@langchain/core": "^1.1.39", + "@langchain/langgraph": "^1.2.8", + "@langchain/openai": "^1.4.3", + "@langchain/tavily": "^1.2.0", "@mantine/core": "^5.10.5", "@mantine/dates": "^5.10.5", "@mantine/hooks": "^5.10.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5aaf4435..5dc1dcac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,7 @@ importers: dependencies: '@ag-ui/mastra': specifier: ^1.0.1 - version: 1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(df7fa9e3d1c753bb493fdac5d039b067))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(53cb17873d4b9fb44549f8e02ffc4a35))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@ai-sdk/openai': specifier: ^2.0.52 version: 2.0.98(zod@3.25.76) @@ -45,7 +45,7 @@ importers: version: 1.10.6(@types/react@19.1.8)(graphql@16.13.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@copilotkit/runtime': specifier: 1.10.6 - version: 1.10.6(df7fa9e3d1c753bb493fdac5d039b067) + version: 1.10.6(53cb17873d4b9fb44549f8e02ffc4a35) '@dub/analytics': specifier: ^0.0.32 version: 0.0.32 @@ -53,17 +53,20 @@ importers: specifier: ^3.3.4 version: 3.10.0(react-hook-form@7.71.2(react@19.2.4)) '@langchain/community': - specifier: ^0.3.40 - version: 0.3.59(2e4a19b3c0fffde05d18130d96cce925) + specifier: ^1.1.27 + version: 1.1.27(1c9dd0a5a712999c5a106df86779aa3b) '@langchain/core': - specifier: ^0.3.44 - version: 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + specifier: ^1.1.39 + version: 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) '@langchain/langgraph': - specifier: ^0.2.63 - version: 0.2.74(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76)) + specifier: ^1.2.8 + version: 1.2.8(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76) '@langchain/openai': - specifier: ^0.5.5 - version: 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + specifier: ^1.4.3 + version: 1.4.3(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/tavily': + specifier: ^1.2.0 + version: 1.2.0(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))) '@mantine/core': specifier: ^5.10.5 version: 5.10.5(@emotion/react@11.14.0(@types/react@19.1.8)(react@19.2.4))(@mantine/hooks@5.10.5(react@19.2.4))(@types/react@19.1.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -324,7 +327,7 @@ importers: version: 0.5.0 axios: specifier: ^1.14.0 - version: 1.14.0 + version: 1.14.0(debug@4.4.3) bcrypt: specifier: ^5.1.1 version: 5.1.1 @@ -673,7 +676,7 @@ importers: version: 1.5.7(@swc/helpers@0.5.13) '@tailwindcss/vite': specifier: ^4.0.17 - version: 4.2.1(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + version: 4.2.1(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3)) '@testing-library/react': specifier: 16.3.0 version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -721,7 +724,7 @@ importers: version: 7.18.0(eslint@8.57.0)(typescript@5.5.4) '@vitejs/plugin-react': specifier: ^4.2.0 - version: 4.7.0(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + version: 4.7.0(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3)) '@vitest/coverage-v8': specifier: 1.6.0 version: 1.6.0(vitest@3.1.4) @@ -802,24 +805,22 @@ importers: version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4) tsup: specifier: ^8.5.0 - version: 8.5.1(@swc/core@1.5.7(@swc/helpers@0.5.13))(jiti@2.6.1)(postcss@8.4.38)(typescript@5.5.4)(yaml@2.8.2) + version: 8.5.1(@swc/core@1.5.7(@swc/helpers@0.5.13))(jiti@2.6.1)(postcss@8.4.38)(typescript@5.5.4)(yaml@2.8.3) typescript: specifier: 5.5.4 version: 5.5.4 vite: specifier: ^6.3.5 - version: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + version: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.5.4)(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + version: 5.1.4(typescript@5.5.4)(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3)) vitest: specifier: 3.1.4 - version: 3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + version: 3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) apps/backend: {} - apps/cli: {} - apps/commands: {} apps/extension: {} @@ -3312,6 +3313,22 @@ packages: peerDependencies: '@langchain/core': '>=0.3.58 <0.4.0' + '@langchain/classic@1.0.27': + resolution: {integrity: sha512-dMq8rgt3cy/QoHrB6HIKobievyW00DfuZcASG0aMy47Pf5TQq3vZM2tLT1kkCBe2yJnncQwqmAzxoEgFLJZrcw==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.0.0 + cheerio: '*' + peggy: ^5.1.0 + typeorm: '*' + peerDependenciesMeta: + cheerio: + optional: true + peggy: + optional: true + typeorm: + optional: true + '@langchain/community@0.3.59': resolution: {integrity: sha512-lYoVFC9wArWMXaixDgIadTE22jk4ZYAvSHHmwaMRagkGr5f4kyqMeJ83UUeW76XPx2cBy2fRSO+acSgqSuWE6A==} engines: {node: '>=18'} @@ -3692,10 +3709,379 @@ packages: youtubei.js: optional: true + '@langchain/community@1.1.27': + resolution: {integrity: sha512-s2U3w7QV7QpkFtY1eZMni4poz+nKLFclpDi3a7hUbZ67ttsGaU9WkZ2BiLuzLIs+IFaUvON/KcGkE8EqAl9aPA==} + engines: {node: '>=20'} + peerDependencies: + '@arcjet/redact': ^v1.2.0 + '@aws-crypto/sha256-js': ^5.0.0 + '@aws-sdk/client-dynamodb': ^3.1001.0 + '@aws-sdk/client-lambda': ^3.1001.0 + '@aws-sdk/client-s3': ^3.1001.0 + '@aws-sdk/client-sagemaker-runtime': ^3.1001.0 + '@aws-sdk/client-sfn': ^3.1001.0 + '@aws-sdk/credential-provider-node': ^3.388.0 + '@aws-sdk/dsql-signer': '*' + '@azure/search-documents': ^12.2.0 + '@azure/storage-blob': ^12.31.0 + '@browserbasehq/sdk': '*' + '@browserbasehq/stagehand': ^1.0.0 + '@clickhouse/client': ^0.2.5 + '@datastax/astra-db-ts': ^1.0.0 + '@elastic/elasticsearch': ^8.4.0 + '@getmetal/metal-sdk': '*' + '@getzep/zep-cloud': ^1.0.6 + '@getzep/zep-js': ^2.0.2 + '@gomomento/sdk-core': ^1.117.2 + '@google-cloud/storage': ^6.10.1 || ^7.7.0 + '@gradientai/nodejs-sdk': ^1.2.0 + '@huggingface/inference': ^4.13.14 + '@huggingface/transformers': ^3.8.1 + '@ibm-cloud/watsonx-ai': '*' + '@lancedb/lancedb': ^0.19.1 + '@langchain/core': ^1.1.38 + '@layerup/layerup-security': ^1.5.12 + '@libsql/client': ^0.17.0 + '@mendable/firecrawl-js': ^4.15.2 + '@mlc-ai/web-llm': '*' + '@mozilla/readability': '*' + '@neondatabase/serverless': '*' + '@notionhq/client': ^5.11.1 + '@opensearch-project/opensearch': '*' + '@pinecone-database/pinecone': '*' + '@planetscale/database': ^1.8.0 + '@premai/prem-sdk': ^0.3.25 + '@qdrant/js-client-rest': '*' + '@raycast/api': ^1.55.2 + '@rockset/client': ^0.9.1 + '@smithy/eventstream-codec': ^4.2.10 + '@smithy/protocol-http': ^5.3.10 + '@smithy/signature-v4': ^5.3.10 + '@smithy/util-utf8': ^4.2.2 + '@spider-cloud/spider-client': ^0.2.0 + '@supabase/supabase-js': ^2.45.0 + '@tensorflow-models/universal-sentence-encoder': '*' + '@tensorflow/tfjs-core': '*' + '@upstash/ratelimit': ^1.1.3 || ^2.0.3 + '@upstash/redis': ^1.20.6 + '@upstash/vector': ^1.1.1 + '@vercel/kv': '*' + '@vercel/postgres': '*' + '@writerai/writer-sdk': ^3.6.0 + '@xata.io/client': ^0.30.1 + '@xenova/transformers': '*' + '@zilliz/milvus2-sdk-node': '>=2.3.5' + apify-client: ^2.22.2 + assemblyai: ^4.25.1 + azion: ^3.1.2 + better-sqlite3: '>=9.4.0 <13.0.0' + cassandra-driver: ^4.7.2 + cborg: ^4.5.8 + cheerio: ^1.2.0 + chromadb: '*' + closevector-common: 0.1.3 + closevector-node: 0.1.6 + closevector-web: 0.1.6 + cohere-ai: '*' + convex: ^1.32.0 + couchbase: ^4.6.1 + crypto-js: ^4.2.0 + d3-dsv: ^3.0.1 + discord.js: ^14.25.1 + duck-duck-scrape: ^2.2.5 + epub2: ^3.0.1 + faiss-node: '*' + fast-xml-parser: '*' + firebase-admin: ^13.6.1 + google-auth-library: '*' + googleapis: '*' + hnswlib-node: ^3.0.0 + html-to-text: ^9.0.5 + ibm-cloud-sdk-core: '*' + ignore: ^7.0.5 + interface-datastore: ^9.0.2 + ioredis: ^5.3.2 + it-all: ^3.0.4 + jsdom: '*' + jsonwebtoken: ^9.0.3 + lodash: ^4.17.23 + lunary: ^0.7.10 + mammoth: ^1.11.0 + mariadb: ^3.5.1 + mem0ai: ^2.2.4 + mongodb: '*' + mysql2: ^3.19.1 + neo4j-driver: '*' + node-llama-cpp: '>=3.0.0' + notion-to-md: ^3.1.0 + officeparser: ^6.0.4 + openai: '*' + pdf-parse: 2.4.5 + pg: ^8.11.0 + pg-copy-streams: ^7.0.0 + pickleparser: ^0.2.1 + playwright: ^1.58.2 + portkey-ai: ^3.0.3 + puppeteer: '*' + pyodide: '>=0.24.1 <0.27.0' + redis: '*' + replicate: '*' + sonix-speech-recognition: ^2.1.1 + srt-parser-2: ^1.2.3 + typeorm: ^0.3.28 + typesense: ^3.0.1 + usearch: ^1.1.1 + voy-search: 0.6.3 + weaviate-client: '*' + word-extractor: '*' + ws: ^8.14.2 + youtubei.js: '*' + peerDependenciesMeta: + '@arcjet/redact': + optional: true + '@aws-crypto/sha256-js': + optional: true + '@aws-sdk/client-dynamodb': + optional: true + '@aws-sdk/client-lambda': + optional: true + '@aws-sdk/client-s3': + optional: true + '@aws-sdk/client-sagemaker-runtime': + optional: true + '@aws-sdk/client-sfn': + optional: true + '@aws-sdk/credential-provider-node': + optional: true + '@aws-sdk/dsql-signer': + optional: true + '@azure/search-documents': + optional: true + '@azure/storage-blob': + optional: true + '@browserbasehq/sdk': + optional: true + '@clickhouse/client': + optional: true + '@datastax/astra-db-ts': + optional: true + '@elastic/elasticsearch': + optional: true + '@getmetal/metal-sdk': + optional: true + '@getzep/zep-cloud': + optional: true + '@getzep/zep-js': + optional: true + '@gomomento/sdk-core': + optional: true + '@google-cloud/storage': + optional: true + '@gradientai/nodejs-sdk': + optional: true + '@huggingface/inference': + optional: true + '@huggingface/transformers': + optional: true + '@lancedb/lancedb': + optional: true + '@layerup/layerup-security': + optional: true + '@libsql/client': + optional: true + '@mendable/firecrawl-js': + optional: true + '@mlc-ai/web-llm': + optional: true + '@mozilla/readability': + optional: true + '@neondatabase/serverless': + optional: true + '@notionhq/client': + optional: true + '@opensearch-project/opensearch': + optional: true + '@pinecone-database/pinecone': + optional: true + '@planetscale/database': + optional: true + '@premai/prem-sdk': + optional: true + '@qdrant/js-client-rest': + optional: true + '@raycast/api': + optional: true + '@rockset/client': + optional: true + '@smithy/eventstream-codec': + optional: true + '@smithy/protocol-http': + optional: true + '@smithy/signature-v4': + optional: true + '@smithy/util-utf8': + optional: true + '@spider-cloud/spider-client': + optional: true + '@supabase/supabase-js': + optional: true + '@tensorflow-models/universal-sentence-encoder': + optional: true + '@tensorflow/tfjs-core': + optional: true + '@upstash/ratelimit': + optional: true + '@upstash/redis': + optional: true + '@upstash/vector': + optional: true + '@vercel/kv': + optional: true + '@vercel/postgres': + optional: true + '@writerai/writer-sdk': + optional: true + '@xata.io/client': + optional: true + '@xenova/transformers': + optional: true + '@zilliz/milvus2-sdk-node': + optional: true + apify-client: + optional: true + assemblyai: + optional: true + azion: + optional: true + better-sqlite3: + optional: true + cassandra-driver: + optional: true + cborg: + optional: true + cheerio: + optional: true + chromadb: + optional: true + closevector-common: + optional: true + closevector-node: + optional: true + closevector-web: + optional: true + cohere-ai: + optional: true + convex: + optional: true + couchbase: + optional: true + crypto-js: + optional: true + d3-dsv: + optional: true + discord.js: + optional: true + duck-duck-scrape: + optional: true + epub2: + optional: true + faiss-node: + optional: true + fast-xml-parser: + optional: true + firebase-admin: + optional: true + google-auth-library: + optional: true + googleapis: + optional: true + hnswlib-node: + optional: true + html-to-text: + optional: true + ignore: + optional: true + interface-datastore: + optional: true + ioredis: + optional: true + it-all: + optional: true + jsdom: + optional: true + jsonwebtoken: + optional: true + lodash: + optional: true + lunary: + optional: true + mammoth: + optional: true + mariadb: + optional: true + mem0ai: + optional: true + mongodb: + optional: true + mysql2: + optional: true + neo4j-driver: + optional: true + node-llama-cpp: + optional: true + notion-to-md: + optional: true + officeparser: + optional: true + pdf-parse: + optional: true + pg: + optional: true + pg-copy-streams: + optional: true + pickleparser: + optional: true + playwright: + optional: true + portkey-ai: + optional: true + puppeteer: + optional: true + pyodide: + optional: true + redis: + optional: true + replicate: + optional: true + sonix-speech-recognition: + optional: true + srt-parser-2: + optional: true + typeorm: + optional: true + typesense: + optional: true + usearch: + optional: true + voy-search: + optional: true + weaviate-client: + optional: true + word-extractor: + optional: true + ws: + optional: true + youtubei.js: + optional: true + '@langchain/core@0.3.80': resolution: {integrity: sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA==} engines: {node: '>=18'} + '@langchain/core@1.1.39': + resolution: {integrity: sha512-DP9c7TREy6iA7HnywstmUAsNyJNYTFpRg2yBfQ+6H0l1HnvQzei9GsQ36GeOLxgRaD3vm9K8urCcawSC7yQpCw==} + engines: {node: '>=20'} + '@langchain/google-common@0.1.8': resolution: {integrity: sha512-8auqWw2PMPhcHQHS+nMN3tVZrUPgSLckUaFeOHDOeSBiDvBd4KCybPwyl2oCwMDGvmyIxvOOckkMdeGaJ92vpQ==} engines: {node: '>=18'} @@ -3708,25 +4094,11 @@ packages: peerDependencies: '@langchain/core': '>=0.2.21 <0.4.0' - '@langchain/langgraph-checkpoint@0.0.18': - resolution: {integrity: sha512-IS7zJj36VgY+4pf8ZjsVuUWef7oTwt1y9ylvwu0aLuOn1d0fg05Om9DLm3v2GZ2Df6bhLV1kfWAM0IAl9O5rQQ==} + '@langchain/langgraph-checkpoint@1.0.1': + resolution: {integrity: sha512-HM0cJLRpIsSlWBQ/xuDC67l52SqZ62Bh2Y61DX+Xorqwoh5e1KxYvfCD7GnSTbWWhjBOutvnR0vPhu4orFkZfw==} engines: {node: '>=18'} peerDependencies: - '@langchain/core': '>=0.2.31 <0.4.0' - - '@langchain/langgraph-sdk@0.0.112': - resolution: {integrity: sha512-/9W5HSWCqYgwma6EoOspL4BGYxGxeJP6lIquPSF4FA0JlKopaUv58ucZC3vAgdJyCgg6sorCIV/qg7SGpEcCLw==} - peerDependencies: - '@langchain/core': '>=0.2.31 <0.4.0' - react: 19.2.4 - react-dom: 19.2.4 - peerDependenciesMeta: - '@langchain/core': - optional: true - react: - optional: true - react-dom: - optional: true + '@langchain/core': ^1.0.1 '@langchain/langgraph-sdk@0.0.70': resolution: {integrity: sha512-O8I12bfeMVz5fOrXnIcK4IdRf50IqyJTO458V56wAIHLNoi4H8/JHM+2M+Y4H2PtslXIGnvomWqlBd0eY5z/Og==} @@ -3753,11 +4125,32 @@ packages: react-dom: optional: true - '@langchain/langgraph@0.2.74': - resolution: {integrity: sha512-oHpEi5sTZTPaeZX1UnzfM2OAJ21QGQrwReTV6+QnX7h8nDCBzhtipAw1cK616S+X8zpcVOjgOtJuaJhXa4mN8w==} + '@langchain/langgraph-sdk@1.8.8': + resolution: {integrity: sha512-4OoqFAvPloOTZ6oPxXbJngz4FLJO8QSXb+BQV3qvNTvmfu1LQA7cCEqSNLYX9MoC340PbnDkHNgUtjajwkDHRg==} + peerDependencies: + '@langchain/core': ^1.1.16 + react: 19.2.4 + react-dom: 19.2.4 + svelte: ^4.0.0 || ^5.0.0 + vue: ^3.0.0 + peerDependenciesMeta: + '@langchain/core': + optional: true + react: + optional: true + react-dom: + optional: true + svelte: + optional: true + vue: + optional: true + + '@langchain/langgraph@1.2.8': + resolution: {integrity: sha512-kKkRpC5xFz1e6vPivE7lwRJa5oahLAMaVQvVGZdTa6uJIchIYJDIuM1n93FqGvg8aYVcgYU4FENtKKC5Eh1JYw==} engines: {node: '>=18'} peerDependencies: - '@langchain/core': '>=0.2.36 <0.3.0 || >=0.3.40 < 0.4.0' + '@langchain/core': ^1.1.16 + zod: ^3.25.32 || ^4.2.0 zod-to-json-schema: ^3.x peerDependenciesMeta: zod-to-json-schema: @@ -3775,12 +4168,36 @@ packages: peerDependencies: '@langchain/core': '>=0.3.58 <0.4.0' + '@langchain/openai@1.4.1': + resolution: {integrity: sha512-jaHk4TnLqWrQ1KYmavvwCImW6x8pBy6LLTK73tzSMg7HBLbq0g/l7EkpMcxZWDOvyufuCXUqO2bj47apcOhw6Q==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.1.38 + + '@langchain/openai@1.4.3': + resolution: {integrity: sha512-psf/e06nJ9YFXG67VVaKw6dAEeHLSc6wSbB3+sXpe6zEdpvC7+fyiEIxY6HntBkBU/uyqdeSt8Uu5WL+pQD+vg==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.1.39 + + '@langchain/tavily@1.2.0': + resolution: {integrity: sha512-aPLPgtw8+b/Rnr3H+X8H8z98T/Y7JuCE4B5eqRDHoEWgZvMDUFF7divqwQqCTMq2deQttlVrm5bN5JbKaAR7/w==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.0.0 + '@langchain/textsplitters@0.1.0': resolution: {integrity: sha512-djI4uw9rlkAb5iMhtLED+xJebDdAG935AdP4eRTB02R7OB/act55Bj9wsskhZsvuyQRpO4O1wQOp85s6T6GWmw==} engines: {node: '>=18'} peerDependencies: '@langchain/core': '>=0.2.21 <0.4.0' + '@langchain/textsplitters@1.0.1': + resolution: {integrity: sha512-rheJlB01iVtrOUzttscutRgLybPH9qR79EyzBEbf1u97ljWyuxQfCwIWK+SjoQTM9O8M7GGLLRBSYE26Jmcoww==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.0.0 + '@langchain/weaviate@0.2.3': resolution: {integrity: sha512-WqNGn1eSrI+ZigJd7kZjCj3fvHBYicKr054qts2nNJ+IyO5dWmY3oFTaVHFq1OLFVZJJxrFeDnxSEOC3JnfP0w==} engines: {node: '>=18'} @@ -9168,9 +9585,6 @@ packages: resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} - axios@1.13.6: - resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} - axios@1.14.0: resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==} @@ -11514,6 +11928,11 @@ packages: engines: {node: '>=0.4.7'} hasBin: true + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + happy-dom@15.11.7: resolution: {integrity: sha512-KyrFvnl+J9US63TEzwoiJOQzZBJY7KgBushJA8X61DMbNsH+2ONkDuLDnCnwUiPTF42tLoEmrPyoqbenVA5zrg==} engines: {node: '>=18.0.0'} @@ -12798,6 +13217,26 @@ packages: openai: optional: true + langsmith@0.5.17: + resolution: {integrity: sha512-/MEqTL50YH2SUZJtRl4+xI/tIgvu8OG5v6PMALKNkznjIelzf9q9kw0xxj1PC+r/ammMjVD1V2z9JmiT3AMqsQ==} + peerDependencies: + '@opentelemetry/api': '*' + '@opentelemetry/exporter-trace-otlp-proto': '*' + '@opentelemetry/sdk-trace-base': '*' + openai: '*' + ws: '>=7' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/exporter-trace-otlp-proto': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + openai: + optional: true + ws: + optional: true + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -14087,6 +14526,18 @@ packages: zod: optional: true + openai@6.34.0: + resolution: {integrity: sha512-yEr2jdGf4tVFYG6ohmr3pF6VJuveP0EA/sS8TBx+4Eq5NT10alu5zg2dmxMXMgqpihRDQlFGpRt2XwsGj+Fyxw==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + openapi-types@12.1.3: resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} @@ -14188,6 +14639,10 @@ packages: resolution: {integrity: sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==} engines: {node: '>=18'} + p-queue@9.1.2: + resolution: {integrity: sha512-ktsDOALzTYTWWF1PbkNVg2rOt+HaOaMWJMUnt7T3qf5tvZ1L8dBW3tObzprBcXNMKkwj+yFSLqHso0x+UFcJXw==} + engines: {node: '>=20'} + p-retry@4.6.2: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} engines: {node: '>=8'} @@ -14208,6 +14663,10 @@ packages: resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} engines: {node: '>=14.16'} + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -17518,6 +17977,11 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -17663,12 +18127,12 @@ snapshots: - react - react-dom - '@ag-ui/mastra@1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(df7fa9e3d1c753bb493fdac5d039b067))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': + '@ag-ui/mastra@1.0.1(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@copilotkit/runtime@1.10.6(53cb17873d4b9fb44549f8e02ffc4a35))(@mastra/client-js@0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76))(@mastra/core@1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@ag-ui/client': 0.0.47 '@ag-ui/core': 0.0.47 '@ai-sdk/ui-utils': 1.2.11(zod@3.25.76) - '@copilotkit/runtime': 1.10.6(df7fa9e3d1c753bb493fdac5d039b067) + '@copilotkit/runtime': 1.10.6(53cb17873d4b9fb44549f8e02ffc4a35) '@mastra/client-js': 0.15.2(openapi-types@12.1.3)(react@19.2.4)(zod@3.25.76) '@mastra/core': 1.21.0(@cfworker/json-schema@4.1.1)(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.1.0)(@types/json-schema@7.0.15)(quansync@0.2.11)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76))(@standard-schema/spec@1.1.0)(openapi-types@12.1.3)(zod@3.25.76))(@types/json-schema@7.0.15)(bufferutil@4.1.0)(openapi-types@12.1.3)(utf-8-validate@5.0.10)(zod@3.25.76) rxjs: 7.8.1 @@ -19564,7 +20028,7 @@ snapshots: - encoding - graphql - '@copilotkit/runtime@1.10.6(df7fa9e3d1c753bb493fdac5d039b067)': + '@copilotkit/runtime@1.10.6(53cb17873d4b9fb44549f8e02ffc4a35)': dependencies: '@ag-ui/client': 0.0.47 '@ag-ui/core': 0.0.47 @@ -19574,12 +20038,12 @@ snapshots: '@anthropic-ai/sdk': 0.57.0 '@copilotkit/shared': 1.10.6 '@graphql-yoga/plugin-defer-stream': 3.18.0(graphql-yoga@5.18.0(graphql@16.13.1))(graphql@16.13.1) - '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - '@langchain/community': 0.3.59(758e5da5f9d2f76d548b677d224e5fba) + '@langchain/aws': 0.1.15(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@langchain/community': 0.3.59(1289a407569d1b0c8cf61ad0c2bcf37c) '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76) - '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react@19.2.4) - '@langchain/openai': 0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/google-gauth': 0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76) + '@langchain/langgraph-sdk': 0.0.70(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react@19.2.4) + '@langchain/openai': 0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) '@scarf/scarf': 1.4.0 class-transformer: 0.5.1 class-validator: 0.14.4 @@ -19588,7 +20052,7 @@ snapshots: graphql-scalars: 1.25.0(graphql@16.13.1) graphql-yoga: 5.18.0(graphql@16.13.1) groq-sdk: 0.5.0 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.9)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) partial-json: 0.1.7 pino: 9.14.0 @@ -21046,31 +21510,53 @@ snapshots: '@kurkle/color@0.3.4': {} - '@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))': + '@langchain/aws@0.1.15(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': dependencies: '@aws-sdk/client-bedrock-agent-runtime': 3.1003.0 '@aws-sdk/client-bedrock-runtime': 3.1003.0 '@aws-sdk/client-kendra': 3.1003.0 '@aws-sdk/credential-provider-node': 3.972.17 - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) transitivePeerDependencies: - aws-crt - '@langchain/community@0.3.59(2e4a19b3c0fffde05d18130d96cce925)': + '@langchain/classic@1.0.27(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(cheerio@1.2.0)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/openai': 1.4.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/textsplitters': 1.0.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + handlebars: 4.7.9 + js-yaml: 4.1.1 + jsonpointer: 5.0.1 + openapi-types: 12.1.3 + uuid: 10.0.0 + yaml: 2.8.3 + zod: 3.25.76 + optionalDependencies: + cheerio: 1.2.0 + langsmith: 0.5.17(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + - ws + + '@langchain/community@0.3.59(1289a407569d1b0c8cf61ad0c2bcf37c)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) '@ibm-cloud/watsonx-ai': 1.7.9 - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - '@langchain/weaviate': 0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/weaviate': 0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) binary-extensions: 2.3.0 flat: 5.0.2 ibm-cloud-sdk-core: 5.4.8 js-yaml: 4.1.1 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.9)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) math-expression-evaluator: 2.0.7 - openai: 6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) uuid: 10.0.0 zod: 3.25.76 optionalDependencies: @@ -21081,7 +21567,6 @@ snapshots: '@aws-sdk/client-s3': 3.1003.0 '@aws-sdk/credential-provider-node': 3.972.17 '@browserbasehq/sdk': 2.7.0 - '@smithy/util-utf8': 2.3.0 '@upstash/redis': 1.36.3 cheerio: 1.2.0 crypto-js: 4.2.0 @@ -21089,7 +21574,6 @@ snapshots: google-auth-library: 9.15.1 googleapis: 137.1.0 html-to-text: 9.0.5 - ignore: 5.3.2 ioredis: 5.10.0 jsdom: 22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10) jsonwebtoken: 9.0.3 @@ -21120,32 +21604,27 @@ snapshots: - handlebars - peggy - '@langchain/community@0.3.59(758e5da5f9d2f76d548b677d224e5fba)': + '@langchain/community@1.1.27(1c9dd0a5a712999c5a106df86779aa3b)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.58.2)(bufferutil@4.1.0)(deepmerge@4.3.1)(dotenv@16.6.1)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(utf-8-validate@5.0.10)(zod@3.25.76) '@ibm-cloud/watsonx-ai': 1.7.9 - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - '@langchain/weaviate': 0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) + '@langchain/classic': 1.0.27(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(cheerio@1.2.0)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/openai': 1.4.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) binary-extensions: 2.3.0 flat: 5.0.2 ibm-cloud-sdk-core: 5.4.8 js-yaml: 4.1.1 - langchain: 0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + langsmith: 0.5.17(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) math-expression-evaluator: 2.0.7 - openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + openai: 6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) uuid: 10.0.0 zod: 3.25.76 optionalDependencies: '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/client-bedrock-agent-runtime': 3.1003.0 - '@aws-sdk/client-bedrock-runtime': 3.1003.0 - '@aws-sdk/client-kendra': 3.1003.0 '@aws-sdk/client-s3': 3.1003.0 '@aws-sdk/credential-provider-node': 3.972.17 '@browserbasehq/sdk': 2.7.0 - '@smithy/util-utf8': 2.3.0 '@upstash/redis': 1.36.3 cheerio: 1.2.0 crypto-js: 4.2.0 @@ -21153,7 +21632,6 @@ snapshots: google-auth-library: 9.15.1 googleapis: 137.1.0 html-to-text: 9.0.5 - ignore: 5.3.2 ioredis: 5.10.0 jsdom: 22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10) jsonwebtoken: 9.0.3 @@ -21164,24 +21642,9 @@ snapshots: weaviate-client: 3.12.0 ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) transitivePeerDependencies: - - '@langchain/anthropic' - - '@langchain/aws' - - '@langchain/cerebras' - - '@langchain/cohere' - - '@langchain/deepseek' - - '@langchain/google-genai' - - '@langchain/google-vertexai' - - '@langchain/google-vertexai-web' - - '@langchain/groq' - - '@langchain/mistralai' - - '@langchain/ollama' - - '@langchain/xai' - '@opentelemetry/api' - '@opentelemetry/exporter-trace-otlp-proto' - '@opentelemetry/sdk-trace-base' - - axios - - encoding - - handlebars - peggy '@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))': @@ -21224,48 +21687,57 @@ snapshots: - '@opentelemetry/sdk-trace-base' - openai - '@langchain/google-common@0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76)': + '@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@cfworker/json-schema': 4.1.1 + '@standard-schema/spec': 1.1.0 + ansi-styles: 5.2.0 + camelcase: 6.3.0 + decamelize: 1.2.0 + js-tiktoken: 1.0.21 + langsmith: 0.5.17(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + mustache: 4.2.0 + p-queue: 6.6.2 + uuid: 11.1.0 + zod: 3.25.76 + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + - ws + + '@langchain/google-common@0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76)': + dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) uuid: 10.0.0 zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - zod - '@langchain/google-gauth@0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76)': + '@langchain/google-gauth@0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76)': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/google-common': 0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/google-common': 0.1.8(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(zod@3.25.76) google-auth-library: 8.9.0 transitivePeerDependencies: - encoding - supports-color - zod - '@langchain/langgraph-checkpoint@0.0.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))': + '@langchain/langgraph-checkpoint@1.0.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) uuid: 10.0.0 - '@langchain/langgraph-sdk@0.0.112(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@langchain/langgraph-sdk@0.0.70(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react@19.2.4)': dependencies: '@types/json-schema': 7.0.15 p-queue: 6.6.2 p-retry: 4.6.2 uuid: 9.0.1 optionalDependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - - '@langchain/langgraph-sdk@0.0.70(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react@19.2.4)': - dependencies: - '@types/json-schema': 7.0.15 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 9.0.1 - optionalDependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) react: 19.2.4 '@langchain/langgraph-sdk@0.1.10(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': @@ -21279,11 +21751,23 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@langchain/langgraph@0.2.74(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76))': + '@langchain/langgraph-sdk@1.8.8(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/langgraph-checkpoint': 0.0.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - '@langchain/langgraph-sdk': 0.0.112(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@types/json-schema': 7.0.15 + p-queue: 9.1.2 + p-retry: 7.1.1 + uuid: 13.0.0 + optionalDependencies: + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@langchain/langgraph@1.2.8(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76)': + dependencies: + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/langgraph-checkpoint': 1.0.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + '@langchain/langgraph-sdk': 1.8.8(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@standard-schema/spec': 1.1.0 uuid: 10.0.0 zod: 3.25.76 optionalDependencies: @@ -21291,10 +21775,12 @@ snapshots: transitivePeerDependencies: - react - react-dom + - svelte + - vue - '@langchain/openai@0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + '@langchain/openai@0.4.9(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) js-tiktoken: 1.0.21 openai: 4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) zod: 3.25.76 @@ -21303,23 +21789,51 @@ snapshots: - encoding - ws - '@langchain/openai@0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + '@langchain/openai@0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) js-tiktoken: 1.0.21 openai: 5.23.2(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) zod: 3.25.76 transitivePeerDependencies: - ws - '@langchain/textsplitters@0.1.0(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))': + '@langchain/openai@1.4.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + js-tiktoken: 1.0.21 + openai: 6.34.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - ws + + '@langchain/openai@1.4.3(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))': + dependencies: + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + js-tiktoken: 1.0.21 + openai: 6.34.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - ws + + '@langchain/tavily@1.2.0(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': + dependencies: + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + zod: 3.25.76 + + '@langchain/textsplitters@0.1.0(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))': + dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) js-tiktoken: 1.0.21 - '@langchain/weaviate@0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))': + '@langchain/textsplitters@1.0.1(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)))': dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/core': 1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + js-tiktoken: 1.0.21 + + '@langchain/weaviate@0.2.3(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))': + dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) uuid: 10.0.0 weaviate-client: 3.12.0 transitivePeerDependencies: @@ -21917,7 +22431,7 @@ snapshots: '@nestjs/axios@4.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.14.0)(rxjs@7.8.2)': dependencies: '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - axios: 1.14.0 + axios: 1.14.0(debug@4.4.3) rxjs: 7.8.2 '@nestjs/cli@10.0.2(@swc/cli@0.3.14(@swc/core@1.5.7(@swc/helpers@0.5.13))(chokidar@3.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.13))(esbuild@0.27.7)': @@ -22138,7 +22652,7 @@ snapshots: '@neynar/nodejs-sdk@3.137.0(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(bufferutil@4.1.0)(class-transformer@0.5.1)(class-validator@0.14.4)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@openapitools/openapi-generator-cli': 2.30.2(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4) - axios: 1.14.0 + axios: 1.14.0(debug@4.4.3) semver: 7.7.4 viem: 2.47.0(bufferutil@4.1.0)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: @@ -22251,7 +22765,7 @@ snapshots: '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@10.4.22)(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxtjs/opencollective': 0.3.2 - axios: 1.14.0 + axios: 1.14.0(debug@4.4.3) chalk: 4.1.2 commander: 8.3.0 compare-versions: 6.1.1 @@ -25956,12 +26470,12 @@ snapshots: postcss: 8.5.8 tailwindcss: 4.2.1 - '@tailwindcss/vite@4.2.1(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.2.1(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.2.1 '@tailwindcss/oxide': 4.2.1 tailwindcss: 4.2.1 - vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) '@tanstack/react-virtual@3.13.21(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -27405,7 +27919,7 @@ snapshots: '@vercel/oidc@3.2.0': {} - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))': + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -27413,7 +27927,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -27432,7 +27946,7 @@ snapshots: std-env: 3.10.0 strip-literal: 2.1.1 test-exclude: 6.0.0 - vitest: 3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vitest: 3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color @@ -27443,13 +27957,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.1.4(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))': + '@vitest/mocker@3.1.4(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 3.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) '@vitest/pretty-format@3.1.4': dependencies: @@ -27483,7 +27997,7 @@ snapshots: pathe: 1.1.2 picocolors: 1.1.1 sirv: 2.0.4 - vitest: 3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vitest: 3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) '@vitest/utils@1.6.0': dependencies: @@ -28577,15 +29091,7 @@ snapshots: axe-core@4.11.1: {} - axios@1.13.6(debug@4.4.3): - dependencies: - follow-redirects: 1.15.11(debug@4.4.3) - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - axios@1.14.0: + axios@1.14.0(debug@4.4.3): dependencies: follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 @@ -30821,7 +31327,7 @@ snapshots: facebook-nodejs-business-sdk@21.0.5: dependencies: - axios: 1.14.0 + axios: 1.14.0(debug@4.4.3) currency-codes: 1.5.1 iso-3166-1: 2.1.1 js-sha256: 0.9.0 @@ -31569,6 +32075,15 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + handlebars@4.7.9: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + happy-dom@15.11.7: dependencies: entities: 4.5.0 @@ -31991,7 +32506,7 @@ snapshots: '@types/debug': 4.1.12 '@types/node': 18.19.130 '@types/tough-cookie': 4.0.5 - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0(debug@4.4.3) camelcase: 6.3.0 debug: 4.4.3(supports-color@5.5.0) dotenv: 16.6.1 @@ -32001,7 +32516,7 @@ snapshots: isstream: 0.1.2 jsonwebtoken: 9.0.3 mime-types: 2.1.35 - retry-axios: 2.6.0(axios@1.13.6(debug@4.4.3)) + retry-axios: 2.6.0(axios@1.14.0) tough-cookie: 4.1.4 transitivePeerDependencies: - supports-color @@ -33114,11 +33629,11 @@ snapshots: konva@10.2.0: {} - langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.9)(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) + '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) + '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) js-tiktoken: 1.0.21 js-yaml: 4.1.1 jsonpointer: 5.0.1 @@ -33129,36 +33644,10 @@ snapshots: yaml: 2.8.2 zod: 3.25.76 optionalDependencies: - '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - axios: 1.14.0 + '@langchain/aws': 0.1.15(@langchain/core@1.1.39(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))) + axios: 1.14.0(debug@4.4.3) cheerio: 1.2.0 - handlebars: 4.7.8 - transitivePeerDependencies: - - '@opentelemetry/api' - - '@opentelemetry/exporter-trace-otlp-proto' - - '@opentelemetry/sdk-trace-base' - - openai - - ws - - langchain@0.3.37(@langchain/aws@0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(axios@1.14.0)(cheerio@1.2.0)(handlebars@4.7.8)(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): - dependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/openai': 0.5.18(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)) - '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - js-tiktoken: 1.0.21 - js-yaml: 4.1.1 - jsonpointer: 5.0.1 - langsmith: 0.3.87(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76)) - openapi-types: 12.1.3 - p-retry: 4.6.2 - uuid: 10.0.0 - yaml: 2.8.2 - zod: 3.25.76 - optionalDependencies: - '@langchain/aws': 0.1.15(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))) - axios: 1.14.0 - cheerio: 1.2.0 - handlebars: 4.7.8 + handlebars: 4.7.9 transitivePeerDependencies: - '@opentelemetry/api' - '@opentelemetry/exporter-trace-otlp-proto' @@ -33194,6 +33683,17 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) openai: 6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + langsmith@0.5.17(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.203.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(openai@6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76))(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10)): + dependencies: + p-queue: 6.6.2 + uuid: 10.0.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/exporter-trace-otlp-proto': 0.203.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + openai: 6.27.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76) + ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + language-subtag-registry@0.3.23: {} language-tags@1.0.5: @@ -33840,7 +34340,7 @@ snapshots: metro-cache: 0.83.5 metro-core: 0.83.5 metro-runtime: 0.83.5 - yaml: 2.8.2 + yaml: 2.8.3 transitivePeerDependencies: - bufferutil - supports-color @@ -34869,6 +35369,11 @@ snapshots: ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) zod: 3.25.76 + openai@6.34.0(ws@8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(zod@3.25.76): + optionalDependencies: + ws: 8.19.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) + zod: 3.25.76 + openapi-types@12.1.3: {} openapi3-ts@3.2.0: @@ -35011,6 +35516,11 @@ snapshots: eventemitter3: 5.0.4 p-timeout: 6.1.4 + p-queue@9.1.2: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + p-retry@4.6.2: dependencies: '@types/retry': 0.12.0 @@ -35032,6 +35542,8 @@ snapshots: p-timeout@6.1.4: {} + p-timeout@7.0.1: {} + p-try@2.2.0: {} pac-proxy-agent@7.2.0: @@ -35433,13 +35945,13 @@ snapshots: postcss: 8.5.8 ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.13))(@types/node@18.16.9)(typescript@5.5.4) - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.4.38)(yaml@2.8.2): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.4.38)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 postcss: 8.4.38 - yaml: 2.8.2 + yaml: 2.8.3 postcss-nested@6.2.0(postcss@8.5.8): dependencies: @@ -36629,9 +37141,9 @@ snapshots: restructure@2.0.1: {} - retry-axios@2.6.0(axios@1.13.6(debug@4.4.3)): + retry-axios@2.6.0(axios@1.14.0): dependencies: - axios: 1.13.6(debug@4.4.3) + axios: 1.14.0(debug@4.4.3) retry@0.10.1: {} @@ -37904,7 +38416,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(@swc/core@1.5.7(@swc/helpers@0.5.13))(jiti@2.6.1)(postcss@8.4.38)(typescript@5.5.4)(yaml@2.8.2): + tsup@8.5.1(@swc/core@1.5.7(@swc/helpers@0.5.13))(jiti@2.6.1)(postcss@8.4.38)(typescript@5.5.4)(yaml@2.8.3): dependencies: bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 @@ -37915,7 +38427,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.4.38)(yaml@2.8.2) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.4.38)(yaml@2.8.3) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 @@ -38522,13 +39034,13 @@ snapshots: - utf-8-validate - zod - vite-node@3.1.4(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): + vite-node@3.1.4(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -38543,18 +39055,18 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.5.4)(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)): + vite-tsconfig-paths@5.1.4(typescript@5.5.4)(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3)): dependencies: debug: 4.4.3(supports-color@5.5.0) globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.5.4) optionalDependencies: - vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - typescript - vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): + vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -38569,12 +39081,12 @@ snapshots: lightningcss: 1.31.1 sass: 1.97.3 terser: 5.46.0 - yaml: 2.8.2 + yaml: 2.8.3 - vitest@3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): + vitest@3.1.4(@types/debug@4.1.12)(@types/node@18.16.9)(@vitest/ui@1.6.0)(happy-dom@15.11.7)(jiti@2.6.1)(jsdom@22.1.0(bufferutil@4.1.0)(canvas@2.11.2)(utf-8-validate@5.0.10))(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3): dependencies: '@vitest/expect': 3.1.4 - '@vitest/mocker': 3.1.4(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2)) + '@vitest/mocker': 3.1.4(vite@6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.1.4 '@vitest/snapshot': 3.1.4 @@ -38591,8 +39103,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) - vite-node: 3.1.4(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) + vite-node: 3.1.4(@types/node@18.16.9)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 @@ -38933,6 +39445,8 @@ snapshots: yaml@2.8.2: {} + yaml@2.8.3: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 diff --git a/tsconfig.base.json b/tsconfig.base.json index 5d95366a..c2abe7bf 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -25,6 +25,7 @@ "noFallthroughCasesInSwitch": true, "strict": true, "paths": { + "@langchain/langgraph/prebuilt": ["node_modules/@langchain/langgraph/dist/prebuilt/index.d.ts"], "@gitroom/backend/*": ["apps/backend/src/*"], "@gitroom/frontend/*": ["apps/frontend/src/*"], "@gitroom/helpers/*": ["libraries/helpers/src/*"], From 98c32c3da575120fc0c41eb0b637bbf73828f312 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 10 Apr 2026 16:27:34 +0700 Subject: [PATCH 18/80] feat: subreddit posting fix with api --- .../posts/providers-settings/reddit.dto.ts | 3 +++ .../integrations/social/reddit.provider.ts | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/reddit.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/reddit.dto.ts index 07e1f8e1..4a8f2a13 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/providers-settings/reddit.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/providers-settings/reddit.dto.ts @@ -39,6 +39,9 @@ export class RedditSettingsDtoInner { @IsString() @MinLength(2) @IsDefined() + @JSONSchema({ + description: 'Must be any of link, self (normal post), image, video, videogif', + }) type: string; @IsUrl() diff --git a/libraries/nestjs-libraries/src/integrations/social/reddit.provider.ts b/libraries/nestjs-libraries/src/integrations/social/reddit.provider.ts index 08da96be..ae8fcc3c 100644 --- a/libraries/nestjs-libraries/src/integrations/social/reddit.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/reddit.provider.ts @@ -184,15 +184,19 @@ export class RedditProvider extends SocialAbstract implements SocialProvider { const valueArray: PostResponse[] = []; for (const firstPostSettings of post.settings.subreddit) { + const kind = + firstPostSettings.value.type === 'media' + ? post.media[0].path.indexOf('mp4') > -1 + ? 'video' + : 'image' + : firstPostSettings.value.type; const postData = { api_type: 'json', title: firstPostSettings.value.title || '', kind: - firstPostSettings.value.type === 'media' - ? post.media[0].path.indexOf('mp4') > -1 - ? 'video' - : 'image' - : firstPostSettings.value.type, + ['link', 'self', 'image', 'video', 'videogif'].indexOf(kind) > -1 + ? kind + : 'self', ...(firstPostSettings.value.flair ? { flair_id: firstPostSettings.value.flair.id } : {}), @@ -218,10 +222,7 @@ export class RedditProvider extends SocialAbstract implements SocialProvider { } : {}), text: post.message, - sr: - firstPostSettings.value.subreddit.indexOf('/r/') > -1 - ? firstPostSettings.value.subreddit - : `/r/${firstPostSettings.value.subreddit}`, + sr: firstPostSettings.value.subreddit.replace('/r/', '').toLowerCase(), }; const all = await ( From 186d3370e97aefaf78d630645aefac46b9a58e76 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 10 Apr 2026 18:33:19 +0700 Subject: [PATCH 19/80] feat: instagram refresh fix --- .../src/integrations/social.abstract.ts | 7 ++--- .../integrations/social/facebook.provider.ts | 26 +++++++++++++----- .../integrations/social/instagram.provider.ts | 27 ++++++++++++++----- .../social/instagram.standalone.provider.ts | 5 ++-- 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/libraries/nestjs-libraries/src/integrations/social.abstract.ts b/libraries/nestjs-libraries/src/integrations/social.abstract.ts index ec13f7f6..c52cf107 100644 --- a/libraries/nestjs-libraries/src/integrations/social.abstract.ts +++ b/libraries/nestjs-libraries/src/integrations/social.abstract.ts @@ -51,7 +51,8 @@ export abstract class SocialAbstract { maxConcurrentJob = 1; public handleErrors( - body: string + body: string, + status: number, ): | { type: 'refresh-token' | 'bad-body' | 'retry'; value: string } | undefined { @@ -78,7 +79,7 @@ export abstract class SocialAbstract { try { value = await func(); } catch (err) { - const handle = this.handleErrors(safeStringify(err)); + const handle = this.handleErrors(safeStringify(err), 200); value = { err: true, value: 'Unknown Error', ...(handle || {}) }; } @@ -121,7 +122,7 @@ export abstract class SocialAbstract { json = '{}'; } - const handleError = this.handleErrors(json || '{}'); + const handleError = this.handleErrors(json || '{}', request.status); if ( request.status === 429 || diff --git a/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts b/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts index 052ef46a..98e41519 100644 --- a/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts @@ -31,7 +31,10 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider { } dto = FacebookDto; - override handleErrors(body: string): + override handleErrors( + body: string, + status: number + ): | { type: 'refresh-token' | 'bad-body'; value: string; @@ -129,7 +132,8 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider { if (body.indexOf('1404112') > -1) { return { type: 'bad-body' as const, - value: 'For security reasons, your account has limited access to the site for a few days', + value: + 'For security reasons, your account has limited access to the site for a few days', }; } @@ -155,6 +159,14 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider { }; } + if (status === 401) { + return { + type: 'bad-body' as const, + value: + 'An unknown error occurred, please try again later or contact support', + }; + } + return undefined; } @@ -289,8 +301,9 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider { // Also fetch pages via Business Manager API to discover pages // not selected during the OAuth page selection step try { - let bizUrl: string | undefined = - `https://graph.facebook.com/v20.0/me/businesses?access_token=${accessToken}`; + let bizUrl: + | string + | undefined = `https://graph.facebook.com/v20.0/me/businesses?access_token=${accessToken}`; while (bizUrl) { const bizResponse = await (await fetch(bizUrl)).json(); @@ -357,8 +370,9 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider { // 2. Check Business Manager owned_pages and client_pages try { - let bizUrl: string | undefined = - `https://graph.facebook.com/v20.0/me/businesses?access_token=${accessToken}`; + let bizUrl: + | string + | undefined = `https://graph.facebook.com/v20.0/me/businesses?access_token=${accessToken}`; while (bizUrl) { const bizResponse = await (await fetch(bizUrl)).json(); diff --git a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts index 435d23e9..6fc04acb 100644 --- a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts @@ -52,7 +52,10 @@ export class InstagramProvider }; } - public override handleErrors(body: string): + public override handleErrors( + body: string, + status: number + ): | { type: 'refresh-token' | 'bad-body' | 'retry'; value: string; @@ -272,7 +275,8 @@ export class InstagramProvider if (body.indexOf('190,') > -1) { return { type: 'bad-body' as const, - value: 'The account is missing some permissions to perform this action, please re-add the account and allow all permissions', + value: + 'The account is missing some permissions to perform this action, please re-add the account and allow all permissions', }; } @@ -308,7 +312,15 @@ export class InstagramProvider if (body.indexOf('param collaborators is not allowed') > -1) { return { type: 'bad-body' as const, - value: 'Collaborators are not allowed for carousel' + value: 'Collaborators are not allowed for carousel', + }; + } + + if (status === 401) { + return { + type: 'bad-body' as const, + value: + 'An unknown error occurred, please try again later or contact support', }; } @@ -439,8 +451,9 @@ export class InstagramProvider // Also fetch pages via Business Manager API to discover pages // not selected during the OAuth page selection step try { - let bizUrl: string | undefined = - `https://graph.facebook.com/v20.0/me/businesses?access_token=${accessToken}`; + let bizUrl: + | string + | undefined = `https://graph.facebook.com/v20.0/me/businesses?access_token=${accessToken}`; while (bizUrl) { const bizResponse = await (await fetch(bizUrl)).json(); @@ -536,7 +549,9 @@ export class InstagramProvider ? `&caption=${encodeURIComponent(firstPost.message)}` : ``; const isCarousel = - (firstPost?.media?.length || 0) > 1 && !isStory ? `&is_carousel_item=true` : ``; + (firstPost?.media?.length || 0) > 1 && !isStory + ? `&is_carousel_item=true` + : ``; const mediaType = m.path.indexOf('.mp4') > -1 ? firstPost?.media?.length === 1 diff --git a/libraries/nestjs-libraries/src/integrations/social/instagram.standalone.provider.ts b/libraries/nestjs-libraries/src/integrations/social/instagram.standalone.provider.ts index 5681d09e..6051e403 100644 --- a/libraries/nestjs-libraries/src/integrations/social/instagram.standalone.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/instagram.standalone.provider.ts @@ -40,11 +40,12 @@ export class InstagramStandaloneProvider } public override handleErrors( - body: string + body: string, + status: number ): | { type: 'refresh-token' | 'bad-body' | 'retry'; value: string } | undefined { - return instagramProvider.handleErrors(body); + return instagramProvider.handleErrors(body, status); } async refreshToken(refresh_token: string): Promise { From 318e9da8d17c4d0e6a6c9d1c7fabb4ab610e671f Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 10 Apr 2026 19:08:09 +0700 Subject: [PATCH 20/80] feat: refresh token, show error --- .../src/activities/post.activity.ts | 34 +- apps/orchestrator/src/workflows/index.ts | 1 + .../post-workflows/post.workflow.v1.0.2.ts | 410 ++++++++++++++++++ .../database/prisma/posts/posts.service.ts | 2 +- .../refresh.integration.service.ts | 15 +- 5 files changed, 454 insertions(+), 8 deletions(-) create mode 100644 apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.2.ts diff --git a/apps/orchestrator/src/activities/post.activity.ts b/apps/orchestrator/src/activities/post.activity.ts index 5467d353..87d5a899 100644 --- a/apps/orchestrator/src/activities/post.activity.ts +++ b/apps/orchestrator/src/activities/post.activity.ts @@ -49,7 +49,7 @@ export class PostActivity { for (const post of list) { await this._temporalService.client .getRawClient() - .workflow.signalWithStart('postWorkflowV101', { + .workflow.signalWithStart('postWorkflowV102', { workflowId: `post_${post.id}`, taskQueue: 'main', signal: 'poke', @@ -332,4 +332,36 @@ export class PostActivity { return false; } } + + @ActivityMethod() + async refreshTokenWithCause( + integration: Integration, + cause: string + ): Promise { + const getIntegration = this._integrationManager.getSocialIntegration( + integration.providerIdentifier + ); + + try { + const refresh = await this._refreshIntegrationService.refresh( + integration, + cause + ); + if (!refresh) { + return false; + } + + if (getIntegration.refreshWait) { + await timer(10000); + } + + return refresh; + } catch (err) { + await this._refreshIntegrationService.setBetweenSteps( + integration, + cause + ); + return false; + } + } } diff --git a/apps/orchestrator/src/workflows/index.ts b/apps/orchestrator/src/workflows/index.ts index 76b0d16f..4e0bccd3 100644 --- a/apps/orchestrator/src/workflows/index.ts +++ b/apps/orchestrator/src/workflows/index.ts @@ -1,4 +1,5 @@ export * from './post-workflows/post.workflow.v1.0.1'; +export * from './post-workflows/post.workflow.v1.0.2'; export * from './autopost.workflow'; export * from './digest.email.workflow'; export * from './missing.post.workflow'; diff --git a/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.2.ts b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.2.ts new file mode 100644 index 00000000..65fea772 --- /dev/null +++ b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.2.ts @@ -0,0 +1,410 @@ +import { PostActivity } from '@gitroom/orchestrator/activities/post.activity'; +import { + ActivityFailure, + ApplicationFailure, + startChild, + proxyActivities, + sleep, + defineSignal, + setHandler, +} from '@temporalio/workflow'; +import dayjs from 'dayjs'; +import { Integration } from '@prisma/client'; +import { capitalize, sortBy } from 'lodash'; +import { PostResponse } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; +import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; +import { TypedSearchAttributes } from '@temporalio/common'; +import { postId as postIdSearchParam } from '@gitroom/nestjs-libraries/temporal/temporal.search.attribute'; + +const proxyTaskQueue = (taskQueue: string) => { + return proxyActivities({ + startToCloseTimeout: '10 minute', + taskQueue, + retry: { + maximumAttempts: 3, + backoffCoefficient: 1, + initialInterval: '2 minutes', + }, + }); +}; + +const { + getPostsList, + inAppNotification, + changeState, + updatePost, + sendWebhooks, + isCommentable, +} = proxyActivities({ + startToCloseTimeout: '10 minute', + retry: { + maximumAttempts: 3, + backoffCoefficient: 1, + initialInterval: '2 minutes', + }, +}); + +const poke = defineSignal('poke'); + +const iterate = Array.from({ length: 5 }); + +export async function postWorkflowV102({ + taskQueue, + postId, + organizationId, + postNow = false, +}: { + taskQueue: string; + postId: string; + organizationId: string; + postNow?: boolean; +}) { + // Dynamic task queue, for concurrency + const { + postSocial, + postComment, + getIntegrationById, + refreshTokenWithCause, + internalPlugs, + globalPlugs, + processInternalPlug, + processPlug, + } = proxyTaskQueue(taskQueue); + + let poked = false; + setHandler(poke, () => { + poked = true; + }); + + const startTime = new Date(); + // get all the posts and comments to post + const postsListBefore = await getPostsList(organizationId, postId); + const [post] = postsListBefore; + + // in case doesn't exists for some reason, fail it + if (!post || (!postNow && post.state !== 'QUEUE')) { + return; + } + + // if it's a repeatable post, we should ignore this. + if (!postNow) { + await sleep( + dayjs(post.publishDate).isBefore(dayjs()) + ? 0 + : dayjs(post.publishDate).diff(dayjs(), 'millisecond') + ); + } + + // if refresh is needed from last time, let's inform the user + if (post.integration?.refreshNeeded) { + await inAppNotification( + post.organizationId, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name}`, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name} because you need to reconnect it. Please enable it and try again.`, + true, + false, + 'info' + ); + return; + } + + // if it's disabled, inform the user + if (post.integration?.disabled) { + await inAppNotification( + post.organizationId, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name}`, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name} because it's disabled. Please enable it and try again.`, + true, + false, + 'info' + ); + return; + } + + // Do we need to post comment for this social? + const toComment: boolean = + postsListBefore.length === 1 + ? false + : await isCommentable(post.integration); + + const postsList = toComment ? postsListBefore : [postsListBefore[0]]; + + // list of all the saved results + const postsResults: PostResponse[] = []; + + // iterate over the posts + for (let i = 0; i < postsList.length; i++) { + const before = postsResults.length; + // this is a small trick to repeat an action in case of token refresh + for (const _ of iterate) { + try { + // first post the main post + if (i === 0) { + postsResults.push( + ...(await postSocial(post.integration as Integration, [ + postsList[i], + ])) + ); + + // then post the comments if any + } else { + if (postsList[i].delay) { + await sleep(60000 * Math.max(0, Number(postsList[i].delay ?? 0))); + } + + postsResults.push( + ...(await postComment( + postsResults[0].postId, + postsResults.length === 1 + ? undefined + : postsResults[i - 1].postId, + post.integration, + [postsList[i]] + )) + ); + } + + // mark post as successful + await updatePost( + postsList[i].id, + postsResults[i].postId, + postsResults[i].releaseURL + ); + + if (i === 0) { + // send notification on a sucessful post + await inAppNotification( + post.integration.organizationId, + `Your post has been published on ${capitalize( + post.integration.providerIdentifier + )}`, + `Your post has been published on ${capitalize( + post.integration.providerIdentifier + )} at ${postsResults[0].releaseURL}`, + true, + true + ); + } + + // break the current while to move to the next post + break; + } catch (err) { + // if token refresh is needed, do it and repeat + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + post.integration, + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + await changeState(postsList[0].id, 'ERROR', err, postsList); + return false; + } + + post.integration.token = refresh.accessToken; + continue; + } + + // for other errors, change state and inform the user if needed + await changeState(postsList[0].id, 'ERROR', err, postsList); + + // specific case for bad body errors + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + await inAppNotification( + post.organizationId, + `Error posting${i === 0 ? ' ' : ' comments '}on ${ + post.integration?.providerIdentifier + } for ${post?.integration?.name}`, + `An error occurred while posting${i === 0 ? ' ' : ' comments '}on ${ + post.integration?.providerIdentifier + }${err?.cause?.message ? `: ${err?.cause?.message}` : ``}`, + true, + false, + 'fail' + ); + return false; + } + } + } + + if (postsResults.length === before) { + // all retries exhausted without success + return false; + } + } + + // send webhooks for the post + await sendWebhooks( + postsResults[0].postId, + post.organizationId, + post.integration.id + ); + + // load internal plugs like repost by other users + const internalPlugsList = await internalPlugs( + post.integration, + JSON.parse(post.settings) + ); + + // load global plugs, like repost a post if it gets to a certain number of likes + const globalPlugsList = (await globalPlugs(post.integration)).reduce( + (all, current) => { + for (let i = 1; i <= current.totalRuns; i++) { + all.push({ + ...current, + delay: current.delay * i, + }); + } + + return all; + }, + [] + ); + + // Check if the post is repeatable + const repeatPost = !post.intervalInDays + ? [] + : [ + { + type: 'repeat-post', + delay: + post.intervalInDays * 24 * 60 * 60 * 1000 - + (new Date().getTime() - startTime.getTime()), + }, + ]; + + // Sort all the actions by delay, so we can process them in order + const list = sortBy( + [...internalPlugsList, ...globalPlugsList, ...repeatPost], + 'delay' + ); + + // process all the plugs in order, we are using while because in some cases we need to remove items from the list + while (list.length > 0) { + // get the next to process + const todo = list.shift(); + + // wait for the delay + await sleep(Math.max(0, Number(todo.delay ?? 0))); + + // process internal plug + if (todo.type === 'internal-plug') { + for (const _ of iterate) { + try { + await processInternalPlug({ ...todo, post: postsResults[0].postId }); + } catch (err) { + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + await getIntegrationById(organizationId, todo.integration), + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + break; + } + + continue; + } + + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + break; + } + + continue; + } + break; + } + } + + // process global plug + if (todo.type === 'global') { + for (const _ of iterate) { + try { + const process = await processPlug({ + ...todo, + postId: postsResults[0].postId, + }); + if (process) { + const toDelete = list + .reduce((all, current, index) => { + if (current.plugId === todo.plugId) { + all.push(index); + } + + return all; + }, []) + .reverse(); + + for (const index of toDelete) { + list.splice(index, 1); + } + } + } catch (err) { + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + post.integration, + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + break; + } + + continue; + } + + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + break; + } + + continue; + } + + break; + } + } + + // process repeat post in a new workflow, this is important so the other plugs can keep running + if (todo.type === 'repeat-post') { + await startChild(postWorkflowV102, { + parentClosePolicy: 'ABANDON', + args: [ + { + taskQueue, + postId, + organizationId, + postNow: true, + }, + ], + workflowId: `post_${post.id}_${makeId(10)}`, + typedSearchAttributes: new TypedSearchAttributes([ + { + key: postIdSearchParam, + value: postId, + }, + ]), + }); + } + } +} diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 86e53bd6..e89ced6a 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -706,7 +706,7 @@ export class PostsService { try { await this._temporalService.client .getRawClient() - ?.workflow.start('postWorkflowV101', { + ?.workflow.start('postWorkflowV102', { workflowId: `post_${postId}`, taskQueue: 'main', workflowIdConflictPolicy: 'TERMINATE_EXISTING', diff --git a/libraries/nestjs-libraries/src/integrations/refresh.integration.service.ts b/libraries/nestjs-libraries/src/integrations/refresh.integration.service.ts index a14d990b..0689bdc6 100644 --- a/libraries/nestjs-libraries/src/integrations/refresh.integration.service.ts +++ b/libraries/nestjs-libraries/src/integrations/refresh.integration.service.ts @@ -16,12 +16,12 @@ export class RefreshIntegrationService { private _integrationService: IntegrationService, private _temporalService: TemporalService ) {} - async refresh(integration: Integration): Promise { + async refresh(integration: Integration, cause = ''): Promise { const socialProvider = this._integrationManager.getSocialIntegration( integration.providerIdentifier ); - const refresh = await this.refreshProcess(integration, socialProvider); + const refresh = await this.refreshProcess(integration, socialProvider, cause); if (!refresh) { return false as const; @@ -44,11 +44,12 @@ export class RefreshIntegrationService { return refresh; } - public async setBetweenSteps(integration: Integration) { + public async setBetweenSteps(integration: Integration, cause = '') { await this._integrationService.setBetweenRefreshSteps(integration.id); await this._integrationService.informAboutRefreshError( integration.organizationId, - integration + integration, + cause ); } @@ -69,7 +70,8 @@ export class RefreshIntegrationService { private async refreshProcess( integration: Integration, - socialProvider: SocialProvider + socialProvider: SocialProvider, + cause = '' ): Promise { const refresh: false | AuthTokenDetails = await socialProvider .refreshToken(integration.refreshToken) @@ -83,7 +85,8 @@ export class RefreshIntegrationService { await this._integrationService.informAboutRefreshError( integration.organizationId, - integration + integration, + cause ); await this._integrationService.disconnectChannel( From e3b3b82faee0000b5e637ab0e4cbfe8774c27c23 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 10 Apr 2026 20:17:38 +0700 Subject: [PATCH 21/80] feat: instagram better error --- .../src/integrations/social/instagram.provider.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts index 6fc04acb..cc7f095f 100644 --- a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts @@ -95,7 +95,7 @@ export class InstagramProvider if (body.toLowerCase().indexOf('session has been invalidated') > -1) { return { type: 'refresh-token' as const, - value: 'Please re-authenticate your Instagram account', + value: 'You session has been invalidated, this can usually happen from frequent posting, please re-authenticate, and wait 1-2 days before posting again', }; } @@ -316,14 +316,6 @@ export class InstagramProvider }; } - if (status === 401) { - return { - type: 'bad-body' as const, - value: - 'An unknown error occurred, please try again later or contact support', - }; - } - return undefined; } From 3ea302202dc0daa3db577eb7c68374cdc1ddbc3c Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sun, 12 Apr 2026 10:27:01 +0700 Subject: [PATCH 22/80] feat: fix advisory --- .../src/api/routes/media.controller.ts | 1 + .../v1/public.integrations.controller.ts | 27 ++++-- .../src/upload/cloudflare.storage.ts | 38 ++++++-- .../src/upload/custom.upload.validation.ts | 59 +++++++++---- .../src/upload/local.storage.ts | 33 +++++-- .../src/upload/r2.uploader.ts | 88 +++++++++++++++---- package.json | 1 + pnpm-lock.yaml | 3 + var/docker/nginx.conf | 13 +++ 9 files changed, 207 insertions(+), 56 deletions(-) diff --git a/apps/backend/src/api/routes/media.controller.ts b/apps/backend/src/api/routes/media.controller.ts index 0da66316..2d561ec2 100644 --- a/apps/backend/src/api/routes/media.controller.ts +++ b/apps/backend/src/api/routes/media.controller.ts @@ -129,6 +129,7 @@ export class MediaController { @Post('/upload-simple') @UseInterceptors(FileInterceptor('file')) + @UsePipes(new CustomFileValidationPipe()) async uploadSimple( @GetOrgFromRequest() org: Organization, @UploadedFile('file') file: Express.Multer.File, diff --git a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts index 4914906a..40ec9ff4 100644 --- a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts +++ b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts @@ -10,7 +10,9 @@ import { Query, UploadedFile, UseInterceptors, + UsePipes, } from '@nestjs/common'; +import { CustomFileValidationPipe } from '@gitroom/nestjs-libraries/upload/custom.upload.validation'; import { ApiTags } from '@nestjs/swagger'; import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request'; import { Organization } from '@prisma/client'; @@ -32,7 +34,19 @@ import { NotificationService } from '@gitroom/nestjs-libraries/database/prisma/n import { GetNotificationsDto } from '@gitroom/nestjs-libraries/dtos/notifications/get.notifications.dto'; import axios from 'axios'; import { Readable } from 'stream'; -import { lookup, extension } from 'mime-types'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { fromBuffer } = require('file-type'); + +const PUBLIC_API_ALLOWED_MIME = new Set([ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/avif', + 'image/bmp', + 'image/tiff', + 'video/mp4', +]); import * as Sentry from '@sentry/nestjs'; import { socialIntegrationList, IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager'; import { getValidationSchemas } from '@gitroom/nestjs-libraries/chat/validation.schemas.helper'; @@ -57,6 +71,7 @@ export class PublicIntegrationsController { @Post('/upload') @UseInterceptors(FileInterceptor('file')) + @UsePipes(new CustomFileValidationPipe()) async uploadSimple( @GetOrgFromRequest() org: Organization, @UploadedFile('file') file: Express.Multer.File @@ -85,10 +100,12 @@ export class PublicIntegrationsController { }); const buffer = Buffer.from(response.data); - const responseMime = response.headers?.['content-type']?.split(';')[0]?.trim(); - const urlMime = lookup(body?.url?.split?.('?')?.[0]); - const mimetype = (urlMime || responseMime || 'image/jpeg') as string; - const ext = extension(mimetype) || 'jpg'; + const detected = await fromBuffer(buffer); + if (!detected || !PUBLIC_API_ALLOWED_MIME.has(detected.mime)) { + throw new HttpException({ msg: 'Unsupported file type.' }, 400); + } + const mimetype = detected.mime; + const ext = detected.ext; const getFile = await this.storage.uploadFile({ buffer, diff --git a/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts b/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts index 42f38004..cac8a803 100644 --- a/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts +++ b/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts @@ -6,6 +6,19 @@ import mime from 'mime-types'; import { getExtension } from 'mime'; import { IUploadProvider } from './upload.interface'; import axios from 'axios'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { fromBuffer } = require('file-type'); + +const ALLOWED_MIME_TYPES = new Set([ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/avif', + 'image/bmp', + 'image/tiff', + 'video/mp4', +]); class CloudflareStorage implements IUploadProvider { private _client: S3Client; @@ -59,19 +72,20 @@ class CloudflareStorage implements IUploadProvider { async uploadSimple(path: string) { const loadImage = await fetch(path); - const contentType = - loadImage?.headers?.get('content-type') || - loadImage?.headers?.get('Content-Type'); - const extension = getExtension(contentType) || - path.split('?')[0].split('#')[0].split('.').pop() || - 'bin'; + const body = Buffer.from(await loadImage.arrayBuffer()); + const detected = await fromBuffer(body); + if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) { + throw new Error('Unsupported file type.'); + } + const extension = detected.ext; + const safeContentType = detected.mime; const id = makeId(10); const params = { Bucket: this._bucketName, Key: `${id}.${extension}`, - Body: Buffer.from(await loadImage.arrayBuffer()), - ContentType: contentType, + Body: body, + ContentType: safeContentType, ChecksumMode: 'DISABLED', }; @@ -83,8 +97,13 @@ class CloudflareStorage implements IUploadProvider { async uploadFile(file: Express.Multer.File): Promise { try { + const detected = await fromBuffer(file.buffer); + if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) { + throw new Error('Unsupported file type.'); + } const id = makeId(10); - const extension = mime.extension(file.mimetype) || ''; + const extension = detected.ext; + const safeContentType = detected.mime; // Create the PutObjectCommand to upload the file to Cloudflare R2 const command = new PutObjectCommand({ @@ -92,6 +111,7 @@ class CloudflareStorage implements IUploadProvider { ACL: 'public-read', Key: `${id}.${extension}`, Body: file.buffer, + ContentType: safeContentType, }); await this._client.send(command); diff --git a/libraries/nestjs-libraries/src/upload/custom.upload.validation.ts b/libraries/nestjs-libraries/src/upload/custom.upload.validation.ts index add65c38..c24c9504 100644 --- a/libraries/nestjs-libraries/src/upload/custom.upload.validation.ts +++ b/libraries/nestjs-libraries/src/upload/custom.upload.validation.ts @@ -1,37 +1,58 @@ import { BadRequestException, - FileTypeValidator, Injectable, - MaxFileSizeValidator, - ParseFilePipe, PipeTransform, } from '@nestjs/common'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { fromBuffer } = require('file-type'); + +const ALLOWED_MIME_TYPES = new Set([ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/avif', + 'image/bmp', + 'image/tiff', + 'video/mp4', +]); @Injectable() export class CustomFileValidationPipe implements PipeTransform { async transform(value: any) { - if (!value) { - throw 'No file provided.'; - } - - if (!value.mimetype) { + if (!value || typeof value !== 'object') { return value; } - // Set the maximum file size based on the MIME type - const maxSize = this.getMaxSize(value.mimetype); - const validation = - (value.mimetype.startsWith('image/') || - value.mimetype.startsWith('video/mp4')) && - value.size <= maxSize; - - if (validation) { + // Skip non-file parameters (org, body, query, etc.) + if (!('buffer' in value) && !('mimetype' in value) && !('fieldname' in value)) { return value; } - throw new BadRequestException( - `File size exceeds the maximum allowed size of ${maxSize} bytes.` - ); + if (!value.buffer || !Buffer.isBuffer(value.buffer)) { + throw new BadRequestException('Invalid file upload.'); + } + + const detected = await fromBuffer(value.buffer); + if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) { + throw new BadRequestException('Unsupported file type.'); + } + + const maxSize = this.getMaxSize(detected.mime); + if (value.size > maxSize) { + throw new BadRequestException( + `File size exceeds the maximum allowed size of ${maxSize} bytes.` + ); + } + + value.mimetype = detected.mime; + const safeBase = (value.originalname || 'upload') + .replace(/\.[^./\\]*$/, '') + .replace(/[\\/]/g, '_') + .slice(0, 100) || 'upload'; + value.originalname = `${safeBase}.${detected.ext}`; + + return value; } private getMaxSize(mimeType: string): number { diff --git a/libraries/nestjs-libraries/src/upload/local.storage.ts b/libraries/nestjs-libraries/src/upload/local.storage.ts index a03c1bd9..6d8007bb 100644 --- a/libraries/nestjs-libraries/src/upload/local.storage.ts +++ b/libraries/nestjs-libraries/src/upload/local.storage.ts @@ -3,6 +3,19 @@ import { mkdirSync, unlink, writeFileSync } from 'fs'; // @ts-ignore import mime from 'mime'; import { extname } from 'path'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { fromBuffer } = require('file-type'); + +const LOCAL_STORAGE_ALLOWED_MIME = new Set([ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/avif', + 'image/bmp', + 'image/tiff', + 'video/mp4', +]); export class LocalStorage implements IUploadProvider { constructor(private uploadDirectory: string) {} @@ -39,6 +52,13 @@ export class LocalStorage implements IUploadProvider { async uploadFile(file: Express.Multer.File): Promise { try { + const detected = await fromBuffer(file.buffer); + if (!detected || !LOCAL_STORAGE_ALLOWED_MIME.has(detected.mime)) { + throw new Error('Unsupported file type.'); + } + const safeExt = `.${detected.ext}`; + const safeMime = detected.mime; + const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); @@ -53,19 +73,16 @@ export class LocalStorage implements IUploadProvider { .map(() => Math.round(Math.random() * 16).toString(16)) .join(''); - const filePath = `${dir}/${randomName}${extname(file.originalname)}`; - const publicPath = `${innerPath}/${randomName}${extname( - file.originalname - )}`; + const filePath = `${dir}/${randomName}${safeExt}`; + const publicPath = `${innerPath}/${randomName}${safeExt}`; - // Logic to save the file to the filesystem goes here writeFileSync(filePath, file.buffer); return { - filename: `${randomName}${extname(file.originalname)}`, + filename: `${randomName}${safeExt}`, path: process.env.FRONTEND_URL + '/uploads' + publicPath, - mimetype: file.mimetype, - originalname: file.originalname, + mimetype: safeMime, + originalname: `${randomName}${safeExt}`, }; } catch (err) { console.error('Error uploading file to Local Storage:', err); diff --git a/libraries/nestjs-libraries/src/upload/r2.uploader.ts b/libraries/nestjs-libraries/src/upload/r2.uploader.ts index 482ef38b..a0ba2250 100644 --- a/libraries/nestjs-libraries/src/upload/r2.uploader.ts +++ b/libraries/nestjs-libraries/src/upload/r2.uploader.ts @@ -6,12 +6,34 @@ import { CompleteMultipartUploadCommand, AbortMultipartUploadCommand, PutObjectCommand, + GetObjectCommand, + DeleteObjectCommand, } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { Request, Response } from 'express'; import crypto from 'crypto'; import path from 'path'; import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { fromBuffer } = require('file-type'); + +const ALLOWED_EXT_TO_MIME: Record = { + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.png': 'image/png', + '.gif': 'image/gif', + '.webp': 'image/webp', + '.avif': 'image/avif', + '.bmp': 'image/bmp', + '.tif': 'image/tiff', + '.tiff': 'image/tiff', + '.mp4': 'video/mp4', +}; + +function normalizeExtension(filename: string): string | null { + const ext = path.extname(filename || '').toLowerCase(); + return ALLOWED_EXT_TO_MIME[ext] ? ext : null; +} const { CLOUDFLARE_ACCOUNT_ID, @@ -60,16 +82,21 @@ export default async function handleR2Upload( export async function simpleUpload( data: Buffer, originalFilename: string, - contentType: string + _contentType: string ) { - const fileExtension = path.extname(originalFilename); // Extract extension - const randomFilename = generateRandomString() + fileExtension; // Append extension + const detected = await fromBuffer(data); + if (!detected || !Object.values(ALLOWED_EXT_TO_MIME).includes(detected.mime)) { + throw new Error('Unsupported file type.'); + } + const fileExtension = `.${detected.ext}`; + const safeContentType = detected.mime; + const randomFilename = generateRandomString() + fileExtension; const params = { Bucket: CLOUDFLARE_BUCKETNAME, Key: randomFilename, Body: data, - ContentType: contentType, + ContentType: safeContentType, }; const command = new PutObjectCommand({ ...params }); @@ -79,15 +106,19 @@ export async function simpleUpload( } export async function createMultipartUpload(req: Request, res: Response) { - const { file, fileHash, contentType } = req.body; - const fileExtension = path.extname(file.name); // Extract extension - const randomFilename = generateRandomString() + fileExtension; // Append extension + const { file, fileHash } = req.body; + const safeExt = normalizeExtension(file?.name || ''); + if (!safeExt) { + return res.status(400).json({ message: 'Unsupported file type.' }); + } + const safeContentType = ALLOWED_EXT_TO_MIME[safeExt]; + const randomFilename = generateRandomString() + safeExt; try { const params = { Bucket: CLOUDFLARE_BUCKETNAME, Key: `${randomFilename}`, - ContentType: contentType, + ContentType: safeContentType, Metadata: { 'x-amz-meta-file-hash': fileHash, }, @@ -159,13 +190,6 @@ export async function completeMultipartUpload(req: Request, res: Response) { const { key, uploadId, parts } = req.body; try { - const params = { - Bucket: CLOUDFLARE_BUCKETNAME, - Key: key, - UploadId: uploadId, - MultipartUpload: { Parts: parts }, - }; - const command = new CompleteMultipartUploadCommand({ Bucket: CLOUDFLARE_BUCKETNAME, Key: key, @@ -173,6 +197,40 @@ export async function completeMultipartUpload(req: Request, res: Response) { MultipartUpload: { Parts: parts }, }); const response = await R2.send(command); + + const safeExt = normalizeExtension(key || ''); + if (!safeExt) { + await R2.send( + new DeleteObjectCommand({ Bucket: CLOUDFLARE_BUCKETNAME, Key: key }) + ); + return res.status(400).json({ message: 'Unsupported file type.' }); + } + const expectedMime = ALLOWED_EXT_TO_MIME[safeExt]; + + const head = await R2.send( + new GetObjectCommand({ + Bucket: CLOUDFLARE_BUCKETNAME, + Key: key, + Range: 'bytes=0-4100', + }) + ); + const chunks: Buffer[] = []; + // @ts-ignore + for await (const chunk of head.Body as AsyncIterable) { + chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); + } + const prefix = Buffer.concat(chunks); + const detected = await fromBuffer(prefix); + + if (!detected || detected.mime !== expectedMime) { + await R2.send( + new DeleteObjectCommand({ Bucket: CLOUDFLARE_BUCKETNAME, Key: key }) + ); + return res + .status(400) + .json({ message: 'File contents do not match declared type.' }); + } + response.Location = process.env.CLOUDFLARE_BUCKET_URL + '/' + diff --git a/package.json b/package.json index 5686470d..717083f2 100644 --- a/package.json +++ b/package.json @@ -180,6 +180,7 @@ "lodash": "^4.17.21", "mastra": "^1.3.19", "md5": "^2.3.0", + "file-type": "^16.5.4", "mime": "^3.0.0", "mime-types": "^2.1.35", "multer": "^1.4.5-lts.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5dc1dcac..ab9b5933 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -394,6 +394,9 @@ importers: fast-xml-parser: specifier: ^4.5.1 version: 4.5.4 + file-type: + specifier: ^16.5.4 + version: 16.5.4 google-auth-library: specifier: ^9.11.0 version: 9.15.1 diff --git a/var/docker/nginx.conf b/var/docker/nginx.conf index 346ef62b..2adaa125 100644 --- a/var/docker/nginx.conf +++ b/var/docker/nginx.conf @@ -35,6 +35,19 @@ http { location /uploads/ { alias /uploads/; + add_header X-Content-Type-Options "nosniff" always; + add_header Content-Security-Policy "default-src 'none'; img-src 'self'; media-src 'self'; style-src 'none'; script-src 'none'; frame-ancestors 'none'; sandbox" always; + types { + image/jpeg jpg jpeg; + image/png png; + image/gif gif; + image/webp webp; + image/avif avif; + image/bmp bmp; + image/tiff tif tiff; + video/mp4 mp4; + } + default_type application/octet-stream; } location / { From 1145e51ea629066ee351cfc5784e5b844639bade Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Mon, 13 Apr 2026 07:10:56 +0200 Subject: [PATCH 23/80] feat: sentry replay --- .../src/sentry/initialize.sentry.client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/react-shared-libraries/src/sentry/initialize.sentry.client.ts b/libraries/react-shared-libraries/src/sentry/initialize.sentry.client.ts index 31a49760..48d976e6 100644 --- a/libraries/react-shared-libraries/src/sentry/initialize.sentry.client.ts +++ b/libraries/react-shared-libraries/src/sentry/initialize.sentry.client.ts @@ -8,7 +8,7 @@ export const initializeSentryClient = (environment: string, dsn: string) => Sentry.browserTracingIntegration(), Sentry.browserProfilingIntegration(), Sentry.replayIntegration({ - maskAllText: true, + maskAllText: false, maskAllInputs: true, }), Sentry.feedbackIntegration({ From 288a4d428be98031d7b808087a7a6050ee5b23f2 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 13 Apr 2026 23:31:08 +0700 Subject: [PATCH 24/80] feat: change post status --- .../v1/public.integrations.controller.ts | 11 ++++++++ .../database/prisma/posts/posts.service.ts | 25 +++++++++++++++++++ .../src/dtos/posts/change.post.status.dto.ts | 6 +++++ 3 files changed, 42 insertions(+) create mode 100644 libraries/nestjs-libraries/src/dtos/posts/change.post.status.dto.ts diff --git a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts index 40ec9ff4..2c9bf934 100644 --- a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts +++ b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts @@ -23,6 +23,7 @@ import { FileInterceptor } from '@nestjs/platform-express'; import { UploadFactory } from '@gitroom/nestjs-libraries/upload/upload.factory'; import { MediaService } from '@gitroom/nestjs-libraries/database/prisma/media/media.service'; import { GetPostsDto } from '@gitroom/nestjs-libraries/dtos/posts/get.posts.dto'; +import { ChangePostStatusDto } from '@gitroom/nestjs-libraries/dtos/posts/change.post.status.dto'; import { AuthorizationActions, Sections, @@ -358,6 +359,16 @@ export class PublicIntegrationsController { return this._postsService.getMissingContent(org.id, id); } + @Put('/posts/:id/status') + async changePostStatus( + @GetOrgFromRequest() org: Organization, + @Param('id') id: string, + @Body() body: ChangePostStatusDto + ) { + Sentry.metrics.count('public_api-request', 1); + return this._postsService.changePostStatus(org.id, id, body.status); + } + @Put('/posts/:id/release-id') async updateReleaseId( @GetOrgFromRequest() org: Organization, diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index e89ced6a..6d05be20 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -784,6 +784,31 @@ export class PostsService { return this._postRepository.changeState(id, state, err, body); } + async changePostStatus( + orgId: string, + id: string, + status: 'draft' | 'schedule' + ) { + const getPostById = await this._postRepository.getPostById(id, orgId); + if (!getPostById) { + throw new BadRequestException('Post not found'); + } + + const state: State = status === 'draft' ? 'DRAFT' : 'QUEUE'; + await this._postRepository.changeState(id, state); + + try { + await this.startWorkflow( + getPostById.integration.providerIdentifier.split('-')[0].toLowerCase(), + getPostById.id, + orgId, + state + ); + } catch (err) {} + + return { id, state }; + } + async changeDate( orgId: string, id: string, diff --git a/libraries/nestjs-libraries/src/dtos/posts/change.post.status.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/change.post.status.dto.ts new file mode 100644 index 00000000..466502bf --- /dev/null +++ b/libraries/nestjs-libraries/src/dtos/posts/change.post.status.dto.ts @@ -0,0 +1,6 @@ +import { IsIn } from 'class-validator'; + +export class ChangePostStatusDto { + @IsIn(['draft', 'schedule']) + status: 'draft' | 'schedule'; +} From ec8c0f6fb99510185450654b951b41288b1485f3 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Tue, 14 Apr 2026 20:35:17 +0700 Subject: [PATCH 25/80] feat: search in media --- .../src/api/routes/media.controller.ts | 5 +- .../src/components/media/media.component.tsx | 71 +++++++++++-------- .../database/prisma/media/media.repository.ts | 14 +++- .../database/prisma/media/media.service.ts | 4 +- 4 files changed, 61 insertions(+), 33 deletions(-) diff --git a/apps/backend/src/api/routes/media.controller.ts b/apps/backend/src/api/routes/media.controller.ts index 2d561ec2..ba6cc44e 100644 --- a/apps/backend/src/api/routes/media.controller.ts +++ b/apps/backend/src/api/routes/media.controller.ts @@ -181,9 +181,10 @@ export class MediaController { @Get('/') getMedia( @GetOrgFromRequest() org: Organization, - @Query('page') page: number + @Query('page') page: number, + @Query('search') search?: string ) { - return this._mediaService.getMedia(org.id, page); + return this._mediaService.getMedia(org.id, page, search); } @Get('/video-options') diff --git a/apps/frontend/src/components/media/media.component.tsx b/apps/frontend/src/components/media/media.component.tsx index dac41d25..78cf0957 100644 --- a/apps/frontend/src/components/media/media.component.tsx +++ b/apps/frontend/src/components/media/media.component.tsx @@ -51,6 +51,7 @@ import { import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store'; import { useShallow } from 'zustand/react/shallow'; import { LoadingComponent } from '@gitroom/frontend/components/layout/loading'; +import { useDebounce } from 'use-debounce'; const Polonto = dynamic( () => import('@gitroom/frontend/components/launches/polonto') ); @@ -205,13 +206,25 @@ export const MediaBox: FC<{ closeModal: () => void; }> = ({ type, standalone, setMedia }) => { const [page, setPage] = useState(0); + const [search, setSearch] = useState(''); + const [debouncedSearch] = useDebounce(search, 300); const fetch = useFetch(); const modals = useModals(); const toaster = useToaster(); + useEffect(() => { + setPage(0); + }, [debouncedSearch]); const loadMedia = useCallback(async () => { - return (await fetch(`/media?page=${page + 1}`)).json(); - }, [page]); - const { data, mutate, isLoading } = useSWR(`get-media-${page}`, loadMedia); + const params = new URLSearchParams({ page: String(page + 1) }); + if (debouncedSearch.trim()) { + params.set('search', debouncedSearch.trim()); + } + return (await fetch(`/media?${params.toString()}`)).json(); + }, [page, debouncedSearch]); + const { data, mutate, isLoading } = useSWR( + `get-media-${page}-${debouncedSearch}`, + loadMedia + ); const [selected, setSelected] = useState([]); const t = useT(); const uploaderRef = useRef(null); @@ -404,23 +417,22 @@ export const MediaBox: FC<{
- {!isLoading && !!data?.results?.length && ( -
- {t( - 'select_or_upload_pictures_max_1gb', - 'Select or upload pictures (maximum 1 GB per upload).' - )} - {'\n'} - {t( - 'you_can_drag_drop_pictures', - 'You can also drag & drop pictures.' - )} -
- )} +
+ setSearch(e.target.value)} + placeholder={t('search_media_by_name', 'Search by file name')} + className="w-full h-[44px] px-[14px] rounded-[8px] bg-newBgColorInner border border-newColColor text-[14px] outline-none focus:border-[#612BD3]" + /> +
- {!isLoading && !!data?.results?.length && ( -
- {btn} - mutate()} /> -
- )} +
+ {btn} + mutate()} /> +
@@ -471,10 +481,15 @@ export const MediaBox: FC<{ <>
- {t( - 'you_dont_have_any_media_yet', - "You don't have any media yet" - )} + {debouncedSearch + ? t( + 'no_media_match_search', + 'No media matches your search' + ) + : t( + 'you_dont_have_any_media_yet', + "You don't have any media yet" + )}
{t( diff --git a/libraries/nestjs-libraries/src/database/prisma/media/media.repository.ts b/libraries/nestjs-libraries/src/database/prisma/media/media.repository.ts index d6389f06..208def20 100644 --- a/libraries/nestjs-libraries/src/database/prisma/media/media.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/media/media.repository.ts @@ -72,13 +72,24 @@ export class MediaRepository { }); } - async getMedia(org: string, page: number) { + async getMedia(org: string, page: number, search?: string) { const pageNum = (page || 1) - 1; + const trimmedSearch = search?.trim(); + const searchFilter = trimmedSearch + ? { + originalName: { + contains: trimmedSearch, + mode: 'insensitive' as const, + }, + } + : {}; const query = { where: { organization: { id: org, }, + deletedAt: null, + ...searchFilter, }, }; const pages = Math.ceil((await this._media.model.media.count(query)) / 18); @@ -86,6 +97,7 @@ export class MediaRepository { where: { organizationId: org, deletedAt: null, + ...searchFilter, }, orderBy: { createdAt: 'desc', diff --git a/libraries/nestjs-libraries/src/database/prisma/media/media.service.ts b/libraries/nestjs-libraries/src/database/prisma/media/media.service.ts index 66bdac84..a7b4f510 100644 --- a/libraries/nestjs-libraries/src/database/prisma/media/media.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/media/media.service.ts @@ -56,8 +56,8 @@ export class MediaService { return this._mediaRepository.saveFile(org, fileName, filePath, originalName); } - getMedia(org: string, page: number) { - return this._mediaRepository.getMedia(org, page); + getMedia(org: string, page: number, search?: string) { + return this._mediaRepository.getMedia(org, page, search); } saveMediaInformation(org: string, data: SaveMediaInformationDto) { From 386fc7b049737d5047bc83c6c19dd291e22eb28c Mon Sep 17 00:00:00 2001 From: Nevo David Date: Wed, 15 Apr 2026 17:53:37 +0700 Subject: [PATCH 26/80] feat: fix generation --- .../src/components/launches/ai.video.tsx | 125 +++++++----------- .../src/components/layout/new-modal.tsx | 2 +- .../src/upload/cloudflare.storage.ts | 4 + .../src/upload/local.storage.ts | 4 + 4 files changed, 60 insertions(+), 75 deletions(-) diff --git a/apps/frontend/src/components/launches/ai.video.tsx b/apps/frontend/src/components/launches/ai.video.tsx index b952579b..84ac317d 100644 --- a/apps/frontend/src/components/launches/ai.video.tsx +++ b/apps/frontend/src/components/launches/ai.video.tsx @@ -12,6 +12,8 @@ import { FormProvider, useForm } from 'react-hook-form'; import { useUser } from '@gitroom/frontend/components/layout/user.context'; import { VideoContextWrapper } from '@gitroom/frontend/components/videos/video.context.wrapper'; import { useToaster } from '@gitroom/react/toaster/toaster'; +import { useModals } from '@gitroom/frontend/components/layout/new-modal'; +import { createPortal } from 'react-dom'; export const Modal: FC<{ close: () => void; @@ -73,71 +75,42 @@ export const Modal: FC<{ onSubmit={form.handleSubmit(generate)} className="flex flex-col gap-[10px]" > + {createPortal( + <>{data?.credits || 0} credits left, + document.querySelector('.top-title-content') || document.createElement('div') + )} -
-
-
-
-
- -
- {data?.credits || 0} credits left -
-
-
- -
-
-
-
-
- -
-
- -
-
- + Vertical (Stories, Reels) + +
+
+
-
- -
+
+
+ +
@@ -153,9 +126,9 @@ export const AiVideo: FC<{ const { value, onChange } = props; const [loading, setLoading] = useState(false); const [type, setType] = useState(null); - const [modal, setModal] = useState(false); const fetch = useFetch(); const { isTrailing } = useUser(); + const modals = useModals(); const loadVideoList = useCallback(async () => { return (await (await fetch('/media/video-options')).json()).filter( @@ -175,7 +148,21 @@ export const AiVideo: FC<{ const generateVideo = useCallback( (type: { identifier: string }) => async () => { setType(type); - setModal(true); + modals.openModal({ + title:
, + children: (close) => ( + { + close(); + setType(null); + }} + type={type} + value={value} + /> + ), + }); }, [value, onChange] ); @@ -186,18 +173,6 @@ export const AiVideo: FC<{ return ( <> - {modal && ( - { - setModal(false); - setType(null); - }} - type={type} - value={props.value} - /> - )}
-
{t('ai', 'AI')} Video
+
+ {t('ai', 'AI')} Video +
{value.length >= 30 && !loading && ( diff --git a/apps/frontend/src/components/layout/new-modal.tsx b/apps/frontend/src/components/layout/new-modal.tsx index 651e3e77..fdc3704a 100644 --- a/apps/frontend/src/components/layout/new-modal.tsx +++ b/apps/frontend/src/components/layout/new-modal.tsx @@ -17,7 +17,7 @@ import clsx from 'clsx'; import { EventEmitter } from 'events'; interface OpenModalInterface { - title?: string; + title?: any; closeOnClickOutside?: boolean; removeLayout?: boolean; fullScreen?: boolean; diff --git a/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts b/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts index cac8a803..1ada0ac7 100644 --- a/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts +++ b/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts @@ -18,6 +18,10 @@ const ALLOWED_MIME_TYPES = new Set([ 'image/bmp', 'image/tiff', 'video/mp4', + 'audio/mpeg', + 'audio/mp4', + 'audio/wav', + 'audio/ogg', ]); class CloudflareStorage implements IUploadProvider { diff --git a/libraries/nestjs-libraries/src/upload/local.storage.ts b/libraries/nestjs-libraries/src/upload/local.storage.ts index 6d8007bb..90cc42c5 100644 --- a/libraries/nestjs-libraries/src/upload/local.storage.ts +++ b/libraries/nestjs-libraries/src/upload/local.storage.ts @@ -15,6 +15,10 @@ const LOCAL_STORAGE_ALLOWED_MIME = new Set([ 'image/bmp', 'image/tiff', 'video/mp4', + 'audio/mpeg', + 'audio/mp4', + 'audio/wav', + 'audio/ogg', ]); export class LocalStorage implements IUploadProvider { constructor(private uploadDirectory: string) {} From 5257f2fabe06653ab0baa494d8fe37d0ac9825cc Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 17 Apr 2026 17:34:34 +0700 Subject: [PATCH 27/80] feat: redirect url --- .../backend/src/api/routes/auth.controller.ts | 20 ++++++- .../backend/src/services/auth/auth.service.ts | 4 +- .../src/services/auth/providers.interface.ts | 2 +- .../auth/providers/farcaster.provider.ts | 2 +- .../auth/providers/github.provider.ts | 2 +- .../auth/providers/google.provider.ts | 57 +++++++------------ .../services/auth/providers/oauth.provider.ts | 2 +- .../auth/providers/wallet.provider.ts | 2 +- 8 files changed, 45 insertions(+), 46 deletions(-) diff --git a/apps/backend/src/api/routes/auth.controller.ts b/apps/backend/src/api/routes/auth.controller.ts index 4f87d07d..04e67984 100644 --- a/apps/backend/src/api/routes/auth.controller.ts +++ b/apps/backend/src/api/routes/auth.controller.ts @@ -251,13 +251,31 @@ export class AuthController { } } + @Get('/oauth/mobile-callback') + mobileCallback( + @Query('code') code: string, + @Query('state') state: string, + @Res({ passthrough: false }) response: Response + ) { + const scheme = process.env.MOBILE_APP_SCHEME || 'postiz://auth/callback'; + const params = new URLSearchParams(); + if (code) params.set('code', code); + if (state) params.set('state', state); + return response.redirect(302, `${scheme}?${params.toString()}`); + } + @Post('/oauth/:provider/exists') async oauthExists( @Body('code') code: string, + @Body('redirect_uri') redirect_uri: string, @Param('provider') provider: string, @Res({ passthrough: false }) response: Response ) { - const { jwt, token } = await this._authService.checkExists(provider, code); + const { jwt, token } = await this._authService.checkExists( + provider, + code, + redirect_uri + ); if (token) { return response.json({ token }); diff --git a/apps/backend/src/services/auth/auth.service.ts b/apps/backend/src/services/auth/auth.service.ts index 5d4dd818..32b43f3b 100644 --- a/apps/backend/src/services/auth/auth.service.ts +++ b/apps/backend/src/services/auth/auth.service.ts @@ -290,9 +290,9 @@ export class AuthService { return providerInstance.generateLink(query); } - async checkExists(provider: string, code: string) { + async checkExists(provider: string, code: string, redirectUri?: string) { const providerInstance = this._providerManager.getProvider(provider); - const token = await providerInstance.getToken(code); + const token = await providerInstance.getToken(code, redirectUri); const user = await providerInstance.getUser(token); if (!user) { throw new Error('Invalid user'); diff --git a/apps/backend/src/services/auth/providers.interface.ts b/apps/backend/src/services/auth/providers.interface.ts index a166d5fb..205a8d8e 100644 --- a/apps/backend/src/services/auth/providers.interface.ts +++ b/apps/backend/src/services/auth/providers.interface.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; export abstract class AuthProviderAbstract { abstract generateLink(query?: any): Promise | string; - abstract getToken(code: string): Promise; + abstract getToken(code: string, redirectUri?: string): Promise; abstract getUser( providerToken: string ): Promise<{ email: string; id: string }> | false; diff --git a/apps/backend/src/services/auth/providers/farcaster.provider.ts b/apps/backend/src/services/auth/providers/farcaster.provider.ts index e5700dfb..8d666316 100644 --- a/apps/backend/src/services/auth/providers/farcaster.provider.ts +++ b/apps/backend/src/services/auth/providers/farcaster.provider.ts @@ -14,7 +14,7 @@ export class FarcasterProvider extends AuthProviderAbstract { return ''; } - async getToken(code: string) { + async getToken(code: string, _redirectUri?: string) { const data = JSON.parse(Buffer.from(code, 'base64').toString()); const status = await client.lookupSigner({ signerUuid: data.signer_uuid }); if (status.status === 'approved') { diff --git a/apps/backend/src/services/auth/providers/github.provider.ts b/apps/backend/src/services/auth/providers/github.provider.ts index 0e47f81a..0fc05011 100644 --- a/apps/backend/src/services/auth/providers/github.provider.ts +++ b/apps/backend/src/services/auth/providers/github.provider.ts @@ -13,7 +13,7 @@ export class GithubProvider extends AuthProviderAbstract { )}`; } - async getToken(code: string): Promise { + async getToken(code: string, _redirectUri?: string): Promise { const { access_token } = await ( await fetch('https://github.com/login/oauth/access_token', { method: 'POST', diff --git a/apps/backend/src/services/auth/providers/google.provider.ts b/apps/backend/src/services/auth/providers/google.provider.ts index 3841baa8..425723f8 100644 --- a/apps/backend/src/services/auth/providers/google.provider.ts +++ b/apps/backend/src/services/auth/providers/google.provider.ts @@ -1,48 +1,28 @@ import { google } from 'googleapis'; -import { OAuth2Client } from 'google-auth-library/build/src/auth/oauth2client'; import { AuthProvider, AuthProviderAbstract, } from '@gitroom/backend/services/auth/providers.interface'; -const clientAndYoutube = () => { - const client = new google.auth.OAuth2({ +const defaultRedirect = () => + `${process.env.FRONTEND_URL}/integrations/social/youtube`; + +const makeClient = (redirectUri: string) => + new google.auth.OAuth2({ clientId: process.env.YOUTUBE_CLIENT_ID, clientSecret: process.env.YOUTUBE_CLIENT_SECRET, - redirectUri: `${process.env.FRONTEND_URL}/integrations/social/youtube`, + redirectUri, }); - const youtube = (newClient: OAuth2Client) => - google.youtube({ - version: 'v3', - auth: newClient, - }); - - const youtubeAnalytics = (newClient: OAuth2Client) => - google.youtubeAnalytics({ - version: 'v2', - auth: newClient, - }); - - const oauth2 = (newClient: OAuth2Client) => - google.oauth2({ - version: 'v2', - auth: newClient, - }); - - return { client, youtube, oauth2, youtubeAnalytics }; -}; - @AuthProvider({ provider: 'GOOGLE' }) export class GoogleProvider extends AuthProviderAbstract { - generateLink() { - const state = 'login'; - const { client } = clientAndYoutube(); - return client.generateAuthUrl({ + generateLink(query?: { redirect_uri?: string }) { + const redirectUri = query?.redirect_uri || defaultRedirect(); + return makeClient(redirectUri).generateAuthUrl({ access_type: 'online', prompt: 'consent', - state, - redirect_uri: `${process.env.FRONTEND_URL}/integrations/social/youtube`, + state: 'login', + redirect_uri: redirectUri, scope: [ 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email', @@ -50,21 +30,22 @@ export class GoogleProvider extends AuthProviderAbstract { }); } - async getToken(code: string) { - const { client, oauth2 } = clientAndYoutube(); + async getToken(code: string, redirectUri?: string) { + const client = makeClient(redirectUri || defaultRedirect()); const { tokens } = await client.getToken(code); - return tokens.access_token; + return tokens.access_token!; } async getUser(providerToken: string) { - const { client, oauth2 } = clientAndYoutube(); + const client = makeClient(defaultRedirect()); client.setCredentials({ access_token: providerToken }); - const user = oauth2(client); - const { data } = await user.userinfo.get(); + const { data } = await google + .oauth2({ version: 'v2', auth: client }) + .userinfo.get(); return { id: data.id!, - email: data.email, + email: data.email!, }; } } diff --git a/apps/backend/src/services/auth/providers/oauth.provider.ts b/apps/backend/src/services/auth/providers/oauth.provider.ts index 70684b16..ade792e3 100644 --- a/apps/backend/src/services/auth/providers/oauth.provider.ts +++ b/apps/backend/src/services/auth/providers/oauth.provider.ts @@ -48,7 +48,7 @@ export class OauthProvider extends AuthProviderAbstract { return `${authUrl}?${params.toString()}`; } - async getToken(code: string): Promise { + async getToken(code: string, _redirectUri?: string): Promise { const { tokenUrl, clientId, clientSecret, frontendUrl } = this.getConfig(); const response = await fetch(`${tokenUrl}`, { method: 'POST', diff --git a/apps/backend/src/services/auth/providers/wallet.provider.ts b/apps/backend/src/services/auth/providers/wallet.provider.ts index aaf46e3c..5ad5cf00 100644 --- a/apps/backend/src/services/auth/providers/wallet.provider.ts +++ b/apps/backend/src/services/auth/providers/wallet.provider.ts @@ -40,7 +40,7 @@ export class WalletProvider extends AuthProviderAbstract { return challenge; } - async getToken(code: string) { + async getToken(code: string, _redirectUri?: string) { const { publicKey, challenge, signature } = JSON.parse( Buffer.from(code, 'base64').toString() ); From 4e277ed32d332222e99d8ea78385c0c77d213e24 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 17 Apr 2026 17:52:15 +0700 Subject: [PATCH 28/80] feat: load first --- .../backend/src/api/routes/auth.controller.ts | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/backend/src/api/routes/auth.controller.ts b/apps/backend/src/api/routes/auth.controller.ts index 04e67984..536b52d1 100644 --- a/apps/backend/src/api/routes/auth.controller.ts +++ b/apps/backend/src/api/routes/auth.controller.ts @@ -199,6 +199,19 @@ export class AuthController { }; } + @Get('/oauth/mobile-callback') + mobileCallback( + @Query('code') code: string, + @Query('state') state: string, + @Res({ passthrough: false }) response: Response + ) { + const scheme = process.env.MOBILE_APP_SCHEME || 'postiz://auth/callback'; + const params = new URLSearchParams(); + if (code) params.set('code', code); + if (state) params.set('state', state); + return response.redirect(302, `${scheme}?${params.toString()}`); + } + @Get('/oauth/:provider') async oauthLink(@Param('provider') provider: string, @Query() query: any) { return this._authService.oauthLink(provider, query); @@ -210,7 +223,10 @@ export class AuthController { @Body('datafast_visitor_id') datafast_visitor_id: string, @Res({ passthrough: false }) response: Response ) { - const activate = await this._authService.activate(code, datafast_visitor_id); + const activate = await this._authService.activate( + code, + datafast_visitor_id + ); if (!activate) { return response.status(200).json({ can: false }); } @@ -251,19 +267,6 @@ export class AuthController { } } - @Get('/oauth/mobile-callback') - mobileCallback( - @Query('code') code: string, - @Query('state') state: string, - @Res({ passthrough: false }) response: Response - ) { - const scheme = process.env.MOBILE_APP_SCHEME || 'postiz://auth/callback'; - const params = new URLSearchParams(); - if (code) params.set('code', code); - if (state) params.set('state', state); - return response.redirect(302, `${scheme}?${params.toString()}`); - } - @Post('/oauth/:provider/exists') async oauthExists( @Body('code') code: string, From 45bdf128e9f454191433b7c57a06a4d7fc0746f2 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 17 Apr 2026 18:02:54 +0700 Subject: [PATCH 29/80] feat: oauth mobile callback --- apps/backend/src/api/routes/auth.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/api/routes/auth.controller.ts b/apps/backend/src/api/routes/auth.controller.ts index 536b52d1..14bc25f9 100644 --- a/apps/backend/src/api/routes/auth.controller.ts +++ b/apps/backend/src/api/routes/auth.controller.ts @@ -199,7 +199,7 @@ export class AuthController { }; } - @Get('/oauth/mobile-callback') + @Get('/oauth-mobile-callback') mobileCallback( @Query('code') code: string, @Query('state') state: string, From 7d9b99abf393260f3045f0b0bfcb3915fcb73484 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 17 Apr 2026 21:55:47 +0700 Subject: [PATCH 30/80] feat: provider edit preview --- apps/frontend/src/app/(provider)/layout.tsx | 73 +++++++ .../app/(provider)/provider/[p]/bridge.tsx | 55 ++++++ .../src/app/(provider)/provider/[p]/page.tsx | 52 +++++ .../launches/helpers/use.integration.ts | 5 +- .../providers/high.order.provider.tsx | 35 +++- .../new-launch/providers/post-comment.enum.ts | 5 + .../src/components/new-launch/store.ts | 2 +- .../preview.provider.component.tsx | 186 ++++++++++++++++++ apps/frontend/src/proxy.ts | 1 + 9 files changed, 405 insertions(+), 9 deletions(-) create mode 100644 apps/frontend/src/app/(provider)/layout.tsx create mode 100644 apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx create mode 100644 apps/frontend/src/app/(provider)/provider/[p]/page.tsx create mode 100644 apps/frontend/src/components/new-launch/providers/post-comment.enum.ts create mode 100644 apps/frontend/src/components/provider-preview/preview.provider.component.tsx diff --git a/apps/frontend/src/app/(provider)/layout.tsx b/apps/frontend/src/app/(provider)/layout.tsx new file mode 100644 index 00000000..f711e7de --- /dev/null +++ b/apps/frontend/src/app/(provider)/layout.tsx @@ -0,0 +1,73 @@ +export const dynamic = 'force-dynamic'; +import '../global.scss'; +import 'react-tooltip/dist/react-tooltip.css'; +import '@copilotkit/react-ui/styles.css'; +import LayoutContext from '@gitroom/frontend/components/layout/layout.context'; +import { ReactNode } from 'react'; +import { Plus_Jakarta_Sans } from 'next/font/google'; +import clsx from 'clsx'; +import { VariableContextComponent } from '@gitroom/react/helpers/variable.context'; +import UtmSaver from '@gitroom/helpers/utils/utm.saver'; + +const jakartaSans = Plus_Jakarta_Sans({ + weight: ['600', '500'], + style: ['normal', 'italic'], + subsets: ['latin'], +}); + +export default async function AppLayout({ children }: { children: ReactNode }) { + return ( + + + + + + + + + {children} + + + + + ); +} diff --git a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx new file mode 100644 index 00000000..8b713bb9 --- /dev/null +++ b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx @@ -0,0 +1,55 @@ +'use client'; +import { FC, useEffect, useRef, useState } from 'react'; +import { + ProviderPreviewComponent, + type ProviderPreviewHandle, + type ProviderPreviewProps, + type ProviderPreviewValidation, +} from '@gitroom/frontend/components/provider-preview/preview.provider.component'; + +type InitPayload = { + value?: Record; + errors?: string[]; + integration?: ProviderPreviewProps['integration']; +}; + +declare global { + interface Window { + __PROVIDER_INIT__?: InitPayload; + __getProviderPreviewValues__?: () => Record; + __validateProviderPreview__?: () => Promise; + } +} + +export const ProviderPreviewBridge: FC<{ provider: string }> = ({ + provider, +}) => { + const [init] = useState(() => + typeof window !== 'undefined' ? window.__PROVIDER_INIT__ ?? {} : {}, + ); + + const controlRef = useRef(null); + + useEffect(() => { + window.__getProviderPreviewValues__ = () => + controlRef.current?.getValues() ?? {}; + window.__validateProviderPreview__ = async () => + controlRef.current + ? await controlRef.current.validate() + : { isValid: false, value: {}, errors: ['not-ready'] }; + return () => { + delete window.__getProviderPreviewValues__; + delete window.__validateProviderPreview__; + }; + }, []); + + return ( + + ); +}; diff --git a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx new file mode 100644 index 00000000..15a51d7b --- /dev/null +++ b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx @@ -0,0 +1,52 @@ +/** + * Provider settings WebView bridge. + * + * URL: /provider/:p (e.g. /provider/tiktok, /provider/instagram) + * + * --- Initial state (native -> WebView, push once) --- + * Before loading the URL, the native side injects a global: + * + * webView.injectJavaScript(`window.__PROVIDER_INIT__ = ${JSON.stringify({ + * value: { ...currentSettings }, // optional, shape = provider DTO + * errors: ['...'], // optional, prior validation errors + * integration: { ... }, // optional Partial + * })};`); + * + * The bridge reads this once on mount (see ./bridge.tsx). + * + * --- Reading values & validation (native -> WebView, pull on demand) --- + * No messages are posted from the WebView. Instead, native calls these + * globals (they are defined once the bridge's effect has run): + * + * // Returns the current form values, no validation: + * webView.evaluateJavaScript('window.__getProviderPreviewValues__()') + * // => { ...settings } + * + * // Triggers validation and returns isValid + flattened error strings: + * webView.evaluateJavaScript('window.__validateProviderPreview__()') + * // => Promise<{ isValid: boolean, value: {...}, errors: string[] }> + * + * React Native example (RN WebView ref): + * const js = `window.__validateProviderPreview__().then(r => + * window.ReactNativeWebView.postMessage(JSON.stringify(r))); + * true;`; + * webViewRef.current?.injectJavaScript(js); + * + * Native should wait for page load (onLoadEnd / didFinishNavigation) before + * calling these. If called before the bridge mounts, the validate getter + * returns { isValid: false, errors: ['not-ready'] } and the values getter + * returns {}. + * + * If a different channel is needed, adjust ./bridge.tsx — this page is only + * a server wrapper that forwards the `:p` route param. + */ +import { ProviderPreviewBridge } from './bridge'; + +export default async function Page({ + params, +}: { + params: Promise<{ p: string }>; +}) { + const { p } = await params; + return ; +} diff --git a/apps/frontend/src/components/launches/helpers/use.integration.ts b/apps/frontend/src/components/launches/helpers/use.integration.ts index 265431f5..ef53c0ac 100644 --- a/apps/frontend/src/components/launches/helpers/use.integration.ts +++ b/apps/frontend/src/components/launches/helpers/use.integration.ts @@ -4,7 +4,7 @@ import { createContext, useContext } from 'react'; import { Integrations } from '@gitroom/frontend/components/launches/calendar.context'; import dayjs from 'dayjs'; import { newDayjs } from '@gitroom/frontend/components/layout/set.timezone'; -export const IntegrationContext = createContext<{ +export type IntegrationContextType = { date: dayjs.Dayjs; integration: Integrations | undefined; allIntegrations: Integrations[]; @@ -16,7 +16,8 @@ export const IntegrationContext = createContext<{ id: string; }>; }>; -}>({ +}; +export const IntegrationContext = createContext({ integration: undefined, value: [], date: newDayjs(), diff --git a/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx b/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx index 4fdbde4e..b66c76b6 100644 --- a/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx @@ -28,11 +28,8 @@ class Empty { empty: string; } -export enum PostComment { - ALL, - POST, - COMMENT, -} +export { PostComment } from '@gitroom/frontend/components/new-launch/providers/post-comment.enum'; +import { PostComment } from '@gitroom/frontend/components/new-launch/providers/post-comment.enum'; interface CharacterCondition { format: 'no-pictures' | 'with-pictures'; @@ -72,7 +69,7 @@ export const withProvider = function (params: { maximumCharacters, } = params; - return forwardRef((props: { id: string }, ref) => { + const Wrapped = forwardRef((props: { id: string }, ref) => { const t = useT(); const fetch = useFetch(); const { @@ -356,4 +353,30 @@ export const withProvider = function (params: { ); }); + + // Expose the settings configuration as static metadata so the preview / + // mobile settings page can render in isolation + // without pulling the launch store + DOM portals. + (Wrapped as any).__settings = { + SettingsComponent, + CustomPreviewComponent, + dto, + postComment, + maximumCharacters, + }; + + return Wrapped; +}; + +/** Pulls the settings metadata off a withProvider-wrapped component. */ +export const getProviderSettingsMeta = (component: unknown) => { + return (component as any)?.__settings as + | { + SettingsComponent: FC<{ values?: any }> | null; + CustomPreviewComponent?: FC<{ maximumCharacters?: number }>; + dto?: any; + postComment: PostComment; + maximumCharacters?: number | ((settings: any) => number); + } + | undefined; }; diff --git a/apps/frontend/src/components/new-launch/providers/post-comment.enum.ts b/apps/frontend/src/components/new-launch/providers/post-comment.enum.ts new file mode 100644 index 00000000..bfaee947 --- /dev/null +++ b/apps/frontend/src/components/new-launch/providers/post-comment.enum.ts @@ -0,0 +1,5 @@ +export enum PostComment { + ALL, + POST, + COMMENT, +} diff --git a/apps/frontend/src/components/new-launch/store.ts b/apps/frontend/src/components/new-launch/store.ts index f848bc60..2ea620b8 100644 --- a/apps/frontend/src/components/new-launch/store.ts +++ b/apps/frontend/src/components/new-launch/store.ts @@ -4,7 +4,7 @@ import { create } from 'zustand'; import dayjs from 'dayjs'; import { Integrations } from '@gitroom/frontend/components/launches/calendar.context'; import { createRef, RefObject } from 'react'; -import { PostComment } from '@gitroom/frontend/components/new-launch/providers/high.order.provider'; +import { PostComment } from '@gitroom/frontend/components/new-launch/providers/post-comment.enum'; import { newDayjs } from '@gitroom/frontend/components/layout/set.timezone'; interface Values { diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx new file mode 100644 index 00000000..9c84d8ce --- /dev/null +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -0,0 +1,186 @@ +'use client'; +import 'reflect-metadata'; +import { FC, MutableRefObject, useEffect, useMemo } from 'react'; +import { FormProvider, useForm, useWatch } from 'react-hook-form'; +import { classValidatorResolver } from '@hookform/resolvers/class-validator'; +import { Providers } from '@gitroom/frontend/components/new-launch/providers/show.all.providers'; +import { getProviderSettingsMeta } from '@gitroom/frontend/components/new-launch/providers/high.order.provider'; +import { + IntegrationContext, + type IntegrationContextType, +} from '@gitroom/frontend/components/launches/helpers/use.integration'; +import { newDayjs } from '@gitroom/frontend/components/layout/set.timezone'; + +type MockIntegration = IntegrationContextType['integration']; + +export type ProviderPreviewValidation = { + isValid: boolean; + value: Record; + errors: string[]; +}; + +export type ProviderPreviewHandle = { + getValues: () => Record; + validate: () => Promise; +}; + +export type ProviderPreviewProps = { + /** Provider identifier (e.g. "tiktok", "instagram", "youtube"). */ + provider: string; + /** Initial settings value (shape matches the provider's DTO). */ + value?: Record; + /** + * Called on every form change with the current settings value — for the + * mobile WebView bridge this is what you postMessage back. + */ + onChange?: (value: Record) => void; + /** Validator error messages from a previous failed save, rendered above the form. */ + errors?: string[]; + /** + * Stub integration to feed the SettingsComponent via IntegrationContext. + * Some providers (e.g. TikTok title) branch on `integration.additionalSettings` + * or `value[0].image` — pass what you have, leave the rest to defaults. + */ + integration?: Partial; + /** + * Imperative handle populated on mount. The parent calls + * `controlRef.current?.validate()` / `.getValues()` to pull state on demand. + */ + controlRef?: MutableRefObject; +}; + +const DEFAULT_INTEGRATION: MockIntegration = { + id: 'preview', + name: 'Preview', + identifier: '', + picture: '', + display: '', + type: 'social', + editor: 'normal' as const, + disabled: false, + inBetweenSteps: false, + additionalSettings: '[]', + changeProfilePicture: false, + changeNickName: false, + time: [] as { time: number }[], +}; + +/** Emits onChange whenever the form changes. Mounted inside FormProvider. */ +const FormChangeEmitter: FC<{ + onChange?: (value: Record) => void; +}> = ({ onChange }) => { + const values = useWatch(); + useEffect(() => { + if (onChange) onChange(values ?? {}); + }, [values, onChange]); + return null; +}; + +const flattenFormErrors = (errs: unknown): string[] => { + const out: string[] = []; + const walk = (node: unknown) => { + if (!node || typeof node !== 'object') return; + const n = node as Record; + if (typeof n.message === 'string') out.push(n.message); + if (n.types && typeof n.types === 'object') { + for (const t of Object.values(n.types as Record)) { + if (typeof t === 'string') out.push(t); + } + } + for (const [key, child] of Object.entries(n)) { + if (['message', 'type', 'types', 'ref', 'root'].includes(key)) continue; + walk(child); + } + }; + walk(errs); + return out; +}; + +export const ProviderPreviewComponent: FC = ({ + provider, + value, + onChange, + errors, + integration, + controlRef, +}) => { + const meta = useMemo(() => { + const entry = Providers.find((p) => p.identifier === provider); + if (!entry) return null; + return getProviderSettingsMeta(entry.component); + }, [provider]); + + const form = useForm({ + resolver: meta?.dto ? classValidatorResolver(meta.dto) : undefined, + defaultValues: value ?? {}, + values: value, + mode: 'all', + criteriaMode: 'all', + reValidateMode: 'onChange', + }); + + useEffect(() => { + if (!controlRef) return; + controlRef.current = { + getValues: () => form.getValues() as Record, + validate: async () => { + const isValid = await form.trigger(undefined, { shouldFocus: false }); + return { + isValid, + value: form.getValues() as Record, + errors: flattenFormErrors(form.formState.errors), + }; + }, + }; + return () => { + if (controlRef.current) controlRef.current = null; + }; + }, [controlRef, form]); + + const contextValue = useMemo( + () => ({ + date: newDayjs(), + integration: { + ...(DEFAULT_INTEGRATION as MockIntegration), + identifier: provider, + ...integration, + } as MockIntegration, + allIntegrations: [], + value: [], + }), + [provider, integration], + ); + + if (!meta) { + return
Provider "{provider}" not found
; + } + + const { SettingsComponent } = meta; + if (!SettingsComponent) { + return ( +
+ This provider has no configurable settings. +
+ ); + } + + return ( + + +
+ {errors && errors.length > 0 && ( +
+
    + {errors.map((e, i) => ( +
  • {e}
  • + ))} +
+
+ )} + + +
+
+
+ ); +}; diff --git a/apps/frontend/src/proxy.ts b/apps/frontend/src/proxy.ts index da712ea5..360c937e 100644 --- a/apps/frontend/src/proxy.ts +++ b/apps/frontend/src/proxy.ts @@ -46,6 +46,7 @@ export async function proxy(request: NextRequest) { if ( nextUrl.pathname.startsWith('/uploads/') || nextUrl.pathname.startsWith('/p/') || + nextUrl.pathname.startsWith('/provider/') || nextUrl.pathname.startsWith('/icons/') ) { return topResponse; From 0ecca5298d3c3fbd0c2f395c1da760a6201f9d2a Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 17 Apr 2026 22:41:30 +0700 Subject: [PATCH 31/80] feat: remove gap --- .../components/provider-preview/preview.provider.component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx index 9c84d8ce..05bf7124 100644 --- a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -167,7 +167,7 @@ export const ProviderPreviewComponent: FC = ({ return ( -
+
{errors && errors.length > 0 && (
    From e5947034ab24f9a1e39d6920024e230be838c736 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 17 Apr 2026 23:53:29 +0700 Subject: [PATCH 32/80] feat: check validity --- .../app/(provider)/provider/[p]/bridge.tsx | 6 ++++ .../providers/high.order.provider.tsx | 6 ++++ .../preview.provider.component.tsx | 33 +++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx index 8b713bb9..0080cf23 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx @@ -11,6 +11,11 @@ type InitPayload = { value?: Record; errors?: string[]; integration?: ProviderPreviewProps['integration']; + /** + * Per-post media (outer array = thread entries, inner = media items). + * Passed to the provider's `checkValidity` function during validation. + */ + posts?: Array>; }; declare global { @@ -49,6 +54,7 @@ export const ProviderPreviewBridge: FC<{ provider: string }> = ({ value={init.value} errors={init.errors} integration={init.integration} + posts={init.posts} controlRef={controlRef} /> ); diff --git a/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx b/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx index b66c76b6..b1f57b0e 100644 --- a/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/high.order.provider.tsx @@ -363,6 +363,7 @@ export const withProvider = function (params: { dto, postComment, maximumCharacters, + checkValidity, }; return Wrapped; @@ -377,6 +378,11 @@ export const getProviderSettingsMeta = (component: unknown) => { dto?: any; postComment: PostComment; maximumCharacters?: number | ((settings: any) => number); + checkValidity?: ( + value: Array>, + settings: any, + additionalSettings: any + ) => Promise; } | undefined; }; diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx index 05bf7124..f5ed2556 100644 --- a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -42,6 +42,11 @@ export type ProviderPreviewProps = { * or `value[0].image` — pass what you have, leave the rest to defaults. */ integration?: Partial; + /** + * Per-post media (outer array = thread entries, inner = media items). + * Forwarded to the provider's `checkValidity` during validate(). + */ + posts?: Array>; /** * Imperative handle populated on mount. The parent calls * `controlRef.current?.validate()` / `.getValues()` to pull state on demand. @@ -102,6 +107,7 @@ export const ProviderPreviewComponent: FC = ({ onChange, errors, integration, + posts, controlRef, }) => { const meta = useMemo(() => { @@ -125,17 +131,38 @@ export const ProviderPreviewComponent: FC = ({ getValues: () => form.getValues() as Record, validate: async () => { const isValid = await form.trigger(undefined, { shouldFocus: false }); + const errs = flattenFormErrors(form.formState.errors); + let customError: string | true = true; + if (meta?.checkValidity) { + try { + const additional = (integration?.additionalSettings as + | string + | undefined) ?? '[]'; + const additionalSettings = + typeof additional === 'string' + ? JSON.parse(additional || '[]') + : additional; + customError = await meta.checkValidity( + posts ?? [], + form.getValues(), + additionalSettings, + ); + } catch (e: any) { + customError = e?.message ?? 'checkValidity threw'; + } + } + if (customError !== true) errs.push(customError); return { - isValid, + isValid: isValid && customError === true, value: form.getValues() as Record, - errors: flattenFormErrors(form.formState.errors), + errors: errs, }; }, }; return () => { if (controlRef.current) controlRef.current = null; }; - }, [controlRef, form]); + }, [controlRef, form, meta, integration, posts]); const contextValue = useMemo( () => ({ From 2ae293916be401deaaf0c6323126e7ee980b54db Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 00:12:41 +0700 Subject: [PATCH 33/80] feat: fix validity --- .../preview.provider.component.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx index f5ed2556..d02e7c9d 100644 --- a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -17,6 +17,10 @@ export type ProviderPreviewValidation = { isValid: boolean; value: Record; errors: string[]; + /** react-hook-form trigger() result. False = at least one DTO field failed. */ + formValid: boolean; + /** Non-null when the provider's checkValidity() returned a string. */ + checkValidityError: string | null; }; export type ProviderPreviewHandle = { @@ -130,7 +134,7 @@ export const ProviderPreviewComponent: FC = ({ controlRef.current = { getValues: () => form.getValues() as Record, validate: async () => { - const isValid = await form.trigger(undefined, { shouldFocus: false }); + const formValid = await form.trigger(undefined, { shouldFocus: false }); const errs = flattenFormErrors(form.formState.errors); let customError: string | true = true; if (meta?.checkValidity) { @@ -151,11 +155,15 @@ export const ProviderPreviewComponent: FC = ({ customError = e?.message ?? 'checkValidity threw'; } } - if (customError !== true) errs.push(customError); + const checkValidityError = + customError === true ? null : customError; + if (checkValidityError) errs.push(checkValidityError); return { - isValid: isValid && customError === true, + isValid: formValid && checkValidityError === null, value: form.getValues() as Record, errors: errs, + formValid, + checkValidityError, }; }, }; From 71b2e2e7938756c284116c1b2d5d217c37beabf7 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 00:17:05 +0700 Subject: [PATCH 34/80] feat: fix validity --- apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx index 0080cf23..c01287ab 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx @@ -41,7 +41,13 @@ export const ProviderPreviewBridge: FC<{ provider: string }> = ({ window.__validateProviderPreview__ = async () => controlRef.current ? await controlRef.current.validate() - : { isValid: false, value: {}, errors: ['not-ready'] }; + : { + isValid: false, + value: {}, + errors: ['not-ready'], + formValid: false, + checkValidityError: null, + }; return () => { delete window.__getProviderPreviewValues__; delete window.__validateProviderPreview__; From 8a7e8eb8f3c8550100e08dddf302917fcabce17e Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 01:16:32 +0700 Subject: [PATCH 35/80] feat: empty object --- .../provider-preview/preview.provider.component.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx index d02e7c9d..48eed929 100644 --- a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -120,10 +120,16 @@ export const ProviderPreviewComponent: FC = ({ return getProviderSettingsMeta(entry.component); }, [provider]); + // When `value` is absent or `{}`, don't feed it to react-hook-form at all — + // passing an empty object as `values` wipes out DTO-level defaults that the + // SettingsComponent relies on (e.g. tiktok privacy = PUBLIC). + const hasSeededValue = + !!value && typeof value === 'object' && Object.keys(value).length > 0; + const form = useForm({ resolver: meta?.dto ? classValidatorResolver(meta.dto) : undefined, - defaultValues: value ?? {}, - values: value, + defaultValues: hasSeededValue ? value : undefined, + values: hasSeededValue ? value : undefined, mode: 'all', criteriaMode: 'all', reValidateMode: 'onChange', From 027c9caa96c4fd075c9c07bc9d46b52565d5d838 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 02:18:28 +0700 Subject: [PATCH 36/80] feat: fix check validity --- .../app/(provider)/provider/[p]/bridge.tsx | 10 +++++ .../src/app/(provider)/provider/[p]/page.tsx | 6 +++ .../preview.provider.component.tsx | 40 +++++++++++++++---- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx index c01287ab..d6cfd270 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx @@ -23,6 +23,13 @@ declare global { __PROVIDER_INIT__?: InitPayload; __getProviderPreviewValues__?: () => Record; __validateProviderPreview__?: () => Promise; + /** + * Returns the provider's resolved character limit (number) or null when + * the provider doesn't declare one. Resolution uses the seeded + * __PROVIDER_INIT__.integration.additionalSettings (e.g. X bumps to + * 4000 when {title:'Verified', value:true} is present). + */ + __getProviderMaxCharacters__?: () => number | null; } } @@ -48,9 +55,12 @@ export const ProviderPreviewBridge: FC<{ provider: string }> = ({ formValid: false, checkValidityError: null, }; + window.__getProviderMaxCharacters__ = () => + controlRef.current?.getMaximumCharacters() ?? null; return () => { delete window.__getProviderPreviewValues__; delete window.__validateProviderPreview__; + delete window.__getProviderMaxCharacters__; }; }, []); diff --git a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx index 15a51d7b..f0657bd3 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx @@ -26,6 +26,12 @@ * webView.evaluateJavaScript('window.__validateProviderPreview__()') * // => Promise<{ isValid: boolean, value: {...}, errors: string[] }> * + * // Returns the provider's resolved character limit (number) or null + * // when the provider doesn't declare one. Uses the seeded + * // __PROVIDER_INIT__.integration.additionalSettings: + * webView.evaluateJavaScript('window.__getProviderMaxCharacters__()') + * // => number | null + * * React Native example (RN WebView ref): * const js = `window.__validateProviderPreview__().then(r => * window.ReactNativeWebView.postMessage(JSON.stringify(r))); diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx index 48eed929..08fe7d89 100644 --- a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -26,6 +26,12 @@ export type ProviderPreviewValidation = { export type ProviderPreviewHandle = { getValues: () => Record; validate: () => Promise; + /** + * Resolves the provider's `maximumCharacters` against the seeded + * integration.additionalSettings. Returns null when the provider doesn't + * declare a limit (caller should treat as unbounded / fall back). + */ + getMaximumCharacters: () => number | null; }; export type ProviderPreviewProps = { @@ -137,25 +143,43 @@ export const ProviderPreviewComponent: FC = ({ useEffect(() => { if (!controlRef) return; + const resolveAdditionalSettings = (): unknown[] => { + const additional = (integration?.additionalSettings as + | string + | unknown[] + | undefined) ?? '[]'; + if (Array.isArray(additional)) return additional; + try { + const parsed = JSON.parse(additional || '[]'); + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } + }; controlRef.current = { getValues: () => form.getValues() as Record, + getMaximumCharacters: () => { + const max = meta?.maximumCharacters; + if (typeof max === 'number') return max; + if (typeof max === 'function') { + try { + return max(resolveAdditionalSettings()); + } catch { + return null; + } + } + return null; + }, validate: async () => { const formValid = await form.trigger(undefined, { shouldFocus: false }); const errs = flattenFormErrors(form.formState.errors); let customError: string | true = true; if (meta?.checkValidity) { try { - const additional = (integration?.additionalSettings as - | string - | undefined) ?? '[]'; - const additionalSettings = - typeof additional === 'string' - ? JSON.parse(additional || '[]') - : additional; customError = await meta.checkValidity( posts ?? [], form.getValues(), - additionalSettings, + resolveAdditionalSettings(), ); } catch (e: any) { customError = e?.message ?? 'checkValidity threw'; From c79965718f329ae506f3d601c0691d6763af72d4 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 17:14:10 +0700 Subject: [PATCH 37/80] feat: auth changes --- apps/frontend/src/app/(provider)/provider/[p]/page.tsx | 9 +++++++++ apps/frontend/src/components/layout/layout.context.tsx | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx index f0657bd3..97918986 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx @@ -3,6 +3,15 @@ * * URL: /provider/:p (e.g. /provider/tiktok, /provider/instagram) * + * --- Auth (native -> WebView, via URL) --- + * Append `?loggedAuth=` to the URL. The shared fetch wrapper + * (libraries/helpers/src/utils/custom.fetch.func.ts) reads that search + * param on every request and attaches it as the `auth` header, so any + * authenticated API call made by the SettingsComponent or checkValidity + * just works. The (provider) route is also excluded from the 401->/ + * redirect logic in LayoutContext, so a stale token won't yank the + * WebView away from the form. + * * --- Initial state (native -> WebView, push once) --- * Before loading the URL, the native side injects a global: * diff --git a/apps/frontend/src/components/layout/layout.context.tsx b/apps/frontend/src/components/layout/layout.context.tsx index 5f87efb6..202da580 100644 --- a/apps/frontend/src/components/layout/layout.context.tsx +++ b/apps/frontend/src/components/layout/layout.context.tsx @@ -28,7 +28,8 @@ function LayoutContextInner(params: { children: ReactNode }) { async (url: string, options: RequestInit, response: Response) => { if ( typeof window !== 'undefined' && - window.location.href.includes('/p/') + (window.location.href.includes('/p/') || + window.location.pathname.startsWith('/provider/')) ) { return true; } From 846954f059a19703f02808eafe6eb8bf210435d7 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 18:00:22 +0700 Subject: [PATCH 38/80] feat: bridge fix --- .../src/app/(provider)/provider/[p]/bridge.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx index d6cfd270..1fd474a5 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx @@ -36,9 +36,20 @@ declare global { export const ProviderPreviewBridge: FC<{ provider: string }> = ({ provider, }) => { - const [init] = useState(() => - typeof window !== 'undefined' ? window.__PROVIDER_INIT__ ?? {} : {}, - ); + // Read __PROVIDER_INIT__ in an effect, not via a useState lazy + // initializer. The initializer would run on the server (where `window` + // is undefined → {}), and during hydration React reuses the server + // state — so the seeded payload would never reach the form. Setting + // state inside an effect guarantees the read happens client-side + // after mount; useForm's `values` prop then reactively resets the + // form to the seed AFTER any field-level `register('x', { value })` + // defaults have been applied, so the seed wins. + const [init, setInit] = useState({}); + useEffect(() => { + if (typeof window !== 'undefined' && window.__PROVIDER_INIT__) { + setInit(window.__PROVIDER_INIT__); + } + }, []); const controlRef = useRef(null); From 65d23707ab8989d9f29bb64c4528667e694aa996 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 18:20:18 +0700 Subject: [PATCH 39/80] feat: fix bridge --- .../src/app/(provider)/provider/[p]/bridge.tsx | 12 +++++++++--- .../src/app/(provider)/provider/[p]/in-bridge.tsx | 13 +++++++++++++ .../src/app/(provider)/provider/[p]/page.tsx | 4 ++-- 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx diff --git a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx index 1fd474a5..fdc522ad 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/bridge.tsx @@ -33,7 +33,7 @@ declare global { } } -export const ProviderPreviewBridge: FC<{ provider: string }> = ({ +const ProviderPreviewBridge: FC<{ provider: string }> = ({ provider, }) => { // Read __PROVIDER_INIT__ in an effect, not via a useState lazy @@ -44,10 +44,10 @@ export const ProviderPreviewBridge: FC<{ provider: string }> = ({ // after mount; useForm's `values` prop then reactively resets the // form to the seed AFTER any field-level `register('x', { value })` // defaults have been applied, so the seed wins. - const [init, setInit] = useState({}); + const [init, setInit] = useState(null); useEffect(() => { if (typeof window !== 'undefined' && window.__PROVIDER_INIT__) { - setInit(window.__PROVIDER_INIT__); + setInit(window.__PROVIDER_INIT__ || {}); } }, []); @@ -75,6 +75,10 @@ export const ProviderPreviewBridge: FC<{ provider: string }> = ({ }; }, []); + if (!init) { + return null; + } + return ( = ({ /> ); }; + +export default ProviderPreviewBridge; diff --git a/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx new file mode 100644 index 00000000..66f60778 --- /dev/null +++ b/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx @@ -0,0 +1,13 @@ +'use client'; +import dynamic from 'next/dynamic'; +import { FC } from 'react'; +const Bridge = dynamic( + () => + import( + '@gitroom/frontend/components/provider-preview/preview.provider.component' + ).then((mod) => mod.ProviderPreviewComponent), + { ssr: false } +); +export const InBridge: FC<{ provider: string }> = ({ provider }) => { + return ; +}; diff --git a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx index 97918986..61403ce1 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/page.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/page.tsx @@ -55,7 +55,7 @@ * If a different channel is needed, adjust ./bridge.tsx — this page is only * a server wrapper that forwards the `:p` route param. */ -import { ProviderPreviewBridge } from './bridge'; +import { InBridge } from '@gitroom/frontend/app/(provider)/provider/[p]/in-bridge'; export default async function Page({ params, @@ -63,5 +63,5 @@ export default async function Page({ params: Promise<{ p: string }>; }) { const { p } = await params; - return ; + return ; } From 0a8fa5bff683ea972d86cf8795899d2c63836bf8 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 18:36:57 +0700 Subject: [PATCH 40/80] feat: fix bridge --- apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx b/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx index 66f60778..4d816724 100644 --- a/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx +++ b/apps/frontend/src/app/(provider)/provider/[p]/in-bridge.tsx @@ -4,8 +4,8 @@ import { FC } from 'react'; const Bridge = dynamic( () => import( - '@gitroom/frontend/components/provider-preview/preview.provider.component' - ).then((mod) => mod.ProviderPreviewComponent), + './bridge' + ).then((mod) => mod.default), { ssr: false } ); export const InBridge: FC<{ provider: string }> = ({ provider }) => { From 45e55c545d8e9446c87bf686ea2abf31f84c386b Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 18 Apr 2026 19:53:19 +0700 Subject: [PATCH 41/80] feat: add auth header --- apps/backend/src/main.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 16f24427..e4899974 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -27,6 +27,9 @@ async function start() { allowedHeaders: [ 'Content-Type', 'Authorization', + 'auth', + 'showorg', + 'impersonate', 'x-copilotkit-runtime-client-gql-version', ], exposedHeaders: [ From 88006a7614396e497346f2407b7d3e2ddd37e14e Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sun, 19 Apr 2026 13:48:15 +0700 Subject: [PATCH 42/80] feat: mobile app iframe --- .../src/api/routes/integrations.controller.ts | 9 +- apps/frontend/src/app/(provider)/layout.tsx | 12 ++- .../src/app/(provider)/provider/add/page.tsx | 6 ++ .../launches/add.provider.component.tsx | 95 ++++++++++++++----- .../new-layout/mobile.integration.tsx | 31 ++++++ .../preview.provider.component.tsx | 2 +- 6 files changed, 123 insertions(+), 32 deletions(-) create mode 100644 apps/frontend/src/app/(provider)/provider/add/page.tsx create mode 100644 apps/frontend/src/components/new-layout/mobile.integration.tsx diff --git a/apps/backend/src/api/routes/integrations.controller.ts b/apps/backend/src/api/routes/integrations.controller.ts index 36bdc884..5bd2f52e 100644 --- a/apps/backend/src/api/routes/integrations.controller.ts +++ b/apps/backend/src/api/routes/integrations.controller.ts @@ -195,6 +195,7 @@ export class IntegrationsController { @Param('integration') integration: string, @Query('refresh') refresh: string, @Query('externalUrl') externalUrl: string, + @Query('redirectUrl') redirectUrl: string, @Query('onboarding') onboarding: string, @GetOrgFromRequest() org: Organization ) { @@ -232,6 +233,10 @@ export class IntegrationsController { await ioRedis.set(`onboarding:${state}`, 'true', 'EX', 3600); } + if (redirectUrl) { + await ioRedis.set(`redirect:${state}`, redirectUrl, 'EX', 3600); + } + await ioRedis.set(`organization:${state}`, org.id, 'EX', 3600); await ioRedis.set(`login:${state}`, codeVerifier, 'EX', 3600); await ioRedis.set( @@ -448,9 +453,7 @@ export class IntegrationsController { } @Post('/moltbook/register') - async moltbookRegister( - @Body() body: { name: string; description: string } - ) { + async moltbookRegister(@Body() body: { name: string; description: string }) { try { const provider = new MoltbookProvider(); const result = await provider.registerAgent(body.name, body.description); diff --git a/apps/frontend/src/app/(provider)/layout.tsx b/apps/frontend/src/app/(provider)/layout.tsx index f711e7de..66c6dae0 100644 --- a/apps/frontend/src/app/(provider)/layout.tsx +++ b/apps/frontend/src/app/(provider)/layout.tsx @@ -1,3 +1,5 @@ +import { MantineWrapper } from '@gitroom/react/helpers/mantine.wrapper'; + export const dynamic = 'force-dynamic'; import '../global.scss'; import 'react-tooltip/dist/react-tooltip.css'; @@ -62,10 +64,12 @@ export default async function AppLayout({ children }: { children: ReactNode }) { : [] } > - - - {children} - + + + + {children} + + diff --git a/apps/frontend/src/app/(provider)/provider/add/page.tsx b/apps/frontend/src/app/(provider)/provider/add/page.tsx new file mode 100644 index 00000000..2610fdc3 --- /dev/null +++ b/apps/frontend/src/app/(provider)/provider/add/page.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { MobileIntegration } from '@gitroom/frontend/components/new-layout/mobile.integration'; + +export default async function Page() { + return ; +} diff --git a/apps/frontend/src/components/launches/add.provider.component.tsx b/apps/frontend/src/components/launches/add.provider.component.tsx index 53de90bd..96ad25d0 100644 --- a/apps/frontend/src/components/launches/add.provider.component.tsx +++ b/apps/frontend/src/components/launches/add.provider.component.tsx @@ -325,7 +325,8 @@ const ChromeExtensionWarning: FC<{ We will store your cookies securely to facilitate the connection.
  • - Postiz does not take responsibility for any issues arising or account termination due to the use of this method. + Postiz does not take responsibility for any issues arising or account + termination due to the use of this method.
@@ -380,8 +381,9 @@ export const AddProviderComponent: FC<{ invite: boolean; update?: () => void; onboarding?: boolean; + isMobile?: boolean; }> = (props) => { - const { update, social, article, onboarding } = props; + const { update, social, article, onboarding, isMobile } = props; const { isGeneral, extensionId } = useVariables(); const toaster = useToaster(); const router = useRouter(); @@ -418,26 +420,38 @@ export const AddProviderComponent: FC<{ modal.openModal({ title: `Add ${capitalize(identifier)}`, withCloseButton: true, + ...(isMobile ? { removeLayout: true, fullScreen: true } : {}), classNames: { modal: 'bg-transparent text-textColor', }, children: ( - { - window.location.href = `/integrations/social/${identifier}?code=${code}&state=${newState}${ - onboarding ? '&onboarding=true' : '' - }`; - }} - nonce={url} - /> +
+ { + window.location.href = `/integrations/social/${identifier}?code=${code}&state=${newState}${ + onboarding ? '&onboarding=true' : '' + }`; + }} + nonce={url} + /> +
), }); return; }; const gotoIntegration = async (externalUrl?: string) => { + // Mobile WebView: reuse the existing `externalUrl` param to + // carry the `postiz://` deep link so the backend redirects + // back to the iOS/Android app after OAuth completes, instead + // of the default web redirect. const params = [ - externalUrl ? `externalUrl=${externalUrl}` : '', + `externalUrl=${encodeURIComponent(externalUrl)}`, onboardingParam, + isMobile + ? `redirectUrl=${encodeURIComponent('postiz://integrations')}` + : '', ] .filter(Boolean) .join('&'); @@ -467,6 +481,23 @@ export const AddProviderComponent: FC<{ return; } + if (isMobile) { + // In the mobile WebView the OAuth provider (Google, Facebook, + // etc.) typically refuses in-WebView sign-in. Post the URL + // out to React Native so it can open the system browser; + // `window.open`/`location.href` aren't reliable here because + // RN WebView doesn't always route them through the native + // navigation intercept. The backend redirects back to the + // app via `postiz://` once OAuth completes. + const rn = (window as any).ReactNativeWebView; + if (rn && typeof rn.postMessage === 'function') { + rn.postMessage(JSON.stringify({ type: 'open-external', url })); + return; + } + window.open(url, '_blank'); + return; + } + window.location.href = url; }; if (isWeb3) { @@ -577,6 +608,7 @@ export const AddProviderComponent: FC<{ modal.openModal({ title: 'URL', withCloseButton: true, + ...(isMobile ? { removeLayout: true, fullScreen: true } : {}), classNames: { modal: 'bg-transparent text-textColor', }, @@ -588,16 +620,21 @@ export const AddProviderComponent: FC<{ modal.openModal({ title: t('add_provider_title', 'Add Provider'), withCloseButton: true, + ...(isMobile ? { removeLayout: true, fullScreen: true } : {}), classNames: { modal: 'bg-transparent text-textColor', }, children: ( - router.push(url)} - variables={customFields} - onboarding={onboarding} - /> +
+ router.push(url)} + variables={customFields} + onboarding={onboarding} + /> +
), }); return; @@ -614,8 +651,10 @@ export const AddProviderComponent: FC<{
{social @@ -648,9 +687,12 @@ export const AddProviderComponent: FC<{ 'data-tooltip-content': item.toolTip, } : {})} - className={ - 'w-full h-[100px] text-[14px] p-[10px] rounded-[8px] bg-newTableHeader text-textColor relative justify-center items-center flex flex-col gap-[10px] cursor-pointer' - } + className={clsx( + isMobile + ? 'flex-row h-[72px] p-[16px]' + : 'flex-col p-[10px] h-[100px] justify-center', + 'w-full text-[14px] rounded-[8px] bg-newTableHeader text-textColor relative items-center flex gap-[10px] cursor-pointer' + )} >
{item.identifier === 'youtube' ? ( @@ -666,9 +708,14 @@ export const AddProviderComponent: FC<{ /> )}
-
+
{item.name} - {!!item.toolTip && ( + {!!item.toolTip && !isMobile && ( { + const [integrations, setIntegrations] = useState(null as any); + const fetch = useFetch(); + + const loadIntegrations = useCallback(async () => { + setIntegrations(await (await fetch('/integrations')).json()); + }, []); + + useEffect(() => { + loadIntegrations(); + }, []); + + if (!integrations) { + return null; + } + + return ( + {}} + {...integrations} + /> + ); +}; diff --git a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx index 08fe7d89..96a94735 100644 --- a/apps/frontend/src/components/provider-preview/preview.provider.component.tsx +++ b/apps/frontend/src/components/provider-preview/preview.provider.component.tsx @@ -232,7 +232,7 @@ export const ProviderPreviewComponent: FC = ({ return ( -
+
{errors && errors.length > 0 && (
    From 0eddfb33043a92b22716d68198c21af2738dbf8f Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sun, 19 Apr 2026 21:13:12 +0200 Subject: [PATCH 43/80] feat: security policy changes - Add Response Timelines - Add Security Scope - Modify maintainer list for security maintainers --- SECURITY.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 8385dcb1..0a1819b5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,6 +4,17 @@ The Postiz app is committed to ensuring the security and integrity of our users' data. This security policy outlines our procedures for handling security vulnerabilities and our disclosure policy. +## Scope + +We, at Postiz, cover the following scopes for vulnerability disclosures: + +- The core repository for `postiz-app` (github.com/gitroomhq/postiz-app) +- All `gitroomhq` repositories related to Postiz (Containing `postiz` in the name / description / README.md) +- Official Postiz CLI tools and NPM packages +- Plugins maintained within the `gitroomhq` organization. + +Vulnerabilities in third-party dependencies or user-hosted infrastructure are outside of this scope. + ## Reporting Security Vulnerabilities If you discover a security vulnerability in the Postiz app, please report it through the [GitHub Security Advisory system](https://github.com/gitroomhq/postiz-app/security/advisories/new). @@ -18,7 +29,6 @@ When reporting a security vulnerability, please provide as much detail as possib If the report has immidiate urgency, please contact one (or more) of the maintainers via email: - @egelhaus ([E-Mail](mailto:egelhaus@ennogelhaus.de)) -- @nevo-david ([E-Mail](mailto:nevo@postiz.com)) ### AI Reports We do not evaluate or support security reports generated by LLMs (Large-Language Models / AI). Any report that seems to be generated by AI will be instantly closed on sight by one of our maintainers. @@ -27,10 +37,11 @@ However, if the AI report has been closely evaluated by human oversight, and pro ## Supported Versions This project currently only supports the latest release. We recommend that users always use the latest version of the Postiz app to ensure they have the latest security patches. +*CVE IDs will only be assigned to vulnerabilities affecting currently supported versions.* ## Disclosure Guidelines -We follow a private disclosure policy. If you discover a security vulnerability, please report it to us privately via email to one of the maintainers listed above. We will respond promptly to reports of vulnerabilities and work to resolve them as quickly as possible. +We follow a private disclosure policy. If you discover a security vulnerability, please report it to us privately via GitHub Security Advisories, and if immidiate urgency, via email as listed above. We will respond promptly to reports of vulnerabilities and work to resolve them as quickly as possible. We will not publicly disclose security vulnerabilities until a patch or fix is available to prevent malicious actors from exploiting the vulnerability before a fix is released. @@ -42,3 +53,13 @@ We take security vulnerabilities seriously and will respond promptly to reports - Developing a patch or fix for the vulnerability. - Releasing the patch or fix as soon as possible. - Notifying users of the vulnerability and the patch or fix. + +## Response Timelines + +We aim to follow these timelines: + +- **Initial Acknowledgement:** Within 72 hours of initial report. +- **Completed Triage / Verification:** Within 7 days of initial acknowledgement. +- **Critical Issue Remedition:** Within 90 days of completed triage. +- **Non-Critical Issue Remedition:** Within 180 days of completed triage. +- **CVE Publication:** Within 24 hours of remedition release. From 55a542485a6dcaaf457ffd8a74443e0f1b7efeed Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sun, 19 Apr 2026 22:58:05 +0200 Subject: [PATCH 44/80] feat: security additions --- SECURITY.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 0a1819b5..758ab66b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,12 +6,13 @@ The Postiz app is committed to ensuring the security and integrity of our users' ## Scope -We, at Postiz, cover the following scopes for vulnerability disclosures: +We, at Postiz (gitroomhq), cover the following scopes for vulnerability disclosures: - The core repository for `postiz-app` (github.com/gitroomhq/postiz-app) -- All `gitroomhq` repositories related to Postiz (Containing `postiz` in the name / description / README.md) -- Official Postiz CLI tools and NPM packages -- Plugins maintained within the `gitroomhq` organization. +- All `gitroomhq` repositories that are official components, tooling, or integrations of Postiz +- Docker images of Positz on GHCR. (published under gitroomhq) +- Official Postiz CLI tools and NPM packages (NPM org: @postiz) +- Plugins for Postiz maintained within the `gitroomhq` organization. Vulnerabilities in third-party dependencies or user-hosted infrastructure are outside of this scope. From 8cfb634b6682d7fe800c539cf32f98fa05f36972 Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sun, 19 Apr 2026 23:00:16 +0200 Subject: [PATCH 45/80] feat: security rewording --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 758ab66b..cc34bb03 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,9 +10,9 @@ We, at Postiz (gitroomhq), cover the following scopes for vulnerability disclosu - The core repository for `postiz-app` (github.com/gitroomhq/postiz-app) - All `gitroomhq` repositories that are official components, tooling, or integrations of Postiz -- Docker images of Positz on GHCR. (published under gitroomhq) +- Official Postiz container images published under `gitroomhq` on GHCR - Official Postiz CLI tools and NPM packages (NPM org: @postiz) -- Plugins for Postiz maintained within the `gitroomhq` organization. +- Plugins for Postiz maintained within the `gitroomhq` organization Vulnerabilities in third-party dependencies or user-hosted infrastructure are outside of this scope. From c61e061145226b8fe96f9311691fa5f8a86aedeb Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sun, 19 Apr 2026 23:09:01 +0200 Subject: [PATCH 46/80] feat: security refinement --- SECURITY.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index cc34bb03..d270c269 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,6 +16,11 @@ We, at Postiz (gitroomhq), cover the following scopes for vulnerability disclosu Vulnerabilities in third-party dependencies or user-hosted infrastructure are outside of this scope. +## Supported Versions + +This project currently only supports the latest release. We recommend that users always use the latest version of the Postiz app to ensure they have the latest security patches. +*CVE IDs will only be assigned to vulnerabilities affecting currently supported versions.* + ## Reporting Security Vulnerabilities If you discover a security vulnerability in the Postiz app, please report it through the [GitHub Security Advisory system](https://github.com/gitroomhq/postiz-app/security/advisories/new). @@ -23,26 +28,23 @@ If you discover a security vulnerability in the Postiz app, please report it thr When reporting a security vulnerability, please provide as much detail as possible, including: - A clear description of the vulnerability -- Proof of Concept +- Proof of concept (PoC), where possible - Steps to reproduce the vulnerability - Any relevant code or configuration files -If the report has immidiate urgency, please contact one (or more) of the maintainers via email: +If the report has immediate urgency, please contact one (or more) of the maintainers via email: - @egelhaus ([E-Mail](mailto:egelhaus@ennogelhaus.de)) ### AI Reports -We do not evaluate or support security reports generated by LLMs (Large-Language Models / AI). Any report that seems to be generated by AI will be instantly closed on sight by one of our maintainers. -However, if the AI report has been closely evaluated by human oversight, and provides a PoC (Proof of Concept) and a reproduction guide, with potential Impact for Postiz, we may evaluate your report like human-generated reports -## Supported Versions +Reports that appear to be LLM-generated without meaningful human analysis — typically lacking a working proof of concept, reproducible steps, or accurate impact assessment — will be closed without detailed response. -This project currently only supports the latest release. We recommend that users always use the latest version of the Postiz app to ensure they have the latest security patches. -*CVE IDs will only be assigned to vulnerabilities affecting currently supported versions.* +Reports that include AI-assisted analysis are welcome provided they have been validated by the reporter and include a proof of concept, reproduction steps, and impact assessment. ## Disclosure Guidelines -We follow a private disclosure policy. If you discover a security vulnerability, please report it to us privately via GitHub Security Advisories, and if immidiate urgency, via email as listed above. We will respond promptly to reports of vulnerabilities and work to resolve them as quickly as possible. +We follow a private disclosure policy. If you discover a security vulnerability, please report it to us privately via GitHub Security Advisories, and if immediate urgency, via email as listed above. We will respond promptly to reports of vulnerabilities and work to resolve them as quickly as possible. We will not publicly disclose security vulnerabilities until a patch or fix is available to prevent malicious actors from exploiting the vulnerability before a fix is released. @@ -59,8 +61,8 @@ We take security vulnerabilities seriously and will respond promptly to reports We aim to follow these timelines: -- **Initial Acknowledgement:** Within 72 hours of initial report. -- **Completed Triage / Verification:** Within 7 days of initial acknowledgement. -- **Critical Issue Remedition:** Within 90 days of completed triage. -- **Non-Critical Issue Remedition:** Within 180 days of completed triage. -- **CVE Publication:** Within 24 hours of remedition release. +- **Initial Acknowledgment:** Within 72 hours of initial report. +- **Completed Triage / Verification:** Within 7 days of initial acknowledgment. +- **Critical Issue Remediation:** Within 90 days of completed triage. +- **Non-Critical Issue Remediation:** Within 180 days of completed triage. +- **CVE Publication:** Within 24 hours of remediation release. \ No newline at end of file From ec4759e9349cb26027da7ce83d22b11154a78db6 Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Mon, 20 Apr 2026 03:11:24 +0200 Subject: [PATCH 47/80] feat: include cloud in security scope --- SECURITY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SECURITY.md b/SECURITY.md index d270c269..6ca97be5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,6 +12,7 @@ We, at Postiz (gitroomhq), cover the following scopes for vulnerability disclosu - All `gitroomhq` repositories that are official components, tooling, or integrations of Postiz - Official Postiz container images published under `gitroomhq` on GHCR - Official Postiz CLI tools and NPM packages (NPM org: @postiz) +- Postiz-Cloud related infrastructure & services. (API, Frontend, Configurations etc.) - Plugins for Postiz maintained within the `gitroomhq` organization Vulnerabilities in third-party dependencies or user-hosted infrastructure are outside of this scope. From 895128942684552f6d9063b25277c69298e8e653 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 20 Apr 2026 12:26:56 +0700 Subject: [PATCH 48/80] feat: fix previous agent messages --- apps/frontend/src/components/agents/agent.chat.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/components/agents/agent.chat.tsx b/apps/frontend/src/components/agents/agent.chat.tsx index e2bc282f..4fafd204 100644 --- a/apps/frontend/src/components/agents/agent.chat.tsx +++ b/apps/frontend/src/components/agents/agent.chat.tsx @@ -93,10 +93,11 @@ const LoadMessages: FC<{ id: string }> = ({ id }) => { const loadMessages = useCallback(async (idToSet: string) => { const data = await (await fetch(`/copilot/${idToSet}/list`)).json(); + console.log(data); setMessages( - data.uiMessages.map((p: any) => { + data.messages.map((p: any) => { return new TextMessage({ - content: p.content, + content: p.content.content, role: p.role, }); }) From fa5d7f4c40e1e6f11aeb227c57e936fd94347210 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Wed, 22 Apr 2026 11:09:42 +0700 Subject: [PATCH 49/80] feat: fix pop --- .../database/prisma/integrations/integration.repository.ts | 6 +++--- .../src/integrations/social/linkedin.page.provider.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts b/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts index cd0e5d79..15434d6c 100644 --- a/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/integrations/integration.repository.ts @@ -71,7 +71,7 @@ export class IntegrationRepository { async checkPreviousConnections(org: string, id: string) { const findIt = await this._integration.model.integration.findMany({ where: { - rootInternalId: id.split('_').pop(), + rootInternalId: id, }, select: { organizationId: true, @@ -263,7 +263,7 @@ export class IntegrationRepository { ...postTimes, organizationId: org, refreshNeeded: false, - rootInternalId: internalId.split('_').pop(), + rootInternalId: internalId, ...(customInstanceDetails ? { customInstanceDetails } : {}), additionalSettings: additionalSettings ? JSON.stringify(additionalSettings) @@ -304,7 +304,7 @@ export class IntegrationRepository { internalId: internalId, }, }) - )?.rootInternalId || internalId.split('_').pop()!; + )?.rootInternalId || internalId; await this._integration.model.integration.updateMany({ where: { diff --git a/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts b/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts index a8aed73a..a87f3a6f 100644 --- a/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/linkedin.page.provider.ts @@ -254,7 +254,7 @@ export class LinkedinPageProvider ).json(); return { - id: `p_${id}`, + id: id, accessToken, refreshToken, expiresIn, From e51cae16147be77712a62fbc6fb670ada8a9f385 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Wed, 22 Apr 2026 13:09:39 +0700 Subject: [PATCH 50/80] feat: fix analytics --- .../src/integrations/social/instagram.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts index cc7f095f..74ace32b 100644 --- a/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts @@ -804,7 +804,7 @@ export class InstagramProvider date: number, type = 'graph.facebook.com' ): Promise { - const until = dayjs().endOf('day').unix(); + const until = dayjs().startOf('day').unix(); const since = dayjs().subtract(date, 'day').unix(); const { data, ...all } = await ( From da448012dd87e94944cbe83a38e7fd023269ec46 Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Wed, 22 Apr 2026 16:20:52 +0200 Subject: [PATCH 51/80] feat: remove insecure & unnecessary workflow. --- .github/workflows/pr-docker-build.yml | 38 --------------------------- 1 file changed, 38 deletions(-) delete mode 100644 .github/workflows/pr-docker-build.yml diff --git a/.github/workflows/pr-docker-build.yml b/.github/workflows/pr-docker-build.yml deleted file mode 100644 index 2c1832e6..00000000 --- a/.github/workflows/pr-docker-build.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Build and Publish PR Docker Image - -on: - pull_request_target: - types: [opened, synchronize] - -permissions: write-all - -jobs: - build-and-publish: - runs-on: ubuntu-latest - - environment: - name: build-pr - - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha }} - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ github.token }} - - - name: Set image tag - id: vars - run: echo "IMAGE_TAG=ghcr.io/gitroomhq/postiz-app-pr:${{ github.event.pull_request.number }}" >> $GITHUB_ENV - - - name: Build Docker image from Dockerfile.dev - run: docker build -f Dockerfile.dev -t $IMAGE_TAG . - - - name: Push Docker image to GHCR - run: docker push $IMAGE_TAG From 071143dcb01cdeb9d5d7019892f4c6ff7b19dbeb Mon Sep 17 00:00:00 2001 From: Nevo David Date: Wed, 22 Apr 2026 22:25:48 +0700 Subject: [PATCH 52/80] feat: security fix --- .../src/api/routes/public.controller.ts | 3 ++ .../v1/public.integrations.controller.ts | 13 ++++--- .../src/dtos/webhooks/ssrf.safe.dispatcher.ts | 39 +++++++++++++++++++ .../src/upload/cloudflare.storage.ts | 10 ++++- .../src/upload/local.storage.ts | 10 ++++- 5 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 libraries/nestjs-libraries/src/dtos/webhooks/ssrf.safe.dispatcher.ts diff --git a/apps/backend/src/api/routes/public.controller.ts b/apps/backend/src/api/routes/public.controller.ts index 698f5c75..e86578af 100644 --- a/apps/backend/src/api/routes/public.controller.ts +++ b/apps/backend/src/api/routes/public.controller.ts @@ -27,6 +27,7 @@ import { Readable, pipeline } from 'stream'; import { promisify } from 'util'; import { OnlyURL } from '@gitroom/nestjs-libraries/dtos/webhooks/webhooks.dto'; import { isSafePublicHttpsUrl } from '@gitroom/nestjs-libraries/dtos/webhooks/webhook.url.validator'; +import { ssrfSafeDispatcher } from '@gitroom/nestjs-libraries/dtos/webhooks/ssrf.safe.dispatcher'; const pump = promisify(pipeline); @@ -191,6 +192,8 @@ export class PublicController { r = await fetch(currentUrl, { signal: ac.signal, redirect: 'manual', + // @ts-ignore — undici option, not in lib.dom fetch types + dispatcher: ssrfSafeDispatcher, }); if (r.status >= 300 && r.status < 400) { diff --git a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts index 2c9bf934..d2a74efe 100644 --- a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts +++ b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts @@ -33,8 +33,8 @@ import { VideoFunctionDto } from '@gitroom/nestjs-libraries/dtos/videos/video.fu import { UploadDto } from '@gitroom/nestjs-libraries/dtos/media/upload.dto'; import { NotificationService } from '@gitroom/nestjs-libraries/database/prisma/notifications/notification.service'; import { GetNotificationsDto } from '@gitroom/nestjs-libraries/dtos/notifications/get.notifications.dto'; -import axios from 'axios'; import { Readable } from 'stream'; +import { ssrfSafeDispatcher } from '@gitroom/nestjs-libraries/dtos/webhooks/ssrf.safe.dispatcher'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { fromBuffer } = require('file-type'); @@ -96,11 +96,14 @@ export class PublicIntegrationsController { @Body() body: UploadDto ) { Sentry.metrics.count('public_api-request', 1); - const response = await axios.get(body.url, { - responseType: 'arraybuffer', + const response = await fetch(body.url, { + // @ts-ignore — undici option, not in lib.dom fetch types + dispatcher: ssrfSafeDispatcher, }); - - const buffer = Buffer.from(response.data); + if (!response.ok) { + throw new HttpException({ msg: 'Failed to fetch URL' }, 400); + } + const buffer = Buffer.from(await response.arrayBuffer()); const detected = await fromBuffer(buffer); if (!detected || !PUBLIC_API_ALLOWED_MIME.has(detected.mime)) { throw new HttpException({ msg: 'Unsupported file type.' }, 400); diff --git a/libraries/nestjs-libraries/src/dtos/webhooks/ssrf.safe.dispatcher.ts b/libraries/nestjs-libraries/src/dtos/webhooks/ssrf.safe.dispatcher.ts new file mode 100644 index 00000000..f72317f8 --- /dev/null +++ b/libraries/nestjs-libraries/src/dtos/webhooks/ssrf.safe.dispatcher.ts @@ -0,0 +1,39 @@ +import { Agent } from 'undici'; +import dns from 'node:dns'; +import net from 'node:net'; +import { isBlockedIp } from './webhook.url.validator'; + +// Pins DNS resolution: every resolved IP is checked with `isBlockedIp` and +// the caller (undici) connects to that same set. Closes the TOCTOU window +// `isSafePublicHttpsUrl` alone leaves open (see GHSA-f7jj-p389-4w45). +export const ssrfSafeDispatcher = new Agent({ + connect: { + lookup(hostname, options, callback) { + if (net.isIP(hostname)) { + const family = net.isIP(hostname); + if (isBlockedIp(hostname)) { + return callback(new Error('Blocked IP'), '', 0); + } + return options && (options as any).all + ? callback(null, [{ address: hostname, family }] as any, family) + : callback(null, hostname, family); + } + + dns.lookup(hostname, options, (err, address: any, family: any) => { + if (err) return callback(err, '', 0); + if (Array.isArray(address)) { + for (const entry of address) { + if (isBlockedIp(entry.address)) { + return callback(new Error('Blocked IP'), '', 0); + } + } + return callback(null, address as any, 0); + } + if (isBlockedIp(address)) { + return callback(new Error('Blocked IP'), '', 0); + } + callback(null, address, family); + }); + }, + }, +}); diff --git a/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts b/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts index 1ada0ac7..032646de 100644 --- a/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts +++ b/libraries/nestjs-libraries/src/upload/cloudflare.storage.ts @@ -6,6 +6,8 @@ import mime from 'mime-types'; import { getExtension } from 'mime'; import { IUploadProvider } from './upload.interface'; import axios from 'axios'; +import { isSafePublicHttpsUrl } from '@gitroom/nestjs-libraries/dtos/webhooks/webhook.url.validator'; +import { ssrfSafeDispatcher } from '@gitroom/nestjs-libraries/dtos/webhooks/ssrf.safe.dispatcher'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { fromBuffer } = require('file-type'); @@ -75,7 +77,13 @@ class CloudflareStorage implements IUploadProvider { } async uploadSimple(path: string) { - const loadImage = await fetch(path); + if (!(await isSafePublicHttpsUrl(path))) { + throw new Error('Unsafe URL'); + } + const loadImage = await fetch(path, { + // @ts-ignore — undici option, not in lib.dom fetch types + dispatcher: ssrfSafeDispatcher, + }); const body = Buffer.from(await loadImage.arrayBuffer()); const detected = await fromBuffer(body); if (!detected || !ALLOWED_MIME_TYPES.has(detected.mime)) { diff --git a/libraries/nestjs-libraries/src/upload/local.storage.ts b/libraries/nestjs-libraries/src/upload/local.storage.ts index 90cc42c5..3c064f69 100644 --- a/libraries/nestjs-libraries/src/upload/local.storage.ts +++ b/libraries/nestjs-libraries/src/upload/local.storage.ts @@ -3,6 +3,8 @@ import { mkdirSync, unlink, writeFileSync } from 'fs'; // @ts-ignore import mime from 'mime'; import { extname } from 'path'; +import { isSafePublicHttpsUrl } from '@gitroom/nestjs-libraries/dtos/webhooks/webhook.url.validator'; +import { ssrfSafeDispatcher } from '@gitroom/nestjs-libraries/dtos/webhooks/ssrf.safe.dispatcher'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { fromBuffer } = require('file-type'); @@ -24,7 +26,13 @@ export class LocalStorage implements IUploadProvider { constructor(private uploadDirectory: string) {} async uploadSimple(path: string) { - const loadImage = await fetch(path); + if (!(await isSafePublicHttpsUrl(path))) { + throw new Error('Unsafe URL'); + } + const loadImage = await fetch(path, { + // @ts-ignore — undici option, not in lib.dom fetch types + dispatcher: ssrfSafeDispatcher, + }); const contentType = loadImage?.headers?.get('content-type') || loadImage?.headers?.get('Content-Type'); From d75662b56a7d3138ac91ff2f02bbe729560f43f1 Mon Sep 17 00:00:00 2001 From: Ahmed Mousa Date: Sat, 25 Apr 2026 16:13:58 -0400 Subject: [PATCH 53/80] feat: add X_URL to docker-compose and .env.example Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .env.example | 1 + docker-compose.yaml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.env.example b/.env.example index e6fc8396..4eba944b 100644 --- a/.env.example +++ b/.env.example @@ -40,6 +40,7 @@ STORAGE_PROVIDER="local" #NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY="" # Social Media API Settings +X_URL="" X_API_KEY="" X_API_SECRET="" LINKEDIN_CLIENT_ID="" diff --git a/docker-compose.yaml b/docker-compose.yaml index 7bf244d7..208053fd 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -31,6 +31,8 @@ services: # CLOUDFLARE_REGION: 'auto' # === Social Media API Settings + X_URL: '' + X_URL: '' X_API_KEY: '' X_API_SECRET: '' LINKEDIN_CLIENT_ID: '' From b91ffdc9c37b1197aceb283b2a71ac63846cfaf9 Mon Sep 17 00:00:00 2001 From: Ahmed Mousa Date: Sat, 25 Apr 2026 16:17:55 -0400 Subject: [PATCH 54/80] fix: remove duplicate X_URL entry in docker-compose Co-Authored-By: Claude Sonnet 4.6 (1M context) --- docker-compose.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 208053fd..d65f45d7 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -32,7 +32,6 @@ services: # === Social Media API Settings X_URL: '' - X_URL: '' X_API_KEY: '' X_API_SECRET: '' LINKEDIN_CLIENT_ID: '' From 4e7864c9297f41f00b5d905cc5cc1254fb170964 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sun, 26 Apr 2026 14:58:19 +0700 Subject: [PATCH 55/80] feat: better MCP options --- .../public-api/public.component.tsx | 75 ++++++++++++------- .../integrations/social/facebook.provider.ts | 1 + 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/apps/frontend/src/components/public-api/public.component.tsx b/apps/frontend/src/components/public-api/public.component.tsx index 4d26dc8b..a27ec7a5 100644 --- a/apps/frontend/src/components/public-api/public.component.tsx +++ b/apps/frontend/src/components/public-api/public.component.tsx @@ -213,10 +213,17 @@ const McpSection = ({ user.publicApi ); + const remoteUrl = `${mcpBase}/mcp/${user.publicApi}`; + const cliUrl = `${mcpBase}/mcp`; + const maskedConfig = revealed ? config : config.replace(new RegExp(user.publicApi.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '*'.repeat(user.publicApi.length)); + const maskedRemoteUrl = revealed + ? remoteUrl + : remoteUrl.replace(user.publicApi, '*'.repeat(user.publicApi.length)); + return (
    @@ -261,40 +268,47 @@ const McpSection = ({ onClick={() => setMethod(m)} > {m === 'header' - ? t('authorization_header', 'Authorization Header') - : t('api_key_in_url', 'API Key in URL')} + ? t('cli_claude_code_codex', 'CLI (Claude Code / Codex)') + : t('remote_servers', 'Remote servers (ChatGPT, Claude)')} ))}
    -
    -
    - {t('mcp_client', 'Client')} + {method === 'header' && ( +
    +
    + {t('mcp_client', 'Client')} +
    +
    + {mcpClients.map((client) => ( + + ))} +
    -
    - {mcpClients.map((client) => ( - - ))} -
    -
    + )}
    - {hint} + {method === 'header' + ? hint + : t( + 'remote_server_url_hint', + 'Paste this URL into your remote MCP client (ChatGPT, Claude, etc.).' + )}
    -            {maskedConfig}
    +            {method === 'header' ? maskedConfig : maskedRemoteUrl}
               
    - + + {method === 'header' && ( + + )}
    diff --git a/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts b/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts index 98e41519..ab03455a 100644 --- a/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/facebook.provider.ts @@ -656,3 +656,4 @@ export class FacebookProvider extends SocialAbstract implements SocialProvider { } } } + From 90b2581048b968e1e79e3068535c175ee730f18c Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sun, 26 Apr 2026 15:04:01 +0700 Subject: [PATCH 56/80] feat: better information on use Postiz for developers --- .../public-api/public.component.tsx | 142 +++++++++++------- 1 file changed, 88 insertions(+), 54 deletions(-) diff --git a/apps/frontend/src/components/public-api/public.component.tsx b/apps/frontend/src/components/public-api/public.component.tsx index a27ec7a5..1a3eed98 100644 --- a/apps/frontend/src/components/public-api/public.component.tsx +++ b/apps/frontend/src/components/public-api/public.component.tsx @@ -358,13 +358,28 @@ const McpSection = ({ ); }; -const cliSteps = [ +const localCliSteps = [ { label: 'Install the CLI', code: 'npm install -g postiz', }, { - label: 'Set your API key, copy it to your secret files', + label: 'Run: postiz auth:login', + code: 'postiz auth:login', + }, + { + label: 'Install the Postiz skill for your AI agent', + code: 'npx skills add gitroomhq/postiz-agent', + }, +] as const; + +const ciCliSteps = [ + { + label: 'Install the CLI', + code: 'npm install -g postiz', + }, + { + label: 'Set your API key as an environment variable', code: 'export POSTIZ_API_KEY="{API_KEY}"', }, { @@ -373,31 +388,29 @@ const cliSteps = [ }, ] as const; -const CliSection = ({ - apiKey, - backendUrl, -}: { - apiKey: string; - backendUrl: string; -}) => { +const CliSection = ({ apiKey }: { apiKey: string }) => { const t = useT(); - const toaster = useToaster(); + const [mode, setMode] = useState<'local' | 'ci'>('local'); const [revealed, setRevealed] = useState(false); - const steps = cliSteps.map((step) => ({ - ...step, - code: step.code.replace('{API_KEY}', apiKey), - })); + const steps = + mode === 'local' + ? localCliSteps.map((step) => ({ ...step })) + : ciCliSteps.map((step) => ({ + ...step, + code: step.code.replace('{API_KEY}', apiKey), + })); - const maskedSteps = steps.map((step) => ({ - ...step, - code: revealed - ? step.code - : step.code.replace( - new RegExp(apiKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), - '*'.repeat(apiKey.length) - ), - })); + const displaySteps = + mode === 'ci' && !revealed + ? steps.map((step) => ({ + ...step, + code: step.code.replace( + new RegExp(apiKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), + '*'.repeat(apiKey.length) + ), + })) + : steps; return (
    @@ -425,7 +438,26 @@ const CliSection = ({
- {maskedSteps.map((step, i) => ( +
+ {(['local', 'ci'] as const).map((m) => ( + + ))} +
+ {displaySteps.map((step, i) => (
{i + 1}. {step.label} @@ -436,36 +468,38 @@ const CliSection = ({
))}
- + + {revealed ? ( + <> + + + + + ) : ( + <> + + + + )} + + {revealed ? t('hide', 'Hide') : t('reveal', 'Reveal')} + + )} s.code).join(' && ')} label={t('copy_all', 'Copy All')} @@ -666,7 +700,7 @@ const PublicApiContent = () => {
- +
From cdcf63bf6bdda31668359ccccd41e78d5d96299a Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 27 Apr 2026 13:17:12 +0700 Subject: [PATCH 57/80] feat: when creating a postiz app, allow localhost --- .../nestjs-libraries/src/dtos/oauth/create-oauth-app.dto.ts | 2 +- .../nestjs-libraries/src/dtos/oauth/update-oauth-app.dto.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/nestjs-libraries/src/dtos/oauth/create-oauth-app.dto.ts b/libraries/nestjs-libraries/src/dtos/oauth/create-oauth-app.dto.ts index aca4dab4..b9fe002a 100644 --- a/libraries/nestjs-libraries/src/dtos/oauth/create-oauth-app.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/oauth/create-oauth-app.dto.ts @@ -17,6 +17,6 @@ export class CreateOAuthAppDto { @IsString() @IsDefined() - @IsUrl() + @IsUrl({ require_tld: false }) redirectUrl: string; } diff --git a/libraries/nestjs-libraries/src/dtos/oauth/update-oauth-app.dto.ts b/libraries/nestjs-libraries/src/dtos/oauth/update-oauth-app.dto.ts index 3cb4461b..e2a537a7 100644 --- a/libraries/nestjs-libraries/src/dtos/oauth/update-oauth-app.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/oauth/update-oauth-app.dto.ts @@ -17,6 +17,6 @@ export class UpdateOAuthAppDto { @IsString() @IsOptional() - @IsUrl() + @IsUrl({ require_tld: false }) redirectUrl?: string; } From 7236213ea4520bd67b45688c2787d1f4586b3b51 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 27 Apr 2026 14:50:55 +0700 Subject: [PATCH 58/80] feat: fix xss --- .../src/app/(app)/(preview)/p/[id]/page.tsx | 3 +- .../src/utils/sanitize.post.content.ts | 36 ++ .../src/dtos/posts/create.post.dto.ts | 4 +- package.json | 3 +- pnpm-lock.yaml | 319 +++++++++++++++++- 5 files changed, 354 insertions(+), 11 deletions(-) create mode 100644 libraries/helpers/src/utils/sanitize.post.content.ts diff --git a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx index fd8a1537..fb12181d 100644 --- a/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx +++ b/apps/frontend/src/app/(app)/(preview)/p/[id]/page.tsx @@ -1,4 +1,5 @@ import { internalFetch } from '@gitroom/helpers/utils/internal.fetch'; +import { sanitizePostContent } from '@gitroom/helpers/utils/sanitize.post.content'; export const dynamic = 'force-dynamic'; import { Metadata } from 'next'; import { isGeneralServerSide } from '@gitroom/helpers/utils/is.general.server.side'; @@ -146,7 +147,7 @@ export default async function Auth(
diff --git a/libraries/helpers/src/utils/sanitize.post.content.ts b/libraries/helpers/src/utils/sanitize.post.content.ts new file mode 100644 index 00000000..9f2d9861 --- /dev/null +++ b/libraries/helpers/src/utils/sanitize.post.content.ts @@ -0,0 +1,36 @@ +import DOMPurify from 'isomorphic-dompurify'; + +const ALLOWED_TAGS = [ + 'p', + 'br', + 'strong', + 'u', + 'a', + 'ul', + 'li', + 'h1', + 'h2', + 'h3', + 'span', +]; + +const ALLOWED_ATTR = [ + 'href', + 'target', + 'rel', + 'class', + 'data-mention-id', + 'data-mention-label', +]; + +export const sanitizePostContent = (value: unknown): string => { + if (typeof value !== 'string' || !value) { + return ''; + } + + return DOMPurify.sanitize(value, { + ALLOWED_TAGS, + ALLOWED_ATTR, + ALLOWED_URI_REGEXP: /^(?:https?:|mailto:|\/|#)/i, + }); +}; diff --git a/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts b/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts index 21001e4c..89c86fa3 100644 --- a/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts +++ b/libraries/nestjs-libraries/src/dtos/posts/create.post.dto.ts @@ -12,7 +12,7 @@ import { ValidateIf, ValidateNested, } from 'class-validator'; -import { Type } from 'class-transformer'; +import { Transform, Type } from 'class-transformer'; import { MediaDto } from '@gitroom/nestjs-libraries/dtos/media/media.dto'; import { allProviders, @@ -20,6 +20,7 @@ import { EmptySettings, } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/all.providers.settings'; import { ValidContent } from '@gitroom/helpers/utils/valid.images'; +import { sanitizePostContent } from '@gitroom/helpers/utils/sanitize.post.content'; export class Integration { @IsDefined() @@ -31,6 +32,7 @@ export class PostContent { @IsDefined() @IsString() @Validate(ValidContent) + @Transform(({ value }) => sanitizePostContent(value)) content: string; @IsOptional() diff --git a/package.json b/package.json index 717083f2..e9af9fc5 100644 --- a/package.json +++ b/package.json @@ -166,6 +166,7 @@ "evp_bytestokey": "^1.0.3", "facebook-nodejs-business-sdk": "^21.0.5", "fast-xml-parser": "^4.5.1", + "file-type": "^16.5.4", "google-auth-library": "^9.11.0", "googleapis": "^137.1.0", "hot-reload-extension-vite": "^1.0.13", @@ -175,12 +176,12 @@ "i18next-resources-to-backend": "^1.2.1", "image-to-pdf": "^3.0.2", "ioredis": "^5.3.2", + "isomorphic-dompurify": "^3.10.0", "json-to-graphql-query": "^2.2.5", "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "mastra": "^1.3.19", "md5": "^2.3.0", - "file-type": "^16.5.4", "mime": "^3.0.0", "mime-types": "^2.1.35", "multer": "^1.4.5-lts.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ab9b5933..604e01c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -424,6 +424,9 @@ importers: ioredis: specifier: ^5.3.2 version: 5.10.0 + isomorphic-dompurify: + specifier: ^3.10.0 + version: 3.10.0(@noble/hashes@2.0.1)(canvas@2.11.2) json-to-graphql-query: specifier: ^2.2.5 version: 2.3.0 @@ -1049,6 +1052,21 @@ packages: peerDependencies: '@types/json-schema': ^7.0.15 + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@atproto/api@0.15.27': resolution: {integrity: sha512-ok/WGafh1nz4t8pEQGtAF/32x2E2VDWU4af6BajkO5Gky2jp2q6cv6aB2A5yuvNNcc3XkYMYipsqVHVwLPMF9g==} @@ -1947,6 +1965,10 @@ packages: '@borewit/text-codec@0.2.1': resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@browserbasehq/sdk@2.7.0': resolution: {integrity: sha512-1iwuj3fChplMq+S66M9tGb9ZXA4e7Vi8MjqQQ6/T6rzoAWLGfDnEAPbgTOU479o+Mi3of5/6YXk1oIHKTw0NBw==} @@ -2022,6 +2044,42 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.0': + resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.0': + resolution: {integrity: sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.3': + resolution: {integrity: sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@cypress/request-promise@5.0.0': resolution: {integrity: sha512-eKdYVpa9cBEw2kTBlHeu1PP16Blwtum6QHg/u9s/MoHkZfuo1pRGka1VlUHXF5kdew82BvOJVVGk0x8X0nbp+w==} engines: {node: '>=0.10.0'} @@ -2614,6 +2672,15 @@ packages: resolution: {integrity: sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==} engines: {node: '>=18'} + '@exodus/bytes@1.15.0': + resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} @@ -9705,6 +9772,9 @@ packages: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -10483,6 +10553,10 @@ packages: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.2.2: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} @@ -10549,6 +10623,10 @@ packages: resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} engines: {node: '>=14'} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -10809,6 +10887,9 @@ packages: resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==} engines: {node: '>=20'} + dompurify@3.4.1: + resolution: {integrity: sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -10941,6 +11022,10 @@ packages: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -12187,6 +12272,10 @@ packages: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -12697,6 +12786,10 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} + isomorphic-dompurify@3.10.0: + resolution: {integrity: sha512-Gj2duy4dACsP/FLPvwJ3+MXTlGtOo+O4yfpA0jdxuz/sZlbZzazGzScajOHRwH7PCy4j3bh5ibLGJY4/Rb5kGQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + isomorphic-ws@4.0.1: resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} peerDependencies: @@ -13008,6 +13101,15 @@ packages: canvas: optional: true + jsdom@29.1.0: + resolution: {integrity: sha512-YNUc7fB9QuvSSQWfrH0xF+TyABkxUwx8sswgIDaCrw4Hol8BghdZDkITtZheRJeMtzWlnTfsM3bBBusRvpO1wg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -13519,14 +13621,14 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.6: - resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} - engines: {node: 20 || >=22} - lru-cache@11.2.7: resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} engines: {node: 20 || >=22} + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} + engines: {node: 20 || >=22} + lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -13686,6 +13788,9 @@ packages: mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -14731,6 +14836,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + parseley@0.12.1: resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} @@ -16817,10 +16925,17 @@ packages: tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + tldts-core@7.0.28: + resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==} + tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true + tldts@7.0.28: + resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==} + hasBin: true + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -16881,6 +16996,10 @@ packages: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -16892,6 +17011,10 @@ packages: resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} engines: {node: '>=14'} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + transloadit@3.0.2: resolution: {integrity: sha512-FvhKs0EBiQufK29irGLM/4aMIrfU5S/TiHB3h+DcO2hjRnVVM2WC278UQJCrNO4L/REE8IKWx/mQzQW2MrrLsg==} engines: {node: '>= 10.0.0'} @@ -17202,6 +17325,10 @@ packages: resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} engines: {node: '>=20.18.1'} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} + engines: {node: '>=20.18.1'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -17691,6 +17818,10 @@ packages: resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} engines: {node: '>=14'} + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -17732,6 +17863,10 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + webpack-node-externals@3.0.0: resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} engines: {node: '>=6'} @@ -17785,6 +17920,10 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + whatwg-url@11.0.0: resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} engines: {node: '>=12'} @@ -17793,6 +17932,10 @@ packages: resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} engines: {node: '>=14'} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -17924,6 +18067,10 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + xml2js@0.5.0: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} @@ -18348,6 +18495,26 @@ snapshots: '@types/json-schema': 7.0.15 js-yaml: 4.1.1 + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} + '@atproto/api@0.15.27': dependencies: '@atproto/common-web': 0.4.18 @@ -19898,6 +20065,10 @@ snapshots: '@borewit/text-codec@0.2.1': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + '@browserbasehq/sdk@2.7.0': dependencies: '@types/node': 18.16.9 @@ -20250,6 +20421,30 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.3(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + '@cypress/request-promise@5.0.0(@cypress/request@3.0.10)(request@2.88.2)': dependencies: '@cypress/request': 3.0.10 @@ -20679,6 +20874,10 @@ snapshots: '@ethereumjs/rlp': 5.0.2 ethereum-cryptography: 2.2.1 + '@exodus/bytes@1.15.0(@noble/hashes@2.0.1)': + optionalDependencies: + '@noble/hashes': 2.0.1 + '@expo/devcert@1.2.1': dependencies: '@expo/sudo-prompt': 9.3.2 @@ -29241,6 +29440,10 @@ snapshots: - encoding - supports-color + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + big.js@5.2.2: {} big.js@6.2.2: {} @@ -30148,6 +30351,11 @@ snapshots: mdn-data: 2.0.30 source-map-js: 1.2.1 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + css-what@6.2.2: {} cssesc@3.0.0: {} @@ -30203,6 +30411,13 @@ snapshots: whatwg-mimetype: 3.0.0 whatwg-url: 12.0.1 + data-urls@7.0.0(@noble/hashes@2.0.1): + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@2.0.1) + transitivePeerDependencies: + - '@noble/hashes' + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -30432,6 +30647,10 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 + dompurify@3.4.1: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -30573,6 +30792,8 @@ snapshots: entities@7.0.1: {} + entities@8.0.0: {} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -32384,6 +32605,12 @@ snapshots: dependencies: whatwg-encoding: 2.0.0 + html-encoding-sniffer@6.0.0(@noble/hashes@2.0.1): + dependencies: + '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) + transitivePeerDependencies: + - '@noble/hashes' + html-entities@2.6.0: {} html-escaper@2.0.2: {} @@ -32919,6 +33146,14 @@ snapshots: isobject@3.0.1: {} + isomorphic-dompurify@3.10.0(@noble/hashes@2.0.1)(canvas@2.11.2): + dependencies: + dompurify: 3.4.1 + jsdom: 29.1.0(@noble/hashes@2.0.1)(canvas@2.11.2) + transitivePeerDependencies: + - '@noble/hashes' + - canvas + isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10)): dependencies: ws: 7.5.10(bufferutil@4.1.0)(utf-8-validate@5.0.10) @@ -33494,6 +33729,34 @@ snapshots: - supports-color - utf-8-validate + jsdom@29.1.0(@noble/hashes@2.0.1)(canvas@2.11.2): + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.3(css-tree@3.2.1) + '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) + css-tree: 3.2.1 + data-urls: 7.0.0(@noble/hashes@2.0.1) + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0(@noble/hashes@2.0.1) + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.3.5 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.25.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@2.0.1) + xml-name-validator: 5.0.0 + optionalDependencies: + canvas: 2.11.2 + transitivePeerDependencies: + - '@noble/hashes' + jsesc@3.1.0: {} json-bigint@1.0.0: @@ -33935,10 +34198,10 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.6: {} - lru-cache@11.2.7: {} + lru-cache@11.3.5: {} + lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 @@ -34261,6 +34524,8 @@ snapshots: mdn-data@2.0.30: {} + mdn-data@2.27.1: {} + mdurl@2.0.0: {} media-typer@0.3.0: {} @@ -35635,6 +35900,10 @@ snapshots: dependencies: entities: 6.0.1 + parse5@8.0.1: + dependencies: + entities: 8.0.0 + parseley@0.12.1: dependencies: leac: 0.6.0 @@ -35675,7 +35944,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.2.6 + lru-cache: 11.2.7 minipass: 7.1.3 path-to-regexp@0.1.12: {} @@ -38223,10 +38492,16 @@ snapshots: tldts-core@6.1.86: {} + tldts-core@7.0.28: {} + tldts@6.1.86: dependencies: tldts-core: 6.1.86 + tldts@7.0.28: + dependencies: + tldts-core: 7.0.28 + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -38287,6 +38562,10 @@ snapshots: dependencies: tldts: 6.1.86 + tough-cookie@6.0.1: + dependencies: + tldts: 7.0.28 + tr46@0.0.3: {} tr46@3.0.0: @@ -38297,6 +38576,10 @@ snapshots: dependencies: punycode: 2.3.1 + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + transloadit@3.0.2: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -38619,6 +38902,8 @@ snapshots: undici@7.22.0: {} + undici@7.25.0: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -38780,7 +39065,7 @@ snapshots: chokidar: 5.0.0 destr: 2.0.5 h3: 1.15.5 - lru-cache: 11.2.6 + lru-cache: 11.2.7 node-fetch-native: 1.6.7 ofetch: 1.5.1 ufo: 1.6.3 @@ -39139,6 +39424,10 @@ snapshots: dependencies: xml-name-validator: 4.0.0 + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -39184,6 +39473,8 @@ snapshots: webidl-conversions@7.0.0: {} + webidl-conversions@8.0.1: {} + webpack-node-externals@3.0.0: {} webpack-sources@3.3.4: {} @@ -39270,6 +39561,8 @@ snapshots: whatwg-mimetype@4.0.0: {} + whatwg-mimetype@5.0.0: {} + whatwg-url@11.0.0: dependencies: tr46: 3.0.0 @@ -39280,6 +39573,14 @@ snapshots: tr46: 4.1.1 webidl-conversions: 7.0.0 + whatwg-url@16.0.1(@noble/hashes@2.0.1): + dependencies: + '@exodus/bytes': 1.15.0(@noble/hashes@2.0.1) + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -39413,6 +39714,8 @@ snapshots: xml-name-validator@4.0.0: {} + xml-name-validator@5.0.0: {} + xml2js@0.5.0: dependencies: sax: 1.5.0 From bb7cd46a4f492660d965ef5887cd7fa29f3af76d Mon Sep 17 00:00:00 2001 From: Nevo David Date: Thu, 30 Apr 2026 17:24:01 +0700 Subject: [PATCH 59/80] feat: errors --- apps/backend/src/api/api.module.ts | 2 + .../src/api/routes/admin.controller.ts | 47 ++ .../app/(app)/(site)/admin/errors/page.tsx | 17 + .../admin/admin-errors.component.tsx | 411 ++++++++++++++++++ .../src/components/layout/impersonate.tsx | 16 + .../src/database/prisma/database.module.ts | 4 + .../prisma/errors/errors.repository.ts | 143 ++++++ .../database/prisma/errors/errors.service.ts | 21 + 8 files changed, 661 insertions(+) create mode 100644 apps/backend/src/api/routes/admin.controller.ts create mode 100644 apps/frontend/src/app/(app)/(site)/admin/errors/page.tsx create mode 100644 apps/frontend/src/components/admin/admin-errors.component.tsx create mode 100644 libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts create mode 100644 libraries/nestjs-libraries/src/database/prisma/errors/errors.service.ts diff --git a/apps/backend/src/api/api.module.ts b/apps/backend/src/api/api.module.ts index 0c3b5acc..40bc2a12 100644 --- a/apps/backend/src/api/api.module.ts +++ b/apps/backend/src/api/api.module.ts @@ -37,6 +37,7 @@ import { OAuthAppController } from '@gitroom/backend/api/routes/oauth-app.contro import { ApprovedAppsController } from '@gitroom/backend/api/routes/approved-apps.controller'; import { OAuthController, OAuthAuthorizedController } from '@gitroom/backend/api/routes/oauth.controller'; import { AnnouncementsController } from '@gitroom/backend/api/routes/announcements.controller'; +import { AdminController } from '@gitroom/backend/api/routes/admin.controller'; import { AuthProviderManager } from '@gitroom/backend/services/auth/providers/providers.manager'; import { GithubProvider } from '@gitroom/backend/services/auth/providers/github.provider'; import { GoogleProvider } from '@gitroom/backend/services/auth/providers/google.provider'; @@ -63,6 +64,7 @@ const authenticatedController = [ ApprovedAppsController, OAuthAuthorizedController, AnnouncementsController, + AdminController, ]; @Module({ imports: [UploadModule], diff --git a/apps/backend/src/api/routes/admin.controller.ts b/apps/backend/src/api/routes/admin.controller.ts new file mode 100644 index 00000000..a0673597 --- /dev/null +++ b/apps/backend/src/api/routes/admin.controller.ts @@ -0,0 +1,47 @@ +import { + Controller, + Get, + HttpException, + Query, +} from '@nestjs/common'; +import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request'; +import { User } from '@prisma/client'; +import { ApiTags } from '@nestjs/swagger'; +import { ErrorsService } from '@gitroom/nestjs-libraries/database/prisma/errors/errors.service'; + +@ApiTags('Admin') +@Controller('/admin') +export class AdminController { + constructor(private _errorsService: ErrorsService) {} + + private assertSuperAdmin(user: User) { + if (!user?.isSuperAdmin) { + throw new HttpException('Unauthorized', 400); + } + } + + @Get('/errors') + async listErrors( + @GetUserFromRequest() user: User, + @Query('page') page?: string, + @Query('limit') limit?: string, + @Query('platform') platform?: string, + @Query('email') email?: string, + @Query('unknownFirst') unknownFirst?: string + ) { + this.assertSuperAdmin(user); + return this._errorsService.listErrors({ + page: page ? parseInt(page, 10) : 0, + limit: limit ? parseInt(limit, 10) : 20, + platform: platform || undefined, + email: email || undefined, + unknownFirst: unknownFirst === 'true' || unknownFirst === '1', + }); + } + + @Get('/errors/platforms') + async listPlatforms(@GetUserFromRequest() user: User) { + this.assertSuperAdmin(user); + return this._errorsService.listPlatforms(); + } +} diff --git a/apps/frontend/src/app/(app)/(site)/admin/errors/page.tsx b/apps/frontend/src/app/(app)/(site)/admin/errors/page.tsx new file mode 100644 index 00000000..c915101a --- /dev/null +++ b/apps/frontend/src/app/(app)/(site)/admin/errors/page.tsx @@ -0,0 +1,17 @@ +export const dynamic = 'force-dynamic'; +import { AdminErrorsComponent } from '@gitroom/frontend/components/admin/admin-errors.component'; +import { Metadata } from 'next'; +import { isGeneralServerSide } from '@gitroom/helpers/utils/is.general.server.side'; + +export const metadata: Metadata = { + title: `${isGeneralServerSide() ? 'Postiz' : 'Gitroom'} Admin Errors`, + description: '', +}; + +export default async function Page() { + return ( +
+ +
+ ); +} diff --git a/apps/frontend/src/components/admin/admin-errors.component.tsx b/apps/frontend/src/components/admin/admin-errors.component.tsx new file mode 100644 index 00000000..8daf99ef --- /dev/null +++ b/apps/frontend/src/components/admin/admin-errors.component.tsx @@ -0,0 +1,411 @@ +'use client'; + +import React, { FC, useCallback, useMemo, useState } from 'react'; +import useSWR from 'swr'; +import copy from 'copy-to-clipboard'; +import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; +import { useUser } from '@gitroom/frontend/components/layout/user.context'; +import { useToaster } from '@gitroom/react/toaster/toaster'; +import { useModals } from '@gitroom/frontend/components/layout/new-modal'; +import { Button } from '@gitroom/react/form/button'; +import { LoadingComponent } from '@gitroom/frontend/components/layout/loading'; + +interface ErrorRow { + id: string; + message: string; + body: string; + platform: string; + postId: string; + createdAt: string; + organization: { + id: string; + name: string; + users: { user: { id: string; email: string; name: string | null } }[]; + }; + post: { id: string; content: string | null }; +} + +interface ErrorsResponse { + items: ErrorRow[]; + total: number; + page: number; + limit: number; + hasMore: boolean; +} + +const safeParse = (value: string) => { + try { + return JSON.parse(value); + } catch { + return value; + } +}; + +const ErrorDetailsModal: FC<{ row: ErrorRow }> = ({ row }) => { + const modal = useModals(); + const toaster = useToaster(); + const parsedMessage = useMemo(() => safeParse(row.message), [row.message]); + const parsedBody = useMemo(() => safeParse(row.body), [row.body]); + + const copyAll = useCallback(() => { + copy( + JSON.stringify( + { message: parsedMessage, body: parsedBody, meta: row }, + null, + 2 + ) + ); + toaster.show('Debug code copied to clipboard', 'success'); + }, [parsedMessage, parsedBody, row, toaster]); + + return ( +
+
+
Error Details
+
+ + +
+
+ +
+
+
Platform
+
{row.platform}
+
+
+
Created
+
{new Date(row.createdAt).toLocaleString()}
+
+
+
Organization
+
+ {row.organization?.name}{' '} + ({row.organization?.id}) +
+
+
+
Users
+
+ {row.organization?.users + ?.map((u) => u.user?.email) + .filter(Boolean) + .join(', ') || '—'} +
+
+
+
Post ID
+
{row.postId}
+
+
+ +
message
+
+        {typeof parsedMessage === 'string'
+          ? parsedMessage
+          : JSON.stringify(parsedMessage, null, 2)}
+      
+ +
body
+
+        {typeof parsedBody === 'string'
+          ? parsedBody
+          : JSON.stringify(parsedBody, null, 2)}
+      
+
+ ); +}; + +const usePlatformsList = () => { + const fetch = useFetch(); + return useSWR('/admin/errors/platforms', async (url: string) => { + const res = await fetch(url); + if (!res.ok) return []; + return res.json(); + }); +}; + +const useErrorsList = (params: { + page: number; + limit: number; + platform: string; + email: string; + unknownFirst: boolean; +}) => { + const fetch = useFetch(); + const query = new URLSearchParams({ + page: String(params.page), + limit: String(params.limit), + ...(params.platform ? { platform: params.platform } : {}), + ...(params.email ? { email: params.email } : {}), + unknownFirst: params.unknownFirst ? 'true' : 'false', + }); + const key = `/admin/errors?${query.toString()}`; + return useSWR(key, async (url: string) => { + const res = await fetch(url); + if (!res.ok) { + throw new Error('Failed to load errors'); + } + return res.json(); + }); +}; + +export const AdminErrorsComponent: FC = () => { + const user = useUser(); + const modal = useModals(); + const toaster = useToaster(); + + const [page, setPage] = useState(0); + const [limit, setLimit] = useState(20); + const [platform, setPlatform] = useState(''); + const [email, setEmail] = useState(''); + const [emailInput, setEmailInput] = useState(''); + const [unknownFirst, setUnknownFirst] = useState(true); + + const { data: platforms } = usePlatformsList(); + const { data, isLoading, error } = useErrorsList({ + page, + limit, + platform, + email, + unknownFirst, + }); + + const onApplyEmail = useCallback(() => { + setPage(0); + setEmail(emailInput.trim()); + }, [emailInput]); + + const onClear = useCallback(() => { + setPage(0); + setEmail(''); + setEmailInput(''); + setPlatform(''); + }, []); + + const openDetails = useCallback( + (row: ErrorRow) => { + modal.openModal({ + closeOnClickOutside: true, + withCloseButton: false, + classNames: { + modal: 'w-[100%] max-w-[1100px] text-textColor', + }, + children: , + }); + }, + [modal] + ); + + const copyRow = useCallback( + (row: ErrorRow) => { + copy( + JSON.stringify( + { message: safeParse(row.message), body: safeParse(row.body), meta: row }, + null, + 2 + ) + ); + toaster.show('Debug code copied to clipboard', 'success'); + }, + [toaster] + ); + + if (!user?.isSuperAdmin) { + return ( +
+ You do not have access to this page. +
+ ); + } + + const totalPages = data ? Math.max(1, Math.ceil(data.total / limit)) : 1; + + return ( +
+
+
Errors
+
+ {data ? `${data.total} total` : ''} +
+
+ +
+
+
Platform
+ +
+ +
+
Email contains
+
+ setEmailInput(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') onApplyEmail(); + }} + placeholder="user@example.com" + className="bg-newBgColorInner h-[38px] border border-newTableBorder rounded-[8px] px-[10px] text-[14px] text-textColor min-w-[240px]" + /> + +
+
+ + + +
+
Per page
+ +
+ + +
+ + {isLoading ? ( + + ) : error ? ( +
Failed to load errors.
+ ) : !data || data.items.length === 0 ? ( +
No errors found.
+ ) : ( +
+
+
Created
+
Platform
+
User / Org
+
Message
+
Actions
+
+ {data.items.map((row) => { + const isUnknown = (row.message || '').includes('Unknown Error'); + const emails = + row.organization?.users + ?.map((u) => u.user?.email) + .filter(Boolean) + .join(', ') || '—'; + const preview = + (row.message || '').length > 280 + ? row.message.slice(0, 280) + '…' + : row.message; + return ( +
+
+ {new Date(row.createdAt).toLocaleString()} +
+
+ + {row.platform} + +
+
+
{emails}
+
+ {row.organization?.name} +
+
+
+ {preview} +
+
+ + +
+
+ ); + })} +
+ )} + +
+
+ Page {page + 1} of {totalPages} +
+
+ + +
+
+
+ ); +}; diff --git a/apps/frontend/src/components/layout/impersonate.tsx b/apps/frontend/src/components/layout/impersonate.tsx index 7f9bf46d..4cc6bdad 100644 --- a/apps/frontend/src/components/layout/impersonate.tsx +++ b/apps/frontend/src/components/layout/impersonate.tsx @@ -411,6 +411,21 @@ const AddAnnouncement = () => { ); }; +const ViewErrors = () => { + const t = useT(); + const handleClick = useCallback(() => { + window.location.href = '/admin/errors'; + }, []); + return ( +
+ {t('view_errors', 'View Errors')} +
+ ); +}; + const ImportDebugPost = () => { const { openModal } = useModals(); const t = useT(); @@ -527,6 +542,7 @@ export const Impersonate = () => {
+
)}
diff --git a/libraries/nestjs-libraries/src/database/prisma/database.module.ts b/libraries/nestjs-libraries/src/database/prisma/database.module.ts index 3a2f2a84..fbd79189 100644 --- a/libraries/nestjs-libraries/src/database/prisma/database.module.ts +++ b/libraries/nestjs-libraries/src/database/prisma/database.module.ts @@ -40,6 +40,8 @@ import { OAuthRepository } from '@gitroom/nestjs-libraries/database/prisma/oauth import { OAuthService } from '@gitroom/nestjs-libraries/database/prisma/oauth/oauth.service'; import { AnnouncementsRepository } from '@gitroom/nestjs-libraries/database/prisma/announcements/announcements.repository'; import { AnnouncementsService } from '@gitroom/nestjs-libraries/database/prisma/announcements/announcements.service'; +import { ErrorsRepository } from '@gitroom/nestjs-libraries/database/prisma/errors/errors.repository'; +import { ErrorsService } from '@gitroom/nestjs-libraries/database/prisma/errors/errors.service'; @Global() @Module({ @@ -89,6 +91,8 @@ import { AnnouncementsService } from '@gitroom/nestjs-libraries/database/prisma/ VideoManager, AnnouncementsRepository, AnnouncementsService, + ErrorsRepository, + ErrorsService, ], get exports() { return this.providers; diff --git a/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts b/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts new file mode 100644 index 00000000..0cb1f903 --- /dev/null +++ b/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts @@ -0,0 +1,143 @@ +import { PrismaRepository } from '@gitroom/nestjs-libraries/database/prisma/prisma.service'; +import { Injectable } from '@nestjs/common'; + +const UNKNOWN_TOKEN = 'Unknown Error'; + +interface ListErrorsParams { + page?: number; + limit?: number; + platform?: string; + email?: string; + unknownFirst?: boolean; +} + +@Injectable() +export class ErrorsRepository { + constructor(private _errors: PrismaRepository<'errors'>) {} + + private buildWhere(params: ListErrorsParams) { + const where: any = {}; + if (params.platform) { + where.platform = params.platform; + } + if (params.email) { + where.organization = { + users: { + some: { + user: { + email: { contains: params.email, mode: 'insensitive' }, + }, + }, + }, + }; + } + return where; + } + + private get include() { + return { + organization: { + select: { + id: true, + name: true, + users: { + select: { + user: { select: { id: true, email: true, name: true } }, + }, + }, + }, + }, + post: { select: { id: true, content: true } }, + } as const; + } + + async listPlatforms() { + const rows = await this._errors.model.errors.findMany({ + distinct: ['platform'], + select: { platform: true }, + orderBy: { platform: 'asc' }, + }); + return rows.map((r) => r.platform); + } + + async listErrors(params: ListErrorsParams) { + const page = Math.max(0, params.page || 0); + const limit = Math.min(Math.max(1, params.limit || 20), 100); + const skip = page * limit; + const where = this.buildWhere(params); + const include = this.include; + + if (!params.unknownFirst) { + const [items, total] = await Promise.all([ + this._errors.model.errors.findMany({ + where, + orderBy: { createdAt: 'desc' }, + skip, + take: limit, + include, + }), + this._errors.model.errors.count({ where }), + ]); + return { + items, + total, + page, + limit, + hasMore: skip + items.length < total, + }; + } + + const unknownWhere = { ...where, message: { contains: UNKNOWN_TOKEN } }; + const knownWhere = { + ...where, + NOT: { message: { contains: UNKNOWN_TOKEN } }, + }; + + const [unknownTotal, knownTotal] = await Promise.all([ + this._errors.model.errors.count({ where: unknownWhere }), + this._errors.model.errors.count({ where: knownWhere }), + ]); + + let unknownItems: any[] = []; + let knownItems: any[] = []; + + if (skip < unknownTotal) { + const takeUnknown = Math.min(unknownTotal - skip, limit); + unknownItems = await this._errors.model.errors.findMany({ + where: unknownWhere, + orderBy: { createdAt: 'desc' }, + skip, + take: takeUnknown, + include, + }); + const remaining = limit - unknownItems.length; + if (remaining > 0) { + knownItems = await this._errors.model.errors.findMany({ + where: knownWhere, + orderBy: { createdAt: 'desc' }, + skip: 0, + take: remaining, + include, + }); + } + } else { + knownItems = await this._errors.model.errors.findMany({ + where: knownWhere, + orderBy: { createdAt: 'desc' }, + skip: skip - unknownTotal, + take: limit, + include, + }); + } + + const items = [...unknownItems, ...knownItems]; + const total = unknownTotal + knownTotal; + return { + items, + total, + page, + limit, + hasMore: skip + items.length < total, + }; + } +} diff --git a/libraries/nestjs-libraries/src/database/prisma/errors/errors.service.ts b/libraries/nestjs-libraries/src/database/prisma/errors/errors.service.ts new file mode 100644 index 00000000..63d3c3ea --- /dev/null +++ b/libraries/nestjs-libraries/src/database/prisma/errors/errors.service.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@nestjs/common'; +import { ErrorsRepository } from '@gitroom/nestjs-libraries/database/prisma/errors/errors.repository'; + +@Injectable() +export class ErrorsService { + constructor(private _errorsRepository: ErrorsRepository) {} + + listErrors(params: { + page?: number; + limit?: number; + platform?: string; + email?: string; + unknownFirst?: boolean; + }) { + return this._errorsRepository.listErrors(params); + } + + listPlatforms() { + return this._errorsRepository.listPlatforms(); + } +} From 7264c002988f5d98970483359b111bc99d13a2fc Mon Sep 17 00:00:00 2001 From: Nevo David Date: Thu, 30 Apr 2026 17:44:06 +0700 Subject: [PATCH 60/80] feat: err --- .../src/database/prisma/errors/errors.repository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts b/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts index 0cb1f903..6f3bb51e 100644 --- a/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/errors/errors.repository.ts @@ -1,7 +1,7 @@ import { PrismaRepository } from '@gitroom/nestjs-libraries/database/prisma/prisma.service'; import { Injectable } from '@nestjs/common'; -const UNKNOWN_TOKEN = 'Unknown Error'; +const UNKNOWN_TOKEN = 'An unknown error occurred'; interface ListErrorsParams { page?: number; From 0d98fc02fb6edccb696c3bc933d4612451fae838 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Thu, 30 Apr 2026 18:34:18 +0700 Subject: [PATCH 61/80] feat: X errors and force upload --- .../v1/public.integrations.controller.ts | 27 ++- .../new-launch/providers/x/x.provider.tsx | 13 +- .../src/integrations/social/x.provider.ts | 167 ++++++++++++++---- 3 files changed, 159 insertions(+), 48 deletions(-) diff --git a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts index d2a74efe..38ce060b 100644 --- a/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts +++ b/apps/backend/src/public-api/routes/v1/public.integrations.controller.ts @@ -49,7 +49,10 @@ const PUBLIC_API_ALLOWED_MIME = new Set([ 'video/mp4', ]); import * as Sentry from '@sentry/nestjs'; -import { socialIntegrationList, IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager'; +import { + socialIntegrationList, + IntegrationManager, +} from '@gitroom/nestjs-libraries/integrations/integration.manager'; import { getValidationSchemas } from '@gitroom/nestjs-libraries/chat/validation.schemas.helper'; import { RefreshIntegrationService } from '@gitroom/nestjs-libraries/integrations/refresh.integration.service'; import { RefreshToken } from '@gitroom/nestjs-libraries/integrations/social.abstract'; @@ -167,6 +170,24 @@ export class PublicIntegrationsController { ); body.type = rawBody.type; + if ( + process.env.RESTRICT_UPLOAD_DOMAINS && + body.posts.some((p) => + p.value.some((a) => + a.image.some( + (i) => i.path.indexOf(process.env.RESTRICT_UPLOAD_DOMAINS) === -1 + ) + ) + ) + ) { + throw new HttpException( + { + msg: `All media must be uploaded through our upload API route and contain the domain: ${process.env.RESTRICT_UPLOAD_DOMAINS}`, + }, + 400 + ); + } + console.log(JSON.stringify(body, null, 2)); return this._postsService.createPost(org.id, body); } @@ -238,7 +259,9 @@ export class PublicIntegrationsController { if (integrationProvider.externalUrl) { throw new HttpException( - { msg: 'This integration requires an external URL and is not supported via the public API' }, + { + msg: 'This integration requires an external URL and is not supported via the public API', + }, 400 ); } diff --git a/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx b/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx index cf4fcd20..7b5efca0 100644 --- a/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx +++ b/apps/frontend/src/components/new-launch/providers/x/x.provider.tsx @@ -92,16 +92,9 @@ export default withProvider({ const premium = additionalSettings?.find((p: any) => p?.title === 'Verified')?.value || false; - if (posts?.some((p) => (p?.length ?? 0) > 4)) { - return 'There can be maximum 4 pictures in a post.'; - } - if ( - posts?.some( - (p) => p?.some((m) => (m?.path?.indexOf?.('mp4') ?? -1) > -1) && (p?.length ?? 0) > 1 - ) - ) { - return 'There can be maximum 1 video in a post.'; - } + // if (posts?.some((p) => (p?.length ?? 0) > 4)) { + // return 'There can be maximum 4 pictures in a post.'; + // } for (const load of posts?.flatMap((p) => p?.flatMap((a) => a?.path)) ?? []) { if ((load?.indexOf?.('mp4') ?? -1) > -1) { const isValid = await checkVideoDuration(load, premium); diff --git a/libraries/nestjs-libraries/src/integrations/social/x.provider.ts b/libraries/nestjs-libraries/src/integrations/social/x.provider.ts index 2cf7f282..68284508 100644 --- a/libraries/nestjs-libraries/src/integrations/social/x.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/x.provider.ts @@ -1,4 +1,5 @@ import { TweetV2, TwitterApi } from 'twitter-api-v2'; +import { createHmac, randomBytes } from 'crypto'; import { AnalyticsData, AuthTokenDetails, @@ -45,6 +46,24 @@ export class XProvider extends SocialAbstract implements SocialProvider { value: string; } | undefined { + if (body.includes('You are not permitted to perform this action')) { + return { + type: 'bad-body', + value: 'There is a problem posting, please edit your post and check character count and media attachments', + } + } + if (body.includes('maximum of one cashtag')) { + return { + type: 'bad-body', + value: 'There can be maximum of one cashtag ($SYMBOL) per post', + }; + } + if (body.includes('maximum of 4 items')) { + return { + type: 'bad-body', + value: 'There must be a maximum of 4 items per post', + }; + } if (body.includes('Unsupported Authentication')) { return { type: 'refresh-token', @@ -308,6 +327,54 @@ export class XProvider extends SocialAbstract implements SocialProvider { }); } + private signOAuth1( + method: string, + url: string, + accessToken: string, + accessSecret: string + ): string { + const pct = (s: string) => + encodeURIComponent(s) + .replace(/!/g, '%21') + .replace(/\*/g, '%2A') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29'); + + const params: Record = { + oauth_consumer_key: process.env.X_API_KEY!, + oauth_nonce: randomBytes(16).toString('hex'), + oauth_signature_method: 'HMAC-SHA1', + oauth_timestamp: String(Math.floor(Date.now() / 1000)), + oauth_token: accessToken, + oauth_version: '1.0', + }; + + const paramString = Object.keys(params) + .sort() + .map((k) => `${pct(k)}=${pct(params[k])}`) + .join('&'); + + const baseString = [ + method.toUpperCase(), + pct(url.split('?')[0]), + pct(paramString), + ].join('&'); + + const signingKey = `${pct(process.env.X_API_SECRET!)}&${pct(accessSecret)}`; + params.oauth_signature = createHmac('sha1', signingKey) + .update(baseString) + .digest('base64'); + + return ( + 'OAuth ' + + Object.keys(params) + .sort() + .map((k) => `${pct(k)}="${pct(params[k])}"`) + .join(', ') + ); + } + private async uploadMedia( client: TwitterApi, postDetails: PostDetails[] @@ -370,6 +437,7 @@ export class XProvider extends SocialAbstract implements SocialProvider { paid_partnership?: boolean; }>[] ): Promise { + const [accessTokenSplit, accessSecretSplit] = accessToken.split(':'); const client = await this.getClient(accessToken); const { data: { username }, @@ -386,30 +454,43 @@ export class XProvider extends SocialAbstract implements SocialProvider { const media_ids = (uploadAll[firstPost.id] || []).filter((f) => f); - // @ts-ignore - const { data }: { data: { id: string } } = await this.runInConcurrent( - async () => - // @ts-ignore - client.v2.tweet({ - ...(!firstPost?.settings?.who_can_reply_post || - firstPost?.settings?.who_can_reply_post === 'everyone' - ? {} - : { - reply_settings: firstPost?.settings?.who_can_reply_post, - }), - ...(firstPost?.settings?.community - ? { - share_with_followers: true, - community_id: - firstPost?.settings?.community?.split('/').pop() || '', - } - : {}), - text: firstPost.message, - ...(media_ids.length ? { media: { media_ids } } : {}), - made_with_ai: !!firstPost?.settings?.made_with_ai, - paid_partnership: !!firstPost?.settings?.paid_partnership, - }) - ); + const tweetUrl = 'https://api.x.com/2/tweets'; + const tweetBody = { + ...(!firstPost?.settings?.who_can_reply_post || + firstPost?.settings?.who_can_reply_post === 'everyone' + ? {} + : { + reply_settings: firstPost?.settings?.who_can_reply_post, + }), + ...(firstPost?.settings?.community + ? { + share_with_followers: true, + community_id: + firstPost?.settings?.community?.split('/').pop() || '', + } + : {}), + text: firstPost.message, + ...(media_ids.length ? { media: { media_ids } } : {}), + made_with_ai: !!firstPost?.settings?.made_with_ai, + paid_partnership: !!firstPost?.settings?.paid_partnership, + }; + + const tweetResponse = await this.fetch(tweetUrl, { + method: 'POST', + headers: { + Authorization: this.signOAuth1( + 'POST', + tweetUrl, + accessTokenSplit, + accessSecretSplit + ), + 'Content-Type': 'application/json', + }, + body: JSON.stringify(tweetBody), + }); + const { data } = (await tweetResponse.json()) as { + data: { id: string }; + }; return [ { @@ -434,6 +515,7 @@ export class XProvider extends SocialAbstract implements SocialProvider { }>[], integration: Integration ): Promise { + const [accessTokenSplit, accessSecretSplit] = accessToken.split(':'); const client = await this.getClient(accessToken); const { data: { username }, @@ -452,18 +534,31 @@ export class XProvider extends SocialAbstract implements SocialProvider { const replyToId = lastCommentId || postId; - // @ts-ignore - const { data }: { data: { id: string } } = await this.runInConcurrent( - async () => - // @ts-ignore - client.v2.tweet({ - text: commentPost.message, - ...(media_ids.length ? { media: { media_ids } } : {}), - reply: { in_reply_to_tweet_id: replyToId }, - made_with_ai: !!commentPost?.settings?.made_with_ai, - paid_partnership: !!commentPost?.settings?.paid_partnership, - }) - ); + const tweetUrl = 'https://api.x.com/2/tweets'; + const tweetBody = { + text: commentPost.message, + ...(media_ids.length ? { media: { media_ids } } : {}), + reply: { in_reply_to_tweet_id: replyToId }, + made_with_ai: !!commentPost?.settings?.made_with_ai, + paid_partnership: !!commentPost?.settings?.paid_partnership, + }; + + const tweetResponse = await this.fetch(tweetUrl, { + method: 'POST', + headers: { + Authorization: this.signOAuth1( + 'POST', + tweetUrl, + accessTokenSplit, + accessSecretSplit + ), + 'Content-Type': 'application/json', + }, + body: JSON.stringify(tweetBody), + }); + const { data } = (await tweetResponse.json()) as { + data: { id: string }; + }; return [ { From d6bc6eb0ffe2d7de562971f9ee4c6ee365cd40d1 Mon Sep 17 00:00:00 2001 From: Santosh Bhandari Date: Thu, 30 Apr 2026 21:28:11 +0545 Subject: [PATCH 62/80] fix: properly handle error in discord provider --- .../integrations/social/discord.provider.ts | 66 +++++++++++++++---- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts b/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts index 6402920a..9a68dad3 100644 --- a/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts @@ -42,7 +42,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { ).json(); const { application } = await ( - await fetch('https://discord.com/api/oauth2/@me', { + await this.fetch('https://discord.com/api/oauth2/@me', { headers: { Authorization: `Bearer ${access_token}`, }, @@ -99,7 +99,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { this.checkScopes(this.scopes, scope.split(' ')); const { application } = await ( - await fetch('https://discord.com/api/oauth2/@me', { + await this.fetch('https://discord.com/api/oauth2/@me', { headers: { Authorization: `Bearer ${access_token}`, }, @@ -120,7 +120,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { @Tool({ description: 'Channels', dataSchema: [] }) async channels(accessToken: string, params: any, id: string) { const list = await ( - await fetch(`https://discord.com/api/guilds/${id}/channels`, { + await this.fetch(`https://discord.com/api/guilds/${id}/channels`, { headers: { Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`, }, @@ -171,7 +171,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { } const data = await ( - await fetch(`https://discord.com/api/channels/${channel}/messages`, { + await this.fetch(`https://discord.com/api/channels/${channel}/messages`, { method: 'POST', headers: { Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`, @@ -208,7 +208,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { // Create thread if this is the first comment if (!lastCommentId) { const { id: threadId } = await ( - await fetch( + await this.fetch( `https://discord.com/api/channels/${channel}/messages/${postId}/threads`, { method: 'POST', @@ -224,9 +224,6 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { ) ).json(); threadChannel = threadId; - } else { - // Extract thread channel from the last comment's URL or use channel directly - threadChannel = channel; } const form = new FormData(); @@ -234,7 +231,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { 'payload_json', JSON.stringify({ content: commentPost.message.replace(/\[\[\[(@.*?)]]]/g, (match, p1) => { - return `<${p1}>`; + return `<${p1}>`; }), attachments: commentPost.media?.map((p, index) => ({ id: index, @@ -257,7 +254,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { } const data = await ( - await fetch( + await this.fetch( `https://discord.com/api/channels/${threadChannel}/messages`, { method: 'POST', @@ -281,7 +278,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { async changeNickname(id: string, accessToken: string, name: string) { await ( - await fetch(`https://discord.com/api/guilds/${id}/members/@me`, { + await this.fetch(`https://discord.com/api/guilds/${id}/members/@me`, { method: 'PATCH', headers: { Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`, @@ -305,7 +302,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { integration: Integration ) { const allRoles = await ( - await fetch(`https://discord.com/api/guilds/${id}/roles`, { + await this.fetch(`https://discord.com/api/guilds/${id}/roles`, { headers: { Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN_ID}`, 'Content-Type': 'application/json', @@ -320,7 +317,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { .filter((f: any) => f.name !== '@everyone' && f.name !== '@here'); const list = await ( - await fetch( + await this.fetch( `https://discord.com/api/guilds/${id}/members/search?query=${data.query}`, { headers: { @@ -368,4 +365,47 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { } return `[[[@${idOrHandle.replace('@', '')}]]]`; } + + override handleErrors( + body: string + ): + | { type: 'refresh-token' | 'bad-body' | 'retry'; value: string } + | undefined { + if (body.includes('50001')) { + return { + type: 'bad-body', + value: "Bot doesn't have access to this channel", + }; + } + + if (body.includes('50013')) { + return { + type: 'bad-body', + value: 'Bot lacks permission in this channel', + }; + } + + if (body.includes('10003')) { + return { + type: 'bad-body', + value: 'Channel no longer exists', + }; + } + + if (body.includes('40005')) { + return { + type: 'bad-body', + value: "Attachment exceeds Discord's size limit", + }; + } + + if (body.includes('20028')) { + return { + type: 'retry', + value: 'Rate limited by Discord', + }; + } + + return undefined; + } } From 3ee35a7348aae2d3bd8dc6e0de66403d440d536b Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Thu, 30 Apr 2026 17:52:36 +0200 Subject: [PATCH 63/80] feat: temporarily disable cache to fix build --- .github/workflows/build.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e985a34..ee5c0f84 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,15 +35,15 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - name: Setup pnpm cache - uses: actions/cache@v4 - with: - path: | - ${{ env.STORE_PATH }} - ${{ github.workspace }}/.next/cache - key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} - restore-keys: | - ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}- +# - name: Setup pnpm cache +# uses: actions/cache@v4 +# with: +# path: | +# ${{ env.STORE_PATH }} +# ${{ github.workspace }}/.next/cache +# key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} +# restore-keys: | +# ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}- - name: Install dependencies run: pnpm install From ef111eb1c44affa5a15ee08ddc3db682b736bdd5 Mon Sep 17 00:00:00 2001 From: Santosh Bhandari Date: Thu, 30 Apr 2026 21:45:25 +0545 Subject: [PATCH 64/80] fix: update error message --- .../src/integrations/social/discord.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts b/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts index 9a68dad3..a70f36ce 100644 --- a/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/discord.provider.ts @@ -381,7 +381,7 @@ export class DiscordProvider extends SocialAbstract implements SocialProvider { if (body.includes('50013')) { return { type: 'bad-body', - value: 'Bot lacks permission in this channel', + value: 'Bot lacks permission to send messages in this channel', }; } From 971042a074f69f318d13af677edbb63ebdb8a2b0 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Sat, 2 May 2026 14:00:09 +0700 Subject: [PATCH 65/80] feat: shrink workflow payload --- .../src/activities/post.activity.ts | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/apps/orchestrator/src/activities/post.activity.ts b/apps/orchestrator/src/activities/post.activity.ts index 87d5a899..d5c3bcff 100644 --- a/apps/orchestrator/src/activities/post.activity.ts +++ b/apps/orchestrator/src/activities/post.activity.ts @@ -24,6 +24,33 @@ import { } from '@gitroom/nestjs-libraries/temporal/temporal.search.attribute'; import { SubscriptionService } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/subscription.service'; +// Drops fields the workflow and downstream activities never read — biggest wins are `error` (grows per retry) and `childrenPost` (Prisma side-loads it on every recursive row). +function slimPost(post: any) { + if (!post) return post; + const { + error, + childrenPost, + tags, + description, + title, + submittedForOrderId, + submittedForOrganizationId, + submittedForOrder, + submittedForOrganization, + lastMessageId, + parentPostId, + approvedSubmitForOrder, + deletedAt, + createdAt, + updatedAt, + payoutProblems, + comments, + errors, + ...rest + } = post; + return rest; +} + @Injectable() @Activity() export class PostActivity { @@ -80,7 +107,7 @@ export class PostActivity { @ActivityMethod() async updatePost(id: string, postId: string, releaseURL: string) { - return this._postService.updatePost(id, postId, releaseURL); + await this._postService.updatePost(id, postId, releaseURL); } @ActivityMethod() @@ -101,7 +128,7 @@ export class PostActivity { return []; } - return getPosts; + return getPosts.map(slimPost); } @ActivityMethod() @@ -220,7 +247,7 @@ export class PostActivity { digest = false, type: NotificationType = 'success' ) { - return this._notificationService.inAppNotification( + await this._notificationService.inAppNotification( orgId, subject, message, @@ -241,7 +268,7 @@ export class PostActivity { @ActivityMethod() async changeState(id: string, state: State, err?: any, body?: any) { - return this._postService.changeState(id, state, err, body); + await this._postService.changeState(id, state, err, body); } @ActivityMethod() @@ -266,7 +293,7 @@ export class PostActivity { ); const post = await this._postService.getPostByForWebhookId(postId); - return Promise.all( + await Promise.all( webhooks.map(async (webhook) => { try { await fetch(webhook.url, { @@ -303,7 +330,7 @@ export class PostActivity { delay: number; information: any; }) { - return this._integrationService.processInternalPlug(data); + await this._integrationService.processInternalPlug(data); } @ActivityMethod() From 47ce014204eeb8cb8e64edf123e2ee30773d34fb Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sun, 3 May 2026 14:17:54 +0200 Subject: [PATCH 66/80] feat: contributor form --- .github/PULL_REQUEST_TEMPLATE.md | 2 ++ .github/workflows/pr-quality.yml | 52 -------------------------------- CONTRIBUTING.md | 4 +++ 3 files changed, 6 insertions(+), 52 deletions(-) delete mode 100644 .github/workflows/pr-quality.yml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 61a483bd..f47ea4f9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,5 @@ + + # What kind of change does this PR introduce? eg: Bug fix, feature, docs update, ... diff --git a/.github/workflows/pr-quality.yml b/.github/workflows/pr-quality.yml deleted file mode 100644 index 3fdc958b..00000000 --- a/.github/workflows/pr-quality.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: PR Quality - -permissions: - contents: read - issues: read - pull-requests: write - -on: - pull_request_target: - types: [opened, reopened] - -jobs: - anti-slop: - runs-on: ubuntu-latest - steps: - - uses: peakoss/anti-slop@v0 - with: - # Overall - max-failures: 3 - - # Other - require-maintainer-can-modify: true - max-negative-reactions: 3 - require-conventional-title: true - - # Description - max-emoji-count: 2 - max-code-references: 3 - blocked-terms: "Generated with Claude Code,Generated with Codex" - - # PR Template - require-pr-template: true - strict-pr-template-sections: "What kind of change does this PR introduce?,Why was this change needed?,Checklist:" - optional-pr-template-sections: "Other information:" - max-additional-pr-template-sections: 2 - - # User - detect-spam-usernames: true - min-account-age: 30 - max-daily-forks: 5 - min-profile-completeness: 4 - - # Exemptions - exempt-author-association: "OWNER,MEMBER,COLLABORATOR" - exempt-users: "nevo-david,egelhaus" - exempt-bots: "postiz-agent[bot]" - - # Actions - exempt-label: "exempt" - close-pr: true - failure-add-pr-labels: "spam" - failure-pr-message: "This PR has been marked as Spam, please re-open if this is a mistake." diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 960e6f34..344daa29 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,10 @@ Contributions are welcome - code, docs, whatever it might be! If this is your fi The main documentation site has a [developer guide](https://docs.postiz.com/developer-guide) . That guide provides you a good understanding of the project structure, and how to setup your development environment. Read this document after you have read that guide. This document is intended to provide you a good understanding of how to submit your first contribution. +## Apply in the contribution form + +To submit your contribution, please fill out the [contribution form](https://contribute.egelhaus.de/p/postiz). This helps us evaluate whether your contribution is a good fit for the project. We will review your submission and get back to you as soon as possible. + ## Write code with others This is an open source project, with an open and welcoming community that is always keen to welcome new contributors. We recommend the two best ways to interact with the community are: From e419e05f09feb596b56f0907ba977c22baab97c6 Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Sun, 3 May 2026 16:27:56 +0200 Subject: [PATCH 67/80] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CONTRIBUTING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f47ea4f9..a0d2be05 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,4 @@ - + # What kind of change does this PR introduce? diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 344daa29..bb703436 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Contributions are welcome - code, docs, whatever it might be! If this is your fi The main documentation site has a [developer guide](https://docs.postiz.com/developer-guide) . That guide provides you a good understanding of the project structure, and how to setup your development environment. Read this document after you have read that guide. This document is intended to provide you a good understanding of how to submit your first contribution. -## Apply in the contribution form +## Apply via the contribution form To submit your contribution, please fill out the [contribution form](https://contribute.egelhaus.de/p/postiz). This helps us evaluate whether your contribution is a good fit for the project. We will review your submission and get back to you as soon as possible. From d056225053c36cbf05932fa00e5e5bf23e2d398d Mon Sep 17 00:00:00 2001 From: Santosh Bhandari Date: Mon, 4 May 2026 08:08:34 +0545 Subject: [PATCH 68/80] fix: remove processing GIF via sharp in linkedin --- .../src/integrations/social/linkedin.provider.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts b/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts index 81b2fded..978b237b 100644 --- a/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/linkedin.provider.ts @@ -478,14 +478,13 @@ export class LinkedinProvider extends SocialAbstract implements SocialProvider { private async prepareMediaBuffer(mediaUrl: string): Promise { const isVideo = mediaUrl.indexOf('mp4') > -1; + const isGif = lookup(mediaUrl) === 'image/gif'; - if (isVideo) { + if (isVideo || isGif) { return Buffer.from(await readOrFetch(mediaUrl)); } - return await sharp(await readOrFetch(mediaUrl), { - animated: lookup(mediaUrl) === 'image/gif', - }) + return await sharp(await readOrFetch(mediaUrl), { animated: false }) .toFormat('jpeg') .resize({ width: 1000 }) .toBuffer(); From 779764aa5d033bdf400e526ee7724dbe8b9e1caa Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Mon, 4 May 2026 10:28:48 +0200 Subject: [PATCH 69/80] Fix contribution form link in PR template Updated contribution form link in PR template. --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a0d2be05..25427966 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,4 @@ - + # What kind of change does this PR introduce? From 1bf32426c72851c35aa61c02da8ef304358aaeb1 Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Mon, 4 May 2026 10:29:09 +0200 Subject: [PATCH 70/80] Update contribution form link in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bb703436..071994c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ The main documentation site has a [developer guide](https://docs.postiz.com/deve ## Apply via the contribution form -To submit your contribution, please fill out the [contribution form](https://contribute.egelhaus.de/p/postiz). This helps us evaluate whether your contribution is a good fit for the project. We will review your submission and get back to you as soon as possible. +To submit your contribution, please fill out the [contribution form](https://contribute.postiz.com/p/postiz). This helps us evaluate whether your contribution is a good fit for the project. We will review your submission and get back to you as soon as possible. ## Write code with others From a6967c85190a3affb557a4ccce56b8b767b05309 Mon Sep 17 00:00:00 2001 From: Santosh Bhandari Date: Mon, 4 May 2026 18:41:34 +0545 Subject: [PATCH 71/80] ui: update the modal such that for long text won't cause overflow --- .../src/components/launches/import-debug-post.modal.tsx | 4 ++-- apps/frontend/src/components/layout/impersonate.tsx | 1 + apps/frontend/src/components/layout/new-modal.tsx | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/components/launches/import-debug-post.modal.tsx b/apps/frontend/src/components/launches/import-debug-post.modal.tsx index 65c28593..14fed8dd 100644 --- a/apps/frontend/src/components/launches/import-debug-post.modal.tsx +++ b/apps/frontend/src/components/launches/import-debug-post.modal.tsx @@ -147,7 +147,7 @@ export const ImportDebugPostModal: FC<{ close: () => void }> = ({ close }) => {
{t('debug_info', 'Debug Info')}
-
+
{t('provider', 'Provider')}: @@ -175,7 +175,7 @@ export const ImportDebugPostModal: FC<{ close: () => void }> = ({ close }) => { {t('error_details', 'Error Details')}: -
+
{parsed._debug.errors.map((err, i) => (
[{err.platform}] {err.message} diff --git a/apps/frontend/src/components/layout/impersonate.tsx b/apps/frontend/src/components/layout/impersonate.tsx index 4cc6bdad..e81d0429 100644 --- a/apps/frontend/src/components/layout/impersonate.tsx +++ b/apps/frontend/src/components/layout/impersonate.tsx @@ -433,6 +433,7 @@ const ImportDebugPost = () => { const handleClick = useCallback(() => { openModal({ title: t('import_debug_post', 'Import Debug Post'), + maxSize: 800, children: (close) => , }); }, []); diff --git a/apps/frontend/src/components/layout/new-modal.tsx b/apps/frontend/src/components/layout/new-modal.tsx index fdc3704a..090f4366 100644 --- a/apps/frontend/src/components/layout/new-modal.tsx +++ b/apps/frontend/src/components/layout/new-modal.tsx @@ -31,6 +31,7 @@ interface OpenModalInterface { modal?: string; }; size?: string | number; + maxSize?: string | number; height?: string | number; id?: string; } @@ -200,10 +201,11 @@ export const Component: FC<{ modal.size ? '' : 'min-w-[600px]', modal.fullScreen && 'h-full' )} - {...((!!modal.size || !!modal.height) && { + {...((!!modal.size || !!modal.height || !!modal.maxSize) && { style: { ...(modal.size ? { width: modal.size } : {}), ...(modal.height ? { height: modal.height } : {}), + ...(modal.maxSize ? { maxWidth: modal.maxSize } : {}), }, })} onClick={(e) => e.stopPropagation()} From 18a1a808710963986fafd07090aa9dc03e529ef0 Mon Sep 17 00:00:00 2001 From: Santosh Bhandari Date: Mon, 4 May 2026 19:05:21 +0545 Subject: [PATCH 72/80] feat: update notification list to be scrollable and added time --- .../src/components/layout/set.timezone.tsx | 2 ++ .../notifications/notification.component.tsx | 26 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/apps/frontend/src/components/layout/set.timezone.tsx b/apps/frontend/src/components/layout/set.timezone.tsx index f37b4f0f..ac5b74a5 100644 --- a/apps/frontend/src/components/layout/set.timezone.tsx +++ b/apps/frontend/src/components/layout/set.timezone.tsx @@ -3,8 +3,10 @@ import dayjs, { ConfigType } from 'dayjs'; import { FC, useEffect } from 'react'; import timezone from 'dayjs/plugin/timezone'; import utc from 'dayjs/plugin/utc'; +import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(timezone); dayjs.extend(utc); +dayjs.extend(relativeTime); const { utc: originalUtc } = dayjs; diff --git a/apps/frontend/src/components/notifications/notification.component.tsx b/apps/frontend/src/components/notifications/notification.component.tsx index 4b890706..731b80f9 100644 --- a/apps/frontend/src/components/notifications/notification.component.tsx +++ b/apps/frontend/src/components/notifications/notification.component.tsx @@ -4,6 +4,7 @@ import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import useSWR from 'swr'; import { FC, useCallback, useState } from 'react'; import clsx from 'clsx'; +import dayjs from 'dayjs'; import { useClickAway } from '@uidotdev/usehooks'; import ReactLoading from '@gitroom/frontend/components/layout/loading'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; @@ -26,16 +27,29 @@ export const ShowNotification: FC<{ const [newNotification] = useState( new Date(notification.createdAt) > new Date(props.lastReadNotification) ); + const createdAt = dayjs(notification.createdAt); + const isWithin24h = dayjs().diff(createdAt, 'hour') < 24; + const fullDate = createdAt.format('MMM D, YYYY h:mm A'); return (
+ > +
+
+ {isWithin24h ? createdAt.fromNow() : fullDate} +
+
); }; export const NotificationOpenComponent = () => { @@ -57,7 +71,7 @@ export const NotificationOpenComponent = () => { {t('notifications', 'Notifications')}
-
+
{isLoading && (
From 53f0967e67f034981f73ded9ccba2079e476f32b Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Mon, 4 May 2026 15:50:13 +0200 Subject: [PATCH 73/80] feat: merge queue --- .github/workflows/build.yml | 2 ++ .github/workflows/codeql.yml | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee5c0f84..242c7c88 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,8 @@ name: Build on: push: + merge_group: + pull_request: jobs: build: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 79d64857..0974256d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,5 +1,5 @@ --- -name: "Code Quality Analysis" +name: "Code Quality Analysis" on: push: @@ -9,6 +9,8 @@ on: - apps/** - '!apps/docs/**' - libraries/** + merge_group: + jobs: analyze: From 22f436e72ebbfab36fa15a0c6ce66540284c638d Mon Sep 17 00:00:00 2001 From: Enno Gelhaus Date: Mon, 4 May 2026 21:00:24 +0200 Subject: [PATCH 74/80] feat: simplify pr template --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 25427966..d4c6ad9c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,5 +18,5 @@ Put a "X" in the boxes below to indicate you have followed the checklist; - [ ] I have read the [CONTRIBUTING](https://github.com/gitroomhq/postiz-app/blob/main/CONTRIBUTING.md) guide. - [ ] I confirm I have not used AI to submit this PR or generate code for it. -- [ ] I checked that there were not similar issues or PRs already open for this. -- [ ] This PR fixes just ONE issue (do not include multiple issues or types of change in the same PR) For example, don't try and fix a UI issue and include new dependencies in the same PR. +- [ ] I checked that there were no similar issues or PRs already open for this. +- [ ] This PR fixes just ONE issue From dcb1b0188a8ecaa93322c07b2fd381d22fbc4aa0 Mon Sep 17 00:00:00 2001 From: Santosh Bhandari Date: Wed, 6 May 2026 10:46:25 +0545 Subject: [PATCH 75/80] fix: lowercase email on local registration --- apps/backend/src/services/auth/auth.service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/backend/src/services/auth/auth.service.ts b/apps/backend/src/services/auth/auth.service.ts index 32b43f3b..187c08ed 100644 --- a/apps/backend/src/services/auth/auth.service.ts +++ b/apps/backend/src/services/auth/auth.service.ts @@ -43,6 +43,9 @@ export class AuthService { if (process.env.DISALLOW_PLUS && body.email.includes('+')) { throw new Error('Email with plus sign is not allowed'); } + if (body instanceof CreateOrgUserDto) { + body.email = body.email.toLowerCase(); + } const user = await this._userService.getUserByEmail(body.email); if (body instanceof CreateOrgUserDto) { if (user) { From 638b071283434bbca2eed3c0e661bc3d40c84572 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 11 May 2026 11:19:02 +0700 Subject: [PATCH 76/80] feat: corrupted file --- .../integrations/social/pinterest.provider.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts b/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts index 2f216182..56165c8f 100644 --- a/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/pinterest.provider.ts @@ -10,7 +10,10 @@ import { PinterestSettingsDto } from '@gitroom/nestjs-libraries/dtos/posts/provi import axios from 'axios'; import FormData from 'form-data'; import { timer } from '@gitroom/helpers/utils/timer'; -import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract'; +import { + BadBody, + SocialAbstract, +} from '@gitroom/nestjs-libraries/integrations/social.abstract'; import dayjs from 'dayjs'; import { Tool } from '@gitroom/nestjs-libraries/integrations/tool.decorator'; import { Rules } from '@gitroom/nestjs-libraries/chat/rules.description.decorator'; @@ -236,6 +239,15 @@ export class PinterestProvider ) ).json(); + if (mediafile.status === 'failed') { + throw new BadBody( + 'pinterest', + JSON.stringify({}), + {} as any, + 'The file is corrupted and cannot be uploaded' + ); + } + await timer(30000); statusCode = mediafile.status; } @@ -414,7 +426,9 @@ export class PinterestProvider result.push({ label: 'Outbound Clicks', percentageChange: 0, - data: [{ total: String(lifetimeMetrics.OUTBOUND_CLICK), date: today }], + data: [ + { total: String(lifetimeMetrics.OUTBOUND_CLICK), date: today }, + ], }); } From 6e55eb3b92640ede52d4a932085e2ab3b9102fea Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 11 May 2026 13:57:46 +0700 Subject: [PATCH 77/80] feat: more cover for pending queues --- .../src/activities/post.activity.ts | 2 +- apps/orchestrator/src/workflows/index.ts | 1 + .../post-workflows/post.workflow.v1.0.3.ts | 430 ++++++++++++++++++ .../database/prisma/posts/posts.repository.ts | 4 +- .../database/prisma/posts/posts.service.ts | 2 +- 5 files changed, 435 insertions(+), 4 deletions(-) create mode 100644 apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.3.ts diff --git a/apps/orchestrator/src/activities/post.activity.ts b/apps/orchestrator/src/activities/post.activity.ts index d5c3bcff..6ca7a478 100644 --- a/apps/orchestrator/src/activities/post.activity.ts +++ b/apps/orchestrator/src/activities/post.activity.ts @@ -76,7 +76,7 @@ export class PostActivity { for (const post of list) { await this._temporalService.client .getRawClient() - .workflow.signalWithStart('postWorkflowV102', { + .workflow.signalWithStart('postWorkflowV103', { workflowId: `post_${post.id}`, taskQueue: 'main', signal: 'poke', diff --git a/apps/orchestrator/src/workflows/index.ts b/apps/orchestrator/src/workflows/index.ts index 4e0bccd3..bdeced1a 100644 --- a/apps/orchestrator/src/workflows/index.ts +++ b/apps/orchestrator/src/workflows/index.ts @@ -1,5 +1,6 @@ export * from './post-workflows/post.workflow.v1.0.1'; export * from './post-workflows/post.workflow.v1.0.2'; +export * from './post-workflows/post.workflow.v1.0.3'; export * from './autopost.workflow'; export * from './digest.email.workflow'; export * from './missing.post.workflow'; diff --git a/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.3.ts b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.3.ts new file mode 100644 index 00000000..1c80a2ed --- /dev/null +++ b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.3.ts @@ -0,0 +1,430 @@ +import { PostActivity } from '@gitroom/orchestrator/activities/post.activity'; +import { + ActivityFailure, + ApplicationFailure, + startChild, + proxyActivities, + sleep, + defineSignal, + setHandler, +} from '@temporalio/workflow'; +import dayjs from 'dayjs'; +import { Integration } from '@prisma/client'; +import { capitalize, sortBy } from 'lodash'; +import { PostResponse } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; +import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; +import { TypedSearchAttributes } from '@temporalio/common'; +import { postId as postIdSearchParam } from '@gitroom/nestjs-libraries/temporal/temporal.search.attribute'; + +const proxyTaskQueue = (taskQueue: string) => { + return proxyActivities({ + startToCloseTimeout: '10 minute', + taskQueue, + retry: { + maximumAttempts: 3, + backoffCoefficient: 1, + initialInterval: '2 minutes', + }, + }); +}; + +const { + getPostsList, + inAppNotification, + changeState, + updatePost, + sendWebhooks, + isCommentable, +} = proxyActivities({ + startToCloseTimeout: '10 minute', + retry: { + maximumAttempts: 3, + backoffCoefficient: 1, + initialInterval: '2 minutes', + }, +}); + +const poke = defineSignal('poke'); + +const iterate = Array.from({ length: 5 }); + +export async function postWorkflowV103({ + taskQueue, + postId, + organizationId, + postNow = false, +}: { + taskQueue: string; + postId: string; + organizationId: string; + postNow?: boolean; +}) { + // Dynamic task queue, for concurrency + const { + postSocial, + postComment, + getIntegrationById, + refreshTokenWithCause, + internalPlugs, + globalPlugs, + processInternalPlug, + processPlug, + } = proxyTaskQueue(taskQueue); + + let poked = false; + setHandler(poke, () => { + poked = true; + }); + + const startTime = new Date(); + // get all the posts and comments to post + const postsListBefore = await getPostsList(organizationId, postId); + const [post] = postsListBefore; + + // in case doesn't exists for some reason, fail it + if (!post || (!postNow && post.state !== 'QUEUE')) { + await changeState( + postsListBefore[0].id, + 'ERROR', + 'Already posted', + postsListBefore + ); + return; + } + + // if it's a repeatable post, we should ignore this. + if (!postNow) { + await sleep( + dayjs(post.publishDate).isBefore(dayjs()) + ? 0 + : dayjs(post.publishDate).diff(dayjs(), 'millisecond') + ); + } + + // if refresh is needed from last time, let's inform the user + if (post.integration?.refreshNeeded) { + await inAppNotification( + post.organizationId, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name}`, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name} because you need to reconnect it. Please enable it and try again.`, + true, + false, + 'info' + ); + + await changeState( + postsListBefore[0].id, + 'ERROR', + 'Refresh channel needed', + postsListBefore + ); + return; + } + + // if it's disabled, inform the user + if (post.integration?.disabled) { + await inAppNotification( + post.organizationId, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name}`, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name} because it's disabled. Please enable it and try again.`, + true, + false, + 'info' + ); + + await changeState( + postsListBefore[0].id, + 'ERROR', + 'Channel disabled', + postsListBefore + ); + return; + } + + // Do we need to post comment for this social? + const toComment: boolean = + postsListBefore.length === 1 + ? false + : await isCommentable(post.integration); + + const postsList = toComment ? postsListBefore : [postsListBefore[0]]; + + // list of all the saved results + const postsResults: PostResponse[] = []; + + // iterate over the posts + for (let i = 0; i < postsList.length; i++) { + const before = postsResults.length; + // this is a small trick to repeat an action in case of token refresh + for (const _ of iterate) { + try { + // first post the main post + if (i === 0) { + postsResults.push( + ...(await postSocial(post.integration as Integration, [ + postsList[i], + ])) + ); + + // then post the comments if any + } else { + if (postsList[i].delay) { + await sleep(60000 * Math.max(0, Number(postsList[i].delay ?? 0))); + } + + postsResults.push( + ...(await postComment( + postsResults[0].postId, + postsResults.length === 1 + ? undefined + : postsResults[i - 1].postId, + post.integration, + [postsList[i]] + )) + ); + } + + // mark post as successful + await updatePost( + postsList[i].id, + postsResults[i].postId, + postsResults[i].releaseURL + ); + + if (i === 0) { + // send notification on a sucessful post + await inAppNotification( + post.integration.organizationId, + `Your post has been published on ${capitalize( + post.integration.providerIdentifier + )}`, + `Your post has been published on ${capitalize( + post.integration.providerIdentifier + )} at ${postsResults[0].releaseURL}`, + true, + true + ); + } + + // break the current while to move to the next post + break; + } catch (err) { + // if token refresh is needed, do it and repeat + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + post.integration, + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + await changeState(postsList[0].id, 'ERROR', err, postsList); + return false; + } + + post.integration.token = refresh.accessToken; + continue; + } + + // for other errors, change state and inform the user if needed + await changeState(postsList[0].id, 'ERROR', err, postsList); + + // specific case for bad body errors + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + await inAppNotification( + post.organizationId, + `Error posting${i === 0 ? ' ' : ' comments '}on ${ + post.integration?.providerIdentifier + } for ${post?.integration?.name}`, + `An error occurred while posting${i === 0 ? ' ' : ' comments '}on ${ + post.integration?.providerIdentifier + }${err?.cause?.message ? `: ${err?.cause?.message}` : ``}`, + true, + false, + 'fail' + ); + return false; + } + } + } + + if (postsResults.length === before) { + // all retries exhausted without success + return false; + } + } + + // send webhooks for the post + await sendWebhooks( + postsResults[0].postId, + post.organizationId, + post.integration.id + ); + + // load internal plugs like repost by other users + const internalPlugsList = await internalPlugs( + post.integration, + JSON.parse(post.settings) + ); + + // load global plugs, like repost a post if it gets to a certain number of likes + const globalPlugsList = (await globalPlugs(post.integration)).reduce( + (all, current) => { + for (let i = 1; i <= current.totalRuns; i++) { + all.push({ + ...current, + delay: current.delay * i, + }); + } + + return all; + }, + [] + ); + + // Check if the post is repeatable + const repeatPost = !post.intervalInDays + ? [] + : [ + { + type: 'repeat-post', + delay: + post.intervalInDays * 24 * 60 * 60 * 1000 - + (new Date().getTime() - startTime.getTime()), + }, + ]; + + // Sort all the actions by delay, so we can process them in order + const list = sortBy( + [...internalPlugsList, ...globalPlugsList, ...repeatPost], + 'delay' + ); + + // process all the plugs in order, we are using while because in some cases we need to remove items from the list + while (list.length > 0) { + // get the next to process + const todo = list.shift(); + + // wait for the delay + await sleep(Math.max(0, Number(todo.delay ?? 0))); + + // process internal plug + if (todo.type === 'internal-plug') { + for (const _ of iterate) { + try { + await processInternalPlug({ ...todo, post: postsResults[0].postId }); + } catch (err) { + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + await getIntegrationById(organizationId, todo.integration), + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + break; + } + + continue; + } + + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + break; + } + + continue; + } + break; + } + } + + // process global plug + if (todo.type === 'global') { + for (const _ of iterate) { + try { + const process = await processPlug({ + ...todo, + postId: postsResults[0].postId, + }); + if (process) { + const toDelete = list + .reduce((all, current, index) => { + if (current.plugId === todo.plugId) { + all.push(index); + } + + return all; + }, []) + .reverse(); + + for (const index of toDelete) { + list.splice(index, 1); + } + } + } catch (err) { + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + post.integration, + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + break; + } + + continue; + } + + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + break; + } + + continue; + } + + break; + } + } + + // process repeat post in a new workflow, this is important so the other plugs can keep running + if (todo.type === 'repeat-post') { + await startChild(postWorkflowV103, { + parentClosePolicy: 'ABANDON', + args: [ + { + taskQueue, + postId, + organizationId, + postNow: true, + }, + ], + workflowId: `post_${post.id}_${makeId(10)}`, + typedSearchAttributes: new TypedSearchAttributes([ + { + key: postIdSearchParam, + value: postId, + }, + ]), + }); + } + } +} diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts index 1dce2267..be031e24 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.repository.ts @@ -37,8 +37,8 @@ export class PostsRepository { disabled: false, }, publishDate: { - gte: dayjs.utc().subtract(2, 'hour').toDate(), - lt: dayjs.utc().add(2, 'hour').toDate(), + gte: dayjs.utc().subtract(2, 'day').toDate(), + lt: dayjs.utc().toDate(), }, state: 'QUEUE', deletedAt: null, diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 6d05be20..5cf9ba36 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -706,7 +706,7 @@ export class PostsService { try { await this._temporalService.client .getRawClient() - ?.workflow.start('postWorkflowV102', { + ?.workflow.start('postWorkflowV103', { workflowId: `post_${postId}`, taskQueue: 'main', workflowIdConflictPolicy: 'TERMINATE_EXISTING', From 7be292094ad4c7a8593635bbe1c1c0bce99795ca Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 11 May 2026 14:15:33 +0700 Subject: [PATCH 78/80] feat: no post --- .../src/activities/post.activity.ts | 2 +- apps/orchestrator/src/workflows/index.ts | 1 + .../post-workflows/post.workflow.v1.0.4.ts | 434 ++++++++++++++++++ .../database/prisma/posts/posts.service.ts | 2 +- 4 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts diff --git a/apps/orchestrator/src/activities/post.activity.ts b/apps/orchestrator/src/activities/post.activity.ts index 6ca7a478..b2e9a62b 100644 --- a/apps/orchestrator/src/activities/post.activity.ts +++ b/apps/orchestrator/src/activities/post.activity.ts @@ -76,7 +76,7 @@ export class PostActivity { for (const post of list) { await this._temporalService.client .getRawClient() - .workflow.signalWithStart('postWorkflowV103', { + .workflow.signalWithStart('postWorkflowV104', { workflowId: `post_${post.id}`, taskQueue: 'main', signal: 'poke', diff --git a/apps/orchestrator/src/workflows/index.ts b/apps/orchestrator/src/workflows/index.ts index bdeced1a..b4da83e8 100644 --- a/apps/orchestrator/src/workflows/index.ts +++ b/apps/orchestrator/src/workflows/index.ts @@ -1,6 +1,7 @@ export * from './post-workflows/post.workflow.v1.0.1'; export * from './post-workflows/post.workflow.v1.0.2'; export * from './post-workflows/post.workflow.v1.0.3'; +export * from './post-workflows/post.workflow.v1.0.4'; export * from './autopost.workflow'; export * from './digest.email.workflow'; export * from './missing.post.workflow'; diff --git a/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts new file mode 100644 index 00000000..65d9d591 --- /dev/null +++ b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts @@ -0,0 +1,434 @@ +import { PostActivity } from '@gitroom/orchestrator/activities/post.activity'; +import { + ActivityFailure, + ApplicationFailure, + startChild, + proxyActivities, + sleep, + defineSignal, + setHandler, +} from '@temporalio/workflow'; +import dayjs from 'dayjs'; +import { Integration } from '@prisma/client'; +import { capitalize, sortBy } from 'lodash'; +import { PostResponse } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; +import { makeId } from '@gitroom/nestjs-libraries/services/make.is'; +import { TypedSearchAttributes } from '@temporalio/common'; +import { postId as postIdSearchParam } from '@gitroom/nestjs-libraries/temporal/temporal.search.attribute'; + +const proxyTaskQueue = (taskQueue: string) => { + return proxyActivities({ + startToCloseTimeout: '10 minute', + taskQueue, + retry: { + maximumAttempts: 3, + backoffCoefficient: 1, + initialInterval: '2 minutes', + }, + }); +}; + +const { + getPostsList, + inAppNotification, + changeState, + updatePost, + sendWebhooks, + isCommentable, +} = proxyActivities({ + startToCloseTimeout: '10 minute', + retry: { + maximumAttempts: 3, + backoffCoefficient: 1, + initialInterval: '2 minutes', + }, +}); + +const poke = defineSignal('poke'); + +const iterate = Array.from({ length: 5 }); + +export async function postWorkflowV104({ + taskQueue, + postId, + organizationId, + postNow = false, +}: { + taskQueue: string; + postId: string; + organizationId: string; + postNow?: boolean; +}) { + // Dynamic task queue, for concurrency + const { + postSocial, + postComment, + getIntegrationById, + refreshTokenWithCause, + internalPlugs, + globalPlugs, + processInternalPlug, + processPlug, + } = proxyTaskQueue(taskQueue); + + let poked = false; + setHandler(poke, () => { + poked = true; + }); + + const startTime = new Date(); + // get all the posts and comments to post + const postsListBefore = await getPostsList(organizationId, postId); + const [post] = postsListBefore; + + // in case doesn't exists for some reason, fail it + if (!post) { + return ; + } + + if (!postNow && post.state !== 'QUEUE') { + await changeState( + postsListBefore[0].id, + 'ERROR', + 'Already posted', + postsListBefore + ); + return; + } + + // if it's a repeatable post, we should ignore this. + if (!postNow) { + await sleep( + dayjs(post.publishDate).isBefore(dayjs()) + ? 0 + : dayjs(post.publishDate).diff(dayjs(), 'millisecond') + ); + } + + // if refresh is needed from last time, let's inform the user + if (post.integration?.refreshNeeded) { + await inAppNotification( + post.organizationId, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name}`, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name} because you need to reconnect it. Please enable it and try again.`, + true, + false, + 'info' + ); + + await changeState( + postsListBefore[0].id, + 'ERROR', + 'Refresh channel needed', + postsListBefore + ); + return; + } + + // if it's disabled, inform the user + if (post.integration?.disabled) { + await inAppNotification( + post.organizationId, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name}`, + `We couldn't post to ${post.integration?.providerIdentifier} for ${post?.integration?.name} because it's disabled. Please enable it and try again.`, + true, + false, + 'info' + ); + + await changeState( + postsListBefore[0].id, + 'ERROR', + 'Channel disabled', + postsListBefore + ); + return; + } + + // Do we need to post comment for this social? + const toComment: boolean = + postsListBefore.length === 1 + ? false + : await isCommentable(post.integration); + + const postsList = toComment ? postsListBefore : [postsListBefore[0]]; + + // list of all the saved results + const postsResults: PostResponse[] = []; + + // iterate over the posts + for (let i = 0; i < postsList.length; i++) { + const before = postsResults.length; + // this is a small trick to repeat an action in case of token refresh + for (const _ of iterate) { + try { + // first post the main post + if (i === 0) { + postsResults.push( + ...(await postSocial(post.integration as Integration, [ + postsList[i], + ])) + ); + + // then post the comments if any + } else { + if (postsList[i].delay) { + await sleep(60000 * Math.max(0, Number(postsList[i].delay ?? 0))); + } + + postsResults.push( + ...(await postComment( + postsResults[0].postId, + postsResults.length === 1 + ? undefined + : postsResults[i - 1].postId, + post.integration, + [postsList[i]] + )) + ); + } + + // mark post as successful + await updatePost( + postsList[i].id, + postsResults[i].postId, + postsResults[i].releaseURL + ); + + if (i === 0) { + // send notification on a sucessful post + await inAppNotification( + post.integration.organizationId, + `Your post has been published on ${capitalize( + post.integration.providerIdentifier + )}`, + `Your post has been published on ${capitalize( + post.integration.providerIdentifier + )} at ${postsResults[0].releaseURL}`, + true, + true + ); + } + + // break the current while to move to the next post + break; + } catch (err) { + // if token refresh is needed, do it and repeat + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + post.integration, + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + await changeState(postsList[0].id, 'ERROR', err, postsList); + return false; + } + + post.integration.token = refresh.accessToken; + continue; + } + + // for other errors, change state and inform the user if needed + await changeState(postsList[0].id, 'ERROR', err, postsList); + + // specific case for bad body errors + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + await inAppNotification( + post.organizationId, + `Error posting${i === 0 ? ' ' : ' comments '}on ${ + post.integration?.providerIdentifier + } for ${post?.integration?.name}`, + `An error occurred while posting${i === 0 ? ' ' : ' comments '}on ${ + post.integration?.providerIdentifier + }${err?.cause?.message ? `: ${err?.cause?.message}` : ``}`, + true, + false, + 'fail' + ); + return false; + } + } + } + + if (postsResults.length === before) { + // all retries exhausted without success + return false; + } + } + + // send webhooks for the post + await sendWebhooks( + postsResults[0].postId, + post.organizationId, + post.integration.id + ); + + // load internal plugs like repost by other users + const internalPlugsList = await internalPlugs( + post.integration, + JSON.parse(post.settings) + ); + + // load global plugs, like repost a post if it gets to a certain number of likes + const globalPlugsList = (await globalPlugs(post.integration)).reduce( + (all, current) => { + for (let i = 1; i <= current.totalRuns; i++) { + all.push({ + ...current, + delay: current.delay * i, + }); + } + + return all; + }, + [] + ); + + // Check if the post is repeatable + const repeatPost = !post.intervalInDays + ? [] + : [ + { + type: 'repeat-post', + delay: + post.intervalInDays * 24 * 60 * 60 * 1000 - + (new Date().getTime() - startTime.getTime()), + }, + ]; + + // Sort all the actions by delay, so we can process them in order + const list = sortBy( + [...internalPlugsList, ...globalPlugsList, ...repeatPost], + 'delay' + ); + + // process all the plugs in order, we are using while because in some cases we need to remove items from the list + while (list.length > 0) { + // get the next to process + const todo = list.shift(); + + // wait for the delay + await sleep(Math.max(0, Number(todo.delay ?? 0))); + + // process internal plug + if (todo.type === 'internal-plug') { + for (const _ of iterate) { + try { + await processInternalPlug({ ...todo, post: postsResults[0].postId }); + } catch (err) { + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + await getIntegrationById(organizationId, todo.integration), + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + break; + } + + continue; + } + + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + break; + } + + continue; + } + break; + } + } + + // process global plug + if (todo.type === 'global') { + for (const _ of iterate) { + try { + const process = await processPlug({ + ...todo, + postId: postsResults[0].postId, + }); + if (process) { + const toDelete = list + .reduce((all, current, index) => { + if (current.plugId === todo.plugId) { + all.push(index); + } + + return all; + }, []) + .reverse(); + + for (const index of toDelete) { + list.splice(index, 1); + } + } + } catch (err) { + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'refresh_token' + ) { + const refresh = await refreshTokenWithCause( + post.integration, + err?.cause?.message || '' + ); + if (!refresh || !refresh.accessToken) { + break; + } + + continue; + } + + if ( + err instanceof ActivityFailure && + err.cause instanceof ApplicationFailure && + err.cause.type === 'bad_body' + ) { + break; + } + + continue; + } + + break; + } + } + + // process repeat post in a new workflow, this is important so the other plugs can keep running + if (todo.type === 'repeat-post') { + await startChild(postWorkflowV104, { + parentClosePolicy: 'ABANDON', + args: [ + { + taskQueue, + postId, + organizationId, + postNow: true, + }, + ], + workflowId: `post_${post.id}_${makeId(10)}`, + typedSearchAttributes: new TypedSearchAttributes([ + { + key: postIdSearchParam, + value: postId, + }, + ]), + }); + } + } +} diff --git a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts index 5cf9ba36..2ca5c875 100644 --- a/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts +++ b/libraries/nestjs-libraries/src/database/prisma/posts/posts.service.ts @@ -706,7 +706,7 @@ export class PostsService { try { await this._temporalService.client .getRawClient() - ?.workflow.start('postWorkflowV103', { + ?.workflow.start('postWorkflowV104', { workflowId: `post_${postId}`, taskQueue: 'main', workflowIdConflictPolicy: 'TERMINATE_EXISTING', From 905392513fabd2f0cdb2bc9f9379352160c924df Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 11 May 2026 14:16:08 +0700 Subject: [PATCH 79/80] feat: no post --- .../src/workflows/post-workflows/post.workflow.v1.0.4.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts index 65d9d591..c09d15a8 100644 --- a/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts +++ b/apps/orchestrator/src/workflows/post-workflows/post.workflow.v1.0.4.ts @@ -83,7 +83,12 @@ export async function postWorkflowV104({ // in case doesn't exists for some reason, fail it if (!post) { - return ; + await changeState( + postId, + 'ERROR', + 'No Post' + ); + return; } if (!postNow && post.state !== 'QUEUE') { From 009bd365284542f1cc4875257baf9d4ef4464ee6 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Mon, 11 May 2026 17:50:14 +0700 Subject: [PATCH 80/80] feat: fix tiktok url ownership error --- .../nestjs-libraries/src/integrations/social/tiktok.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/integrations/social/tiktok.provider.ts b/libraries/nestjs-libraries/src/integrations/social/tiktok.provider.ts index b3b042db..768403e0 100644 --- a/libraries/nestjs-libraries/src/integrations/social/tiktok.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/tiktok.provider.ts @@ -184,7 +184,7 @@ export class TiktokProvider extends SocialAbstract implements SocialProvider { if (body.indexOf('url_ownership_unverified') > -1) { return { type: 'bad-body' as const, - value: 'URL ownership not verified, please verify domain ownership', + value: 'You have to upload the picture/video to Postiz when sending a URL', }; }