Skip to content

Commit

Permalink
Merge pull request #374 from refly-ai/fix/stream-invoke-401
Browse files Browse the repository at this point in the history
Fix/stream invoke 401
  • Loading branch information
mrcfps authored Jan 15, 2025
2 parents 637cf31 + 33ba40d commit c51a935
Show file tree
Hide file tree
Showing 10 changed files with 244 additions and 220 deletions.
2 changes: 1 addition & 1 deletion apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class CustomThrottlerGuard extends ThrottlerGuard {
},
],
getTracker: (req) => (req.ips?.length ? req.ips[0] : req.ip),
storage: new ThrottlerStorageRedisService(redis),
// storage: new ThrottlerStorageRedisService(redis),
}),
}),
LoggerModule.forRoot({
Expand Down
82 changes: 42 additions & 40 deletions apps/api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { randomBytes } from 'node:crypto';
import argon2 from 'argon2';
import ms from 'ms';
import { Profile } from 'passport';
import { Response } from 'express';
import { CookieOptions, Response } from 'express';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { User as UserModel, VerificationSession } from '@prisma/client';
Expand All @@ -13,6 +13,7 @@ import {
genUID,
genVerificationSessionID,
LEGACY_TOKEN_COOKIE,
omit,
pick,
REFRESH_TOKEN_COOKIE,
UID_COOKIE,
Expand Down Expand Up @@ -171,51 +172,52 @@ export class AuthService {
});
}

cookieOptions(key: string): CookieOptions {
const baseOptions: CookieOptions = {
domain: this.configService.get('auth.cookieDomain') ?? '',
secure: true,
sameSite: 'strict',
path: '/',
};

switch (key) {
case UID_COOKIE:
return {
...baseOptions,
expires: new Date(Date.now() + ms(this.configService.get('auth.jwt.refreshExpiresIn'))),
};
case ACCESS_TOKEN_COOKIE:
return {
...baseOptions,
httpOnly: true,
expires: new Date(Date.now() + ms(this.configService.get('auth.jwt.expiresIn'))),
};
case REFRESH_TOKEN_COOKIE:
return {
...baseOptions,
httpOnly: true,
expires: new Date(Date.now() + ms(this.configService.get('auth.jwt.refreshExpiresIn'))),
};
default:
return baseOptions;
}
}

setAuthCookie(res: Response, { uid, accessToken, refreshToken }: TokenData) {
return res
.cookie(UID_COOKIE, uid, {
domain: this.configService.get('auth.cookieDomain'),
secure: true,
sameSite: 'strict',
})
.cookie(ACCESS_TOKEN_COOKIE, accessToken, {
domain: this.configService.get('auth.cookieDomain'),
httpOnly: true,
secure: true,
sameSite: 'strict',
})
.cookie(REFRESH_TOKEN_COOKIE, refreshToken, {
domain: this.configService.get('auth.cookieDomain'),
httpOnly: true,
secure: true,
sameSite: 'strict',
});
.cookie(UID_COOKIE, uid, this.cookieOptions(UID_COOKIE))
.cookie(ACCESS_TOKEN_COOKIE, accessToken, this.cookieOptions(ACCESS_TOKEN_COOKIE))
.cookie(REFRESH_TOKEN_COOKIE, refreshToken, this.cookieOptions(REFRESH_TOKEN_COOKIE));
}

clearAuthCookie(res: Response) {
const clearOptions = omit(this.cookieOptions(UID_COOKIE), ['expires']);

return res
.clearCookie(UID_COOKIE, {
domain: this.configService.get('auth.cookieDomain'),
secure: true,
sameSite: 'strict',
})
.clearCookie(ACCESS_TOKEN_COOKIE, {
domain: this.configService.get('auth.cookieDomain'),
httpOnly: true,
secure: true,
sameSite: 'strict',
})
.clearCookie(REFRESH_TOKEN_COOKIE, {
domain: this.configService.get('auth.cookieDomain'),
httpOnly: true,
secure: true,
sameSite: 'strict',
})
.clearCookie(LEGACY_TOKEN_COOKIE, {
domain: this.configService.get('auth.cookieDomain'),
secure: true,
sameSite: 'strict',
});
.clearCookie(UID_COOKIE, clearOptions)
.clearCookie(ACCESS_TOKEN_COOKIE, clearOptions)
.clearCookie(REFRESH_TOKEN_COOKIE, clearOptions)
.clearCookie(LEGACY_TOKEN_COOKIE, clearOptions);
}

async genUniqueUsername(candidate: string) {
Expand Down
14 changes: 13 additions & 1 deletion apps/api/src/skill/skill.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,19 @@ export class SkillService {
);

const throttledResetIdleTimeout = throttle(
async () => await job.changeDelay(this.config.get('skill.idleTimeout')),
async () => {
try {
// Get current job state
const jobState = await job.getState();

// Only attempt to change delay if job is in delayed state
if (jobState === 'delayed') {
await job.changeDelay(this.config.get('skill.idleTimeout'));
}
} catch (err) {
this.logger.warn(`Failed to reset idle timeout: ${err.message}`);
}
},
100,
{ leading: true, trailing: true },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ import { convertResultContextToItems } from '@refly-packages/ai-workspace-common
import { NodeResizer as NodeResizerComponent } from './shared/node-resizer';
import { useNodeSize } from '@refly-packages/ai-workspace-common/hooks/canvas/use-node-size';
import { ContentPreview } from './shared/content-preview';
import { useActionPolling } from '@refly-packages/ai-workspace-common/hooks/canvas/use-action-polling';

const POLLING_WAIT_TIME = 15000;

type SkillResponseNode = Node<CanvasNodeData<ResponseNodeMeta>, 'skillResponse'>;

Expand Down Expand Up @@ -173,7 +176,25 @@ export const SkillResponseNode = memo(
});
const moveableRef = useRef<Moveable>(null);

const { status, artifacts, currentLog: log, modelInfo, structuredData, actionMeta, tokenUsage } = metadata ?? {};
const {
status,
artifacts,
currentLog: log,
modelInfo,
structuredData,
actionMeta,
tokenUsage,
version,
} = metadata ?? {};

const { startPolling } = useActionPolling();

useEffect(() => {
if (createdAt && Date.now() - new Date(createdAt).getTime() >= POLLING_WAIT_TIME && status === 'executing') {
startPolling(entityId, version);
}
}, [createdAt, status, startPolling, entityId, version]);

const sources = Array.isArray(structuredData?.sources) ? structuredData?.sources : [];

const logTitle = log
Expand Down
17 changes: 13 additions & 4 deletions packages/ai-workspace-common/src/context/document.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, useContext, useEffect, useMemo } from 'react';
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import * as Y from 'yjs';
import { HocuspocusProvider } from '@hocuspocus/provider';
import { IndexeddbPersistence } from 'y-indexeddb';
Expand All @@ -12,12 +12,14 @@ interface DocumentContextType {
ydoc: Y.Doc;
provider: HocuspocusProvider;
localProvider: IndexeddbPersistence;
isLoading: boolean;
}

const DocumentContext = createContext<DocumentContextType | null>(null);

export const DocumentProvider = ({ docId, children }: { docId: string; children: React.ReactNode }) => {
const { token, refreshToken } = useCollabToken();
const [isLoading, setIsLoading] = useState(true);

const { setDocumentLocalSyncedAt, setDocumentRemoteSyncedAt, updateDocument } = useDocumentStoreShallow((state) => ({
setDocumentLocalSyncedAt: state.setDocumentLocalSyncedAt,
Expand Down Expand Up @@ -46,13 +48,15 @@ export const DocumentProvider = ({ docId, children }: { docId: string; children:
remoteProvider.on('synced', () => {
setDocumentRemoteSyncedAt(docId, Date.now());
editorEmitter.emit('editorSynced');
setIsLoading(false);
});

// Add local provider
const localProvider = new IndexeddbPersistence(docId, doc);

localProvider.on('synced', () => {
setDocumentLocalSyncedAt(docId, Date.now());
setIsLoading(false);
});

return { remote: remoteProvider, local: localProvider, doc };
Expand All @@ -70,6 +74,11 @@ export const DocumentProvider = ({ docId, children }: { docId: string; children:

title.observe(titleObserverCallback);

// Initial title update
if (title?.toJSON()) {
titleObserverCallback();
}

return () => {
title.unobserve(titleObserverCallback);

Expand All @@ -81,13 +90,13 @@ export const DocumentProvider = ({ docId, children }: { docId: string; children:
};
}, [provider, docId, token, localProvider]);

// Add null check before rendering
if (!provider) {
// Add loading state check
if (!provider || isLoading) {
return null;
}

return (
<DocumentContext.Provider value={{ docId, provider, localProvider, ydoc: doc }}>
<DocumentContext.Provider value={{ docId, provider, localProvider, ydoc: doc, isLoading }}>
{children}
</DocumentContext.Provider>
);
Expand Down
Loading

0 comments on commit c51a935

Please sign in to comment.