mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-11 18:28:29 +00:00
Fix: authentication and ingest API
This commit is contained in:
parent
33eae2619a
commit
941ce8e4fa
@ -11,6 +11,7 @@
|
||||
C.O.R.E lets you create a private, portable, open-source memory space for LLMs, all stored locally for full data control. You decide what to share or connect with other tools, managing exactly what gets recalled and where.
|
||||
|
||||
C.O.R.E is built for two reasons:
|
||||
|
||||
1. To give you complete ownership of your memory, stored locally and accessible across any app needing LLM context.
|
||||
2. To help SOL (your AI assistant) access your context, facts, and preferences for more relevant and personalized responses.
|
||||
|
||||
@ -25,10 +26,10 @@ C.O.R.E supports **temporal reasoning**, **relational memory**, and **traceabili
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. Docker
|
||||
2. OpenAI API Key
|
||||
|
||||
|
||||
### Run C.O.R.E locally by
|
||||
|
||||
1. **Copy Environment Variables**
|
||||
@ -97,7 +98,6 @@ You can also interact with C.O.R.E. programmatically via its APIs.
|
||||
{
|
||||
"episodeBody": "I love playing badminton",
|
||||
"referenceTime": "2024-06-01T12:00:00Z",
|
||||
"type": "Conversation", // or "Text"
|
||||
"source": "user", // Which tool or user is ingesting
|
||||
"spaceId": "your-space-id", // optional, for multiple spaces
|
||||
"sessionId": "your-session-id" // optional
|
||||
|
||||
@ -76,9 +76,10 @@ export function getUserQueue(userId: string) {
|
||||
}
|
||||
|
||||
export const IngestBodyRequest = z.object({
|
||||
name: z.string(),
|
||||
episodeBody: z.string(),
|
||||
referenceTime: z.string(),
|
||||
type: z.enum([EpisodeType.Conversation, EpisodeType.Text]), // Assuming these are the EpisodeType values
|
||||
metadata: z.record(z.union([z.string(), z.number()])),
|
||||
source: z.string(),
|
||||
spaceId: z.string().optional(),
|
||||
sessionId: z.string().optional(),
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
import {
|
||||
createCookie,
|
||||
redirect,
|
||||
type ActionFunctionArgs,
|
||||
type LoaderFunctionArgs,
|
||||
type MetaFunction,
|
||||
} from "@remix-run/node";
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "~/components/ui/card";
|
||||
import { Form, useNavigation } from "@remix-run/react";
|
||||
import { Inbox, Loader, Mail } from "lucide-react";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
@ -16,8 +23,7 @@ import { FormButtons } from "~/components/ui/FormButtons";
|
||||
import { Header1 } from "~/components/ui/Headers";
|
||||
import { Input } from "~/components/ui/input";
|
||||
import { Paragraph } from "~/components/ui/Paragraph";
|
||||
import { TextLink } from "~/components/ui/TextLink";
|
||||
|
||||
import { Cookie } from "@mjackson/headers";
|
||||
import { authenticator } from "~/services/auth.server";
|
||||
import { getUserId } from "~/services/session.server";
|
||||
import {
|
||||
@ -65,10 +71,14 @@ export async function loader({ request }: LoaderFunctionArgs): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
const magicLinkSent = new Cookie(request.headers.get("cookie") ?? "").has(
|
||||
"core:magiclink",
|
||||
);
|
||||
|
||||
return typedjson(
|
||||
{
|
||||
emailLoginEnabled: true,
|
||||
magicLinkSent: session.has("core:magiclink"),
|
||||
magicLinkSent,
|
||||
magicLinkError,
|
||||
},
|
||||
{
|
||||
@ -93,14 +103,19 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
.parse(payload);
|
||||
|
||||
if (action === "send") {
|
||||
return await authenticator.authenticate("email-link", request);
|
||||
const headers = await authenticator
|
||||
.authenticate("email-link", request)
|
||||
.catch((headers) => headers);
|
||||
throw redirect("/login/magic", { headers });
|
||||
} else {
|
||||
const session = await getUserSession(request);
|
||||
session.unset("core:magiclink");
|
||||
const myCookie = createCookie("core:magiclink");
|
||||
|
||||
return redirect("/magic", {
|
||||
return redirect("/login/magic", {
|
||||
headers: {
|
||||
"Set-Cookie": await commitSession(session),
|
||||
"Set-Cookie": await myCookie.serialize("", {
|
||||
maxAge: 0,
|
||||
path: "/",
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -130,80 +145,81 @@ export default function LoginMagicLinkPage() {
|
||||
<Form method="post">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
{data.magicLinkSent ? (
|
||||
<>
|
||||
<Header1 className="pb-6 text-center text-xl leading-7 font-normal md:text-xl lg:text-2xl">
|
||||
We've sent you a magic link!
|
||||
</Header1>
|
||||
<Fieldset className="flex w-full flex-col items-center gap-y-2">
|
||||
<Inbox className="text-primary mb-4 h-12 w-12" />
|
||||
<Paragraph className="mb-6 text-center">
|
||||
<Card className="min-w-[400px] rounded-md p-3">
|
||||
<CardHeader className="flex flex-col items-start">
|
||||
<CardTitle className="mb-0 text-lg">
|
||||
{" "}
|
||||
We've sent you a magic link!
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
We sent you an email which contains a magic link that will log
|
||||
you in to your account.
|
||||
</Paragraph>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<Fieldset className="flex w-full flex-col items-center gap-y-2 px-2">
|
||||
<FormButtons
|
||||
cancelButton={
|
||||
<Button
|
||||
type="submit"
|
||||
name="action"
|
||||
value="reset"
|
||||
variant="link"
|
||||
variant="secondary"
|
||||
data-action="re-enter email"
|
||||
>
|
||||
Re-enter email
|
||||
</Button>
|
||||
}
|
||||
confirmButton={
|
||||
<Button
|
||||
variant="ghost"
|
||||
data-action="log in using another option"
|
||||
>
|
||||
Log in using another option
|
||||
</Button>
|
||||
}
|
||||
confirmButton={<></>}
|
||||
/>
|
||||
</Fieldset>
|
||||
</>
|
||||
</Card>
|
||||
) : (
|
||||
<>
|
||||
<Header1 className="pb-4 font-semibold sm:text-2xl md:text-3xl lg:text-4xl">
|
||||
Welcome
|
||||
</Header1>
|
||||
<Paragraph variant="base" className="mb-6 text-center">
|
||||
Create an account or login using email
|
||||
</Paragraph>
|
||||
<Fieldset className="flex w-full flex-col items-center gap-y-2">
|
||||
<Input
|
||||
type="email"
|
||||
name="email"
|
||||
spellCheck={false}
|
||||
placeholder="Email Address"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
<Card className="min-w-[400px] rounded-md p-3">
|
||||
<CardHeader className="flex flex-col items-start">
|
||||
<CardTitle className="mb-0 text-lg">Welcome</CardTitle>
|
||||
<CardDescription>
|
||||
Create an account or login using email
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-2">
|
||||
<Fieldset className="flex w-full flex-col items-center gap-y-2">
|
||||
<Input
|
||||
type="email"
|
||||
name="email"
|
||||
className="h-9"
|
||||
spellCheck={false}
|
||||
placeholder="Email Address"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
<Button
|
||||
name="action"
|
||||
value="send"
|
||||
type="submit"
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
disabled={isLoading}
|
||||
data-action="send a magic link"
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loader className="mr-2 size-5" color="white" />
|
||||
) : (
|
||||
<Mail className="text-text-bright mr-2 size-5" />
|
||||
)}
|
||||
{isLoading ? (
|
||||
<span className="text-text-bright">Sending…</span>
|
||||
) : (
|
||||
<span className="text-text-bright">Send a magic link</span>
|
||||
)}
|
||||
</Button>
|
||||
{data.magicLinkError && <>{data.magicLinkError}</>}
|
||||
</Fieldset>
|
||||
</>
|
||||
<Button
|
||||
name="action"
|
||||
value="send"
|
||||
type="submit"
|
||||
variant="secondary"
|
||||
size="lg"
|
||||
disabled={isLoading}
|
||||
data-action="send a magic link"
|
||||
>
|
||||
{isLoading ? (
|
||||
<Loader className="mr-2 size-5" color="white" />
|
||||
) : (
|
||||
<Mail className="text-text-bright mr-2 size-5" />
|
||||
)}
|
||||
{isLoading ? (
|
||||
<span className="text-text-bright">Sending…</span>
|
||||
) : (
|
||||
<span className="text-text-bright">
|
||||
Send a magic link
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
{data.magicLinkError && <>{data.magicLinkError}</>}
|
||||
</Fieldset>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
@ -5,9 +5,11 @@ import { json } from "@remix-run/node";
|
||||
|
||||
export const SearchBodyRequest = z.object({
|
||||
query: z.string(),
|
||||
spaceId: z.string().optional(),
|
||||
startTime: z.string().optional(),
|
||||
endTime: z.string().optional(),
|
||||
|
||||
// These are not supported yet, but need to support these
|
||||
spaceId: z.string().optional(),
|
||||
limit: z.number().optional(),
|
||||
maxBfsDepth: z.number().optional(),
|
||||
includeInvalidated: z.boolean().optional(),
|
||||
|
||||
@ -13,7 +13,9 @@ const authenticator = new Authenticator<AuthUser>();
|
||||
|
||||
const isGoogleAuthSupported =
|
||||
typeof env.AUTH_GOOGLE_CLIENT_ID === "string" &&
|
||||
typeof env.AUTH_GOOGLE_CLIENT_SECRET === "string";
|
||||
env.AUTH_GOOGLE_CLIENT_ID.length > 0 &&
|
||||
typeof env.AUTH_GOOGLE_CLIENT_SECRET === "string" &&
|
||||
env.AUTH_GOOGLE_CLIENT_SECRET.length > 0;
|
||||
|
||||
if (env.AUTH_GOOGLE_CLIENT_ID && env.AUTH_GOOGLE_CLIENT_SECRET) {
|
||||
addGoogleStrategy(
|
||||
|
||||
@ -58,11 +58,6 @@ function buildTransportOptions(): MailTransportOptions {
|
||||
}
|
||||
|
||||
export async function sendMagicLinkEmail(options: any): Promise<void> {
|
||||
// Auto redirect when in development mode
|
||||
if (env.NODE_ENV === "development") {
|
||||
throw redirect(options.magicLink);
|
||||
}
|
||||
|
||||
logger.debug("Sending magic link email", {
|
||||
emailAddress: options.emailAddress,
|
||||
});
|
||||
@ -77,6 +72,7 @@ export async function sendMagicLinkEmail(options: any): Promise<void> {
|
||||
logger.error("Error sending magic link email", {
|
||||
error: JSON.stringify(error),
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,9 @@ const emailStrategy = new EmailLinkStrategy(
|
||||
sendEmail: sendMagicLinkEmail,
|
||||
secret,
|
||||
magicEndpoint: `${APP_ORIGIN}/magic`,
|
||||
cookie: {
|
||||
name: "core:magiclink",
|
||||
},
|
||||
},
|
||||
async ({ email }: { email: string }) => {
|
||||
logger.info("Magic link user authenticated", { email });
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
"@core/database": "workspace:*",
|
||||
"@core/types": "workspace:*",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@mjackson/headers": "0.11.1",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
|
||||
@ -1,58 +1,58 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
core:
|
||||
container_name: core-app
|
||||
image: redplanethq/core:${VERSION}
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV}
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- DIRECT_URL=${DIRECT_URL}
|
||||
- SESSION_SECRET=${SESSION_SECRET}
|
||||
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
|
||||
- MAGIC_LINK_SECRET=${MAGIC_LINK_SECRET}
|
||||
- LOGIN_ORIGIN=${LOGIN_ORIGIN}
|
||||
- APP_ORIGIN=${APP_ORIGIN}
|
||||
- REDIS_HOST=${REDIS_HOST}
|
||||
- REDIS_PORT=${REDIS_PORT}
|
||||
- REDIS_TLS_DISABLED=${REDIS_TLS_DISABLED}
|
||||
- NEO4J_URI=${NEO4J_URI}
|
||||
- NEO4J_USERNAME=${NEO4J_USERNAME}
|
||||
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
||||
- AUTH_GOOGLE_CLIENT_ID=${AUTH_GOOGLE_CLIENT_ID}
|
||||
- AUTH_GOOGLE_CLIENT_SECRET=${AUTH_GOOGLE_CLIENT_SECRET}
|
||||
- ENABLE_EMAIL_LOGIN=${ENABLE_EMAIL_LOGIN}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- neo4j
|
||||
networks:
|
||||
- core
|
||||
# core:
|
||||
# container_name: core-app
|
||||
# image: redplanethq/core:${VERSION}
|
||||
# environment:
|
||||
# - NODE_ENV=${NODE_ENV}
|
||||
# - DATABASE_URL=${DATABASE_URL}
|
||||
# - DIRECT_URL=${DIRECT_URL}
|
||||
# - SESSION_SECRET=${SESSION_SECRET}
|
||||
# - ENCRYPTION_KEY=${ENCRYPTION_KEY}
|
||||
# - MAGIC_LINK_SECRET=${MAGIC_LINK_SECRET}
|
||||
# - LOGIN_ORIGIN=${LOGIN_ORIGIN}
|
||||
# - APP_ORIGIN=${APP_ORIGIN}
|
||||
# - REDIS_HOST=${REDIS_HOST}
|
||||
# - REDIS_PORT=${REDIS_PORT}
|
||||
# - REDIS_TLS_DISABLED=${REDIS_TLS_DISABLED}
|
||||
# - NEO4J_URI=${NEO4J_URI}
|
||||
# - NEO4J_USERNAME=${NEO4J_USERNAME}
|
||||
# - NEO4J_PASSWORD=${NEO4J_PASSWORD}
|
||||
# - OPENAI_API_KEY=${OPENAI_API_KEY}
|
||||
# - AUTH_GOOGLE_CLIENT_ID=${AUTH_GOOGLE_CLIENT_ID}
|
||||
# - AUTH_GOOGLE_CLIENT_SECRET=${AUTH_GOOGLE_CLIENT_SECRET}
|
||||
# - ENABLE_EMAIL_LOGIN=${ENABLE_EMAIL_LOGIN}
|
||||
# ports:
|
||||
# - "3033:3000"
|
||||
# depends_on:
|
||||
# - postgres
|
||||
# - redis
|
||||
# - neo4j
|
||||
# networks:
|
||||
# - core
|
||||
|
||||
postgres:
|
||||
container_name: core-postgres
|
||||
image: postgres:15
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- core
|
||||
# postgres:
|
||||
# container_name: core-postgres
|
||||
# image: postgres:15
|
||||
# environment:
|
||||
# - POSTGRES_USER=${POSTGRES_USER}
|
||||
# - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
# - POSTGRES_DB=${POSTGRES_DB}
|
||||
# ports:
|
||||
# - "5432:5432"
|
||||
# volumes:
|
||||
# - postgres_data:/var/lib/postgresql/data
|
||||
# networks:
|
||||
# - core
|
||||
|
||||
redis:
|
||||
container_name: core-redis
|
||||
image: redis:7
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
- core
|
||||
# redis:
|
||||
# container_name: core-redis
|
||||
# image: redis:7
|
||||
# ports:
|
||||
# - "6379:6379"
|
||||
# networks:
|
||||
# - core
|
||||
|
||||
neo4j:
|
||||
container_name: core-neo4j
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@ -48,6 +48,9 @@ importers:
|
||||
'@core/types':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/types
|
||||
'@mjackson/headers':
|
||||
specifier: 0.11.1
|
||||
version: 0.11.1
|
||||
'@nichtsam/remix-auth-email-link':
|
||||
specifier: 3.0.0
|
||||
version: 3.0.0(remix-auth@4.2.0)
|
||||
@ -1520,6 +1523,9 @@ packages:
|
||||
'@mjackson/headers@0.10.0':
|
||||
resolution: {integrity: sha512-U1Eu1gF979k7ZoIBsJyD+T5l9MjtPONsZfoXfktsQHPJD0s7SokBGx+tLKDLsOY+gzVYAWS0yRFDNY8cgbQzWQ==}
|
||||
|
||||
'@mjackson/headers@0.11.1':
|
||||
resolution: {integrity: sha512-uXXhd4rtDdDwkqAuGef1nuafkCa1NlTmEc1Jzc0NL4YiA1yON1NFXuqJ3hOuKvNKQwkiDwdD+JJlKVyz4dunFA==}
|
||||
|
||||
'@mjackson/headers@0.9.0':
|
||||
resolution: {integrity: sha512-1WFCu2iRaqbez9hcYYI611vcH1V25R+fDfOge/CyKc8sdbzniGfy/FRhNd3DgvFF4ZEEX2ayBrvFHLtOpfvadw==}
|
||||
|
||||
@ -9776,6 +9782,8 @@ snapshots:
|
||||
|
||||
'@mjackson/headers@0.10.0': {}
|
||||
|
||||
'@mjackson/headers@0.11.1': {}
|
||||
|
||||
'@mjackson/headers@0.9.0': {}
|
||||
|
||||
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
"NEO4J_USERNAME",
|
||||
"NEO4J_PASSWORD",
|
||||
"OPENAI_API_KEY",
|
||||
"MAGIC_LINK_SECRET"
|
||||
"MAGIC_LINK_SECRET",
|
||||
"ENABLE_EMAIL_LOGIN"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user