diff --git a/.github/workflows/build-waitlist-website.yml b/.github/workflows/build-waitlist-website.yml
index 9344a53..be2707a 100644
--- a/.github/workflows/build-waitlist-website.yml
+++ b/.github/workflows/build-waitlist-website.yml
@@ -11,7 +11,7 @@ on:
env:
REGISTRY: cr.nym.sh
- IMAGE_NAME: aelis-waitlist-website
+ IMAGE_NAME: freya-waitlist-website
jobs:
build:
diff --git a/AGENTS.md b/AGENTS.md
index 1411890..aa345a8 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2,7 +2,7 @@
## Project
-AELIS is an AI-powered personal assistant that aggregates data from various sources into a contextual feed. Monorepo with `packages/` (shared libraries) and `apps/` (applications).
+FREYA is an AI-powered personal assistant that aggregates data from various sources into a contextual feed. Monorepo with `packages/` (shared libraries) and `apps/` (applications).
## Commands
diff --git a/README.md b/README.md
index 637560c..d39e95a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# aelis
+# freya
To install dependencies:
@@ -8,14 +8,14 @@ bun install
## Packages
-### @aelis/source-tfl
+### @freya/source-tfl
TfL (Transport for London) feed source for tube, overground, and Elizabeth line alerts.
#### Testing
```bash
-cd packages/aelis-source-tfl
+cd packages/freya-source-tfl
bun run test
```
diff --git a/apps/admin-dashboard/src/components/login-page.tsx b/apps/admin-dashboard/src/components/login-page.tsx
index ef94b60..0a08ffc 100644
--- a/apps/admin-dashboard/src/components/login-page.tsx
+++ b/apps/admin-dashboard/src/components/login-page.tsx
@@ -71,7 +71,7 @@ export function LoginPage({ onLogin }: LoginPageProps) {
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
- placeholder="admin@aelis.local"
+ placeholder="admin@freya.local"
required
/>
diff --git a/apps/admin-dashboard/src/components/source-config-panel.tsx b/apps/admin-dashboard/src/components/source-config-panel.tsx
index 831fc34..ec02510 100644
--- a/apps/admin-dashboard/src/components/source-config-panel.tsx
+++ b/apps/admin-dashboard/src/components/source-config-panel.tsx
@@ -247,7 +247,7 @@ export function SourceConfigPanel({ source, onUpdate }: SourceConfigPanelProps)
)}
{/* Always-on sources */}
- {source.alwaysEnabled && source.id !== "aelis.location" && (
+ {source.alwaysEnabled && source.id !== "freya.location" && (
<>
@@ -256,7 +256,7 @@ export function SourceConfigPanel({ source, onUpdate }: SourceConfigPanelProps)
>
)}
- {source.id === "aelis.location" && }
+ {source.id === "freya.location" && }
)
}
diff --git a/apps/admin-dashboard/src/lib/api.ts b/apps/admin-dashboard/src/lib/api.ts
index fd57a2c..00773ea 100644
--- a/apps/admin-dashboard/src/lib/api.ts
+++ b/apps/admin-dashboard/src/lib/api.ts
@@ -36,14 +36,14 @@ export interface SourceConfig {
const sourceDefinitions: SourceDefinition[] = [
{
- id: "aelis.location",
+ id: "freya.location",
name: "Location",
description: "Device location provider. Always enabled as a dependency for other sources.",
alwaysEnabled: true,
fields: {},
},
{
- id: "aelis.weather",
+ id: "freya.weather",
name: "WeatherKit",
description: "Apple WeatherKit weather data. Requires Apple Developer credentials.",
fields: {
@@ -81,7 +81,7 @@ const sourceDefinitions: SourceDefinition[] = [
},
},
{
- id: "aelis.caldav",
+ id: "freya.caldav",
name: "CalDAV",
description: "Calendar events from any CalDAV server (Nextcloud, Radicale, Baikal, etc.).",
perUserCredentials: true,
@@ -119,7 +119,7 @@ const sourceDefinitions: SourceDefinition[] = [
},
},
{
- id: "aelis.tfl",
+ id: "freya.tfl",
name: "TfL",
description: "Transport for London tube line status alerts.",
fields: {
diff --git a/apps/admin-dashboard/src/lib/server-url.ts b/apps/admin-dashboard/src/lib/server-url.ts
index 606f594..c6b26c6 100644
--- a/apps/admin-dashboard/src/lib/server-url.ts
+++ b/apps/admin-dashboard/src/lib/server-url.ts
@@ -1,4 +1,4 @@
-const STORAGE_KEY = "aelis-server-url"
+const STORAGE_KEY = "freya-server-url"
const DEFAULT_URL = "https://3000--019cf276-6ed6-7529-a425-210182693908.eu-runner.flex.doptig.cloud"
export function getServerUrl(): string {
diff --git a/apps/admin-dashboard/src/routes/_dashboard.tsx b/apps/admin-dashboard/src/routes/_dashboard.tsx
index 4e695fb..91ff173 100644
--- a/apps/admin-dashboard/src/routes/_dashboard.tsx
+++ b/apps/admin-dashboard/src/routes/_dashboard.tsx
@@ -45,11 +45,11 @@ import { getSession, signOut } from "@/lib/auth"
import { Route as rootRoute } from "./__root"
const SOURCE_ICONS: Record> = {
- "aelis.location": MapPin,
- "aelis.weather": CloudSun,
- "aelis.caldav": CalendarDays,
- "aelis.google-calendar": Calendar,
- "aelis.tfl": TrainFront,
+ "freya.location": MapPin,
+ "freya.weather": CloudSun,
+ "freya.caldav": CalendarDays,
+ "freya.google-calendar": Calendar,
+ "freya.tfl": TrainFront,
}
export const Route = createRoute({
diff --git a/apps/aelis-backend/.env.example b/apps/freya-backend/.env.example
similarity index 100%
rename from apps/aelis-backend/.env.example
rename to apps/freya-backend/.env.example
diff --git a/apps/aelis-backend/auth.ts b/apps/freya-backend/auth.ts
similarity index 100%
rename from apps/aelis-backend/auth.ts
rename to apps/freya-backend/auth.ts
diff --git a/apps/aelis-backend/drizzle.config.ts b/apps/freya-backend/drizzle.config.ts
similarity index 100%
rename from apps/aelis-backend/drizzle.config.ts
rename to apps/freya-backend/drizzle.config.ts
diff --git a/apps/aelis-backend/drizzle/0000_wakeful_scorpion.sql b/apps/freya-backend/drizzle/0000_wakeful_scorpion.sql
similarity index 100%
rename from apps/aelis-backend/drizzle/0000_wakeful_scorpion.sql
rename to apps/freya-backend/drizzle/0000_wakeful_scorpion.sql
diff --git a/apps/aelis-backend/drizzle/0001_misty_white_tiger.sql b/apps/freya-backend/drizzle/0001_misty_white_tiger.sql
similarity index 100%
rename from apps/aelis-backend/drizzle/0001_misty_white_tiger.sql
rename to apps/freya-backend/drizzle/0001_misty_white_tiger.sql
diff --git a/apps/aelis-backend/drizzle/meta/0000_snapshot.json b/apps/freya-backend/drizzle/meta/0000_snapshot.json
similarity index 100%
rename from apps/aelis-backend/drizzle/meta/0000_snapshot.json
rename to apps/freya-backend/drizzle/meta/0000_snapshot.json
diff --git a/apps/aelis-backend/drizzle/meta/0001_snapshot.json b/apps/freya-backend/drizzle/meta/0001_snapshot.json
similarity index 100%
rename from apps/aelis-backend/drizzle/meta/0001_snapshot.json
rename to apps/freya-backend/drizzle/meta/0001_snapshot.json
diff --git a/apps/aelis-backend/drizzle/meta/_journal.json b/apps/freya-backend/drizzle/meta/_journal.json
similarity index 100%
rename from apps/aelis-backend/drizzle/meta/_journal.json
rename to apps/freya-backend/drizzle/meta/_journal.json
diff --git a/apps/aelis-backend/package.json b/apps/freya-backend/package.json
similarity index 74%
rename from apps/aelis-backend/package.json
rename to apps/freya-backend/package.json
index 59a6d18..23b86e1 100644
--- a/apps/aelis-backend/package.json
+++ b/apps/freya-backend/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/backend",
+ "name": "@freya/backend",
"version": "0.0.0",
"type": "module",
"main": "src/server.ts",
@@ -15,12 +15,12 @@
"create-admin": "bun run src/scripts/create-admin.ts"
},
"dependencies": {
- "@aelis/core": "workspace:*",
- "@aelis/source-caldav": "workspace:*",
- "@aelis/source-google-calendar": "workspace:*",
- "@aelis/source-location": "workspace:*",
- "@aelis/source-tfl": "workspace:*",
- "@aelis/source-weatherkit": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-caldav": "workspace:*",
+ "@freya/source-google-calendar": "workspace:*",
+ "@freya/source-location": "workspace:*",
+ "@freya/source-tfl": "workspace:*",
+ "@freya/source-weatherkit": "workspace:*",
"@openrouter/sdk": "^0.9.11",
"arktype": "^2.1.29",
"better-auth": "^1",
diff --git a/apps/aelis-backend/src/admin/http.test.ts b/apps/freya-backend/src/admin/http.test.ts
similarity index 85%
rename from apps/aelis-backend/src/admin/http.test.ts
rename to apps/freya-backend/src/admin/http.test.ts
index ed73986..c56a272 100644
--- a/apps/aelis-backend/src/admin/http.test.ts
+++ b/apps/freya-backend/src/admin/http.test.ts
@@ -1,4 +1,4 @@
-import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@freya/core"
import { describe, expect, mock, test } from "bun:test"
import { Hono } from "hono"
@@ -118,9 +118,9 @@ const validWeatherConfig = {
describe("PUT /api/admin/:sourceId/config", () => {
test("returns 404 for unknown provider", async () => {
- const { app } = createApp([createStubProvider("aelis.location")])
+ const { app } = createApp([createStubProvider("freya.location")])
- const res = await app.request("/api/admin/aelis.nonexistent/config", {
+ const res = await app.request("/api/admin/freya.nonexistent/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ key: "value" }),
@@ -132,9 +132,9 @@ describe("PUT /api/admin/:sourceId/config", () => {
})
test("returns 404 for provider without runtime config support", async () => {
- const { app } = createApp([createStubProvider("aelis.location")])
+ const { app } = createApp([createStubProvider("freya.location")])
- const res = await app.request("/api/admin/aelis.location/config", {
+ const res = await app.request("/api/admin/freya.location/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ key: "value" }),
@@ -146,9 +146,9 @@ describe("PUT /api/admin/:sourceId/config", () => {
})
test("returns 400 for invalid JSON body", async () => {
- const { app } = createApp([createStubProvider("aelis.weather")])
+ const { app } = createApp([createStubProvider("freya.weather")])
- const res = await app.request("/api/admin/aelis.weather/config", {
+ const res = await app.request("/api/admin/freya.weather/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: "not json",
@@ -160,9 +160,9 @@ describe("PUT /api/admin/:sourceId/config", () => {
})
test("returns 400 when weather config fails validation", async () => {
- const { app } = createApp([createStubProvider("aelis.weather")])
+ const { app } = createApp([createStubProvider("freya.weather")])
- const res = await app.request("/api/admin/aelis.weather/config", {
+ const res = await app.request("/api/admin/freya.weather/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ credentials: { privateKey: 123 } }),
@@ -174,11 +174,11 @@ describe("PUT /api/admin/:sourceId/config", () => {
})
test("returns 204 and applies valid weather config", async () => {
- const { app, sessionManager } = createApp([createStubProvider("aelis.weather")])
+ const { app, sessionManager } = createApp([createStubProvider("freya.weather")])
- const originalProvider = sessionManager.getProvider("aelis.weather")
+ const originalProvider = sessionManager.getProvider("freya.weather")
- const res = await app.request("/api/admin/aelis.weather/config", {
+ const res = await app.request("/api/admin/freya.weather/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(validWeatherConfig),
@@ -187,9 +187,9 @@ describe("PUT /api/admin/:sourceId/config", () => {
expect(res.status).toBe(204)
// Provider was replaced with a new instance
- const provider = sessionManager.getProvider("aelis.weather")
+ const provider = sessionManager.getProvider("freya.weather")
expect(provider).toBeDefined()
- expect(provider!.sourceId).toBe("aelis.weather")
+ expect(provider!.sourceId).toBe("freya.weather")
expect(provider).not.toBe(originalProvider)
})
})
diff --git a/apps/aelis-backend/src/admin/http.ts b/apps/freya-backend/src/admin/http.ts
similarity index 98%
rename from apps/aelis-backend/src/admin/http.ts
rename to apps/freya-backend/src/admin/http.ts
index 4ad3e0e..3dfc78a 100644
--- a/apps/aelis-backend/src/admin/http.ts
+++ b/apps/freya-backend/src/admin/http.ts
@@ -60,7 +60,7 @@ async function handleUpdateProviderConfig(c: Context) {
}
switch (sourceId) {
- case "aelis.weather": {
+ case "freya.weather": {
const parsed = WeatherKitSourceProviderConfig(body)
if (parsed instanceof type.errors) {
return c.json({ error: parsed.summary }, 400)
diff --git a/apps/aelis-backend/src/auth/admin-middleware.test.ts b/apps/freya-backend/src/auth/admin-middleware.test.ts
similarity index 100%
rename from apps/aelis-backend/src/auth/admin-middleware.test.ts
rename to apps/freya-backend/src/auth/admin-middleware.test.ts
diff --git a/apps/aelis-backend/src/auth/admin-middleware.ts b/apps/freya-backend/src/auth/admin-middleware.ts
similarity index 100%
rename from apps/aelis-backend/src/auth/admin-middleware.ts
rename to apps/freya-backend/src/auth/admin-middleware.ts
diff --git a/apps/aelis-backend/src/auth/http.ts b/apps/freya-backend/src/auth/http.ts
similarity index 100%
rename from apps/aelis-backend/src/auth/http.ts
rename to apps/freya-backend/src/auth/http.ts
diff --git a/apps/aelis-backend/src/auth/index.ts b/apps/freya-backend/src/auth/index.ts
similarity index 100%
rename from apps/aelis-backend/src/auth/index.ts
rename to apps/freya-backend/src/auth/index.ts
diff --git a/apps/aelis-backend/src/auth/session-middleware.ts b/apps/freya-backend/src/auth/session-middleware.ts
similarity index 98%
rename from apps/aelis-backend/src/auth/session-middleware.ts
rename to apps/freya-backend/src/auth/session-middleware.ts
index c681d45..a0475b7 100644
--- a/apps/aelis-backend/src/auth/session-middleware.ts
+++ b/apps/freya-backend/src/auth/session-middleware.ts
@@ -79,7 +79,7 @@ export function mockAuthSessionMiddleware(userId?: string): AuthSessionMiddlewar
const user: AuthUser = {
id: "k7Gx2mPqRvNwYs9TdLfA4bHcJeUo1iZn",
name: "Dev User",
- email: "dev@aelis.local",
+ email: "dev@freya.local",
emailVerified: true,
image: null,
createdAt: now,
@@ -96,7 +96,7 @@ export function mockAuthSessionMiddleware(userId?: string): AuthSessionMiddlewar
token: "Vb9CxNfRm2KwQs7TjPeA5dLhYg0UoZi4",
expiresAt,
ipAddress: "127.0.0.1",
- userAgent: "aelis-dev",
+ userAgent: "freya-dev",
createdAt: now,
updatedAt: now,
}
diff --git a/apps/aelis-backend/src/auth/session.ts b/apps/freya-backend/src/auth/session.ts
similarity index 100%
rename from apps/aelis-backend/src/auth/session.ts
rename to apps/freya-backend/src/auth/session.ts
diff --git a/apps/aelis-backend/src/caldav/provider.test.ts b/apps/freya-backend/src/caldav/provider.test.ts
similarity index 94%
rename from apps/aelis-backend/src/caldav/provider.test.ts
rename to apps/freya-backend/src/caldav/provider.test.ts
index 0c3891a..d3a11db 100644
--- a/apps/aelis-backend/src/caldav/provider.test.ts
+++ b/apps/freya-backend/src/caldav/provider.test.ts
@@ -5,8 +5,8 @@ import { CalDavSourceProvider } from "./provider.ts"
describe("CalDavSourceProvider", () => {
const provider = new CalDavSourceProvider()
- test("sourceId is aelis.caldav", () => {
- expect(provider.sourceId).toBe("aelis.caldav")
+ test("sourceId is freya.caldav", () => {
+ expect(provider.sourceId).toBe("freya.caldav")
})
test("throws when credentials are null", async () => {
@@ -68,7 +68,7 @@ describe("CalDavSourceProvider", () => {
const source = await provider.feedSourceForUser("user-1", config, credentials)
expect(source).toBeDefined()
- expect(source.id).toBe("aelis.caldav")
+ expect(source.id).toBe("freya.caldav")
})
test("returns CalDavSource with minimal config", async () => {
@@ -80,6 +80,6 @@ describe("CalDavSourceProvider", () => {
const source = await provider.feedSourceForUser("user-1", config, credentials)
expect(source).toBeDefined()
- expect(source.id).toBe("aelis.caldav")
+ expect(source.id).toBe("freya.caldav")
})
})
diff --git a/apps/aelis-backend/src/caldav/provider.ts b/apps/freya-backend/src/caldav/provider.ts
similarity index 84%
rename from apps/aelis-backend/src/caldav/provider.ts
rename to apps/freya-backend/src/caldav/provider.ts
index 5ad5195..daa0747 100644
--- a/apps/aelis-backend/src/caldav/provider.ts
+++ b/apps/freya-backend/src/caldav/provider.ts
@@ -1,4 +1,4 @@
-import { CalDavSource } from "@aelis/source-caldav"
+import { CalDavSource } from "@freya/source-caldav"
import { type } from "arktype"
import type { FeedSourceProvider } from "../session/feed-source-provider.ts"
@@ -19,7 +19,7 @@ const caldavCredentials = type({
})
export class CalDavSourceProvider implements FeedSourceProvider {
- readonly sourceId = "aelis.caldav"
+ readonly sourceId = "freya.caldav"
readonly configSchema = caldavConfig
async feedSourceForUser(
@@ -33,12 +33,12 @@ export class CalDavSourceProvider implements FeedSourceProvider {
}
if (!credentials) {
- throw new InvalidSourceCredentialsError("aelis.caldav", "No CalDAV credentials configured")
+ throw new InvalidSourceCredentialsError("freya.caldav", "No CalDAV credentials configured")
}
const creds = caldavCredentials(credentials)
if (creds instanceof type.errors) {
- throw new InvalidSourceCredentialsError("aelis.caldav", creds.summary)
+ throw new InvalidSourceCredentialsError("freya.caldav", creds.summary)
}
return new CalDavSource({
diff --git a/apps/aelis-backend/src/db/auth-schema.ts b/apps/freya-backend/src/db/auth-schema.ts
similarity index 100%
rename from apps/aelis-backend/src/db/auth-schema.ts
rename to apps/freya-backend/src/db/auth-schema.ts
diff --git a/apps/aelis-backend/src/db/index.ts b/apps/freya-backend/src/db/index.ts
similarity index 100%
rename from apps/aelis-backend/src/db/index.ts
rename to apps/freya-backend/src/db/index.ts
diff --git a/apps/aelis-backend/src/db/schema.ts b/apps/freya-backend/src/db/schema.ts
similarity index 97%
rename from apps/aelis-backend/src/db/schema.ts
rename to apps/freya-backend/src/db/schema.ts
index 0b08a8e..41130ac 100644
--- a/apps/aelis-backend/src/db/schema.ts
+++ b/apps/freya-backend/src/db/schema.ts
@@ -29,7 +29,7 @@ export {
import { user } from "./auth-schema.ts"
// ---------------------------------------------------------------------------
-// AELIS — per-user source configuration
+// FREYA — per-user source configuration
// ---------------------------------------------------------------------------
const bytea = customType<{ data: Buffer }>({
diff --git a/apps/aelis-backend/src/engine/http.test.ts b/apps/freya-backend/src/engine/http.test.ts
similarity index 94%
rename from apps/aelis-backend/src/engine/http.test.ts
rename to apps/freya-backend/src/engine/http.test.ts
index 14c4a39..4bcdc9b 100644
--- a/apps/aelis-backend/src/engine/http.test.ts
+++ b/apps/freya-backend/src/engine/http.test.ts
@@ -1,6 +1,6 @@
-import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@freya/core"
-import { contextKey } from "@aelis/core"
+import { contextKey } from "@freya/core"
import { describe, expect, mock, spyOn, test } from "bun:test"
import { Hono } from "hono"
@@ -244,7 +244,7 @@ describe("GET /api/feed", () => {
})
describe("GET /api/context", () => {
- const weatherKey = contextKey("aelis.weather", "weather")
+ const weatherKey = contextKey("freya.weather", "weather")
const weatherData = { temperature: 20, condition: "Clear" }
const contextEntries: readonly ContextEntry[] = [[weatherKey, weatherData]]
@@ -274,7 +274,7 @@ describe("GET /api/context", () => {
const manager = new UserSessionManager({ db: fakeDb, providers: [] })
const app = buildTestApp(manager)
- const res = await app.request('/api/context?key=["aelis.weather","weather"]')
+ const res = await app.request('/api/context?key=["freya.weather","weather"]')
expect(res.status).toBe(401)
})
@@ -332,7 +332,7 @@ describe("GET /api/context", () => {
test("returns 400 when match param is invalid", async () => {
const { app } = await buildContextApp("user-1")
- const res = await app.request('/api/context?key=["aelis.weather"]&match=invalid')
+ const res = await app.request('/api/context?key=["freya.weather"]&match=invalid')
expect(res.status).toBe(400)
const body = (await res.json()) as { error: string }
@@ -343,7 +343,7 @@ describe("GET /api/context", () => {
const { app, session } = await buildContextApp("user-1")
await session.engine.refresh()
- const res = await app.request('/api/context?key=["aelis.weather","weather"]&match=exact')
+ const res = await app.request('/api/context?key=["freya.weather","weather"]&match=exact')
expect(res.status).toBe(200)
const body = (await res.json()) as { match: string; value: unknown }
@@ -355,7 +355,7 @@ describe("GET /api/context", () => {
const { app, session } = await buildContextApp("user-1")
await session.engine.refresh()
- const res = await app.request('/api/context?key=["aelis.weather"]&match=exact')
+ const res = await app.request('/api/context?key=["freya.weather"]&match=exact')
expect(res.status).toBe(404)
})
@@ -364,7 +364,7 @@ describe("GET /api/context", () => {
const { app, session } = await buildContextApp("user-1")
await session.engine.refresh()
- const res = await app.request('/api/context?key=["aelis.weather"]&match=prefix')
+ const res = await app.request('/api/context?key=["freya.weather"]&match=prefix')
expect(res.status).toBe(200)
const body = (await res.json()) as {
@@ -373,7 +373,7 @@ describe("GET /api/context", () => {
}
expect(body.match).toBe("prefix")
expect(body.entries).toHaveLength(1)
- expect(body.entries[0]!.key).toEqual(["aelis.weather", "weather"])
+ expect(body.entries[0]!.key).toEqual(["freya.weather", "weather"])
expect(body.entries[0]!.value).toEqual(weatherData)
})
@@ -381,7 +381,7 @@ describe("GET /api/context", () => {
const { app, session } = await buildContextApp("user-1")
await session.engine.refresh()
- const res = await app.request('/api/context?key=["aelis.weather","weather"]')
+ const res = await app.request('/api/context?key=["freya.weather","weather"]')
expect(res.status).toBe(200)
const body = (await res.json()) as { match: string; value: unknown }
@@ -393,7 +393,7 @@ describe("GET /api/context", () => {
const { app, session } = await buildContextApp("user-1")
await session.engine.refresh()
- const res = await app.request('/api/context?key=["aelis.weather"]')
+ const res = await app.request('/api/context?key=["freya.weather"]')
expect(res.status).toBe(200)
const body = (await res.json()) as {
diff --git a/apps/aelis-backend/src/engine/http.ts b/apps/freya-backend/src/engine/http.ts
similarity index 98%
rename from apps/aelis-backend/src/engine/http.ts
rename to apps/freya-backend/src/engine/http.ts
index 06702c2..6f9b94c 100644
--- a/apps/aelis-backend/src/engine/http.ts
+++ b/apps/freya-backend/src/engine/http.ts
@@ -1,6 +1,6 @@
import type { Context, Hono } from "hono"
-import { contextKey } from "@aelis/core"
+import { contextKey } from "@freya/core"
import { createMiddleware } from "hono/factory"
import type { AuthSessionMiddleware } from "../auth/session-middleware.ts"
diff --git a/apps/aelis-backend/src/enhancement/enhance-feed.ts b/apps/freya-backend/src/enhancement/enhance-feed.ts
similarity index 96%
rename from apps/aelis-backend/src/enhancement/enhance-feed.ts
rename to apps/freya-backend/src/enhancement/enhance-feed.ts
index cf82501..836a635 100644
--- a/apps/aelis-backend/src/enhancement/enhance-feed.ts
+++ b/apps/freya-backend/src/enhancement/enhance-feed.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import type { LlmClient } from "./llm-client.ts"
diff --git a/apps/aelis-backend/src/enhancement/llm-client.ts b/apps/freya-backend/src/enhancement/llm-client.ts
similarity index 100%
rename from apps/aelis-backend/src/enhancement/llm-client.ts
rename to apps/freya-backend/src/enhancement/llm-client.ts
diff --git a/apps/aelis-backend/src/enhancement/merge.test.ts b/apps/freya-backend/src/enhancement/merge.test.ts
similarity index 98%
rename from apps/aelis-backend/src/enhancement/merge.test.ts
rename to apps/freya-backend/src/enhancement/merge.test.ts
index 8fca1c7..d479fb9 100644
--- a/apps/aelis-backend/src/enhancement/merge.test.ts
+++ b/apps/freya-backend/src/enhancement/merge.test.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import { describe, expect, test } from "bun:test"
diff --git a/apps/aelis-backend/src/enhancement/merge.ts b/apps/freya-backend/src/enhancement/merge.ts
similarity index 92%
rename from apps/aelis-backend/src/enhancement/merge.ts
rename to apps/freya-backend/src/enhancement/merge.ts
index 600f5ba..9f2584f 100644
--- a/apps/aelis-backend/src/enhancement/merge.ts
+++ b/apps/freya-backend/src/enhancement/merge.ts
@@ -1,8 +1,8 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import type { EnhancementResult } from "./schema.ts"
-const ENHANCEMENT_SOURCE_ID = "aelis.enhancement"
+const ENHANCEMENT_SOURCE_ID = "freya.enhancement"
/**
* Merges an EnhancementResult into feed items.
diff --git a/apps/aelis-backend/src/enhancement/prompt-builder.test.ts b/apps/freya-backend/src/enhancement/prompt-builder.test.ts
similarity index 99%
rename from apps/aelis-backend/src/enhancement/prompt-builder.test.ts
rename to apps/freya-backend/src/enhancement/prompt-builder.test.ts
index f066771..f1e8790 100644
--- a/apps/aelis-backend/src/enhancement/prompt-builder.test.ts
+++ b/apps/freya-backend/src/enhancement/prompt-builder.test.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import { describe, expect, test } from "bun:test"
diff --git a/apps/aelis-backend/src/enhancement/prompt-builder.ts b/apps/freya-backend/src/enhancement/prompt-builder.ts
similarity index 97%
rename from apps/aelis-backend/src/enhancement/prompt-builder.ts
rename to apps/freya-backend/src/enhancement/prompt-builder.ts
index 376b701..e31c427 100644
--- a/apps/aelis-backend/src/enhancement/prompt-builder.ts
+++ b/apps/freya-backend/src/enhancement/prompt-builder.ts
@@ -1,7 +1,7 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
-import { CalDavFeedItemType } from "@aelis/source-caldav"
-import { CalendarFeedItemType } from "@aelis/source-google-calendar"
+import { CalDavFeedItemType } from "@freya/source-caldav"
+import { CalendarFeedItemType } from "@freya/source-google-calendar"
import systemPromptBase from "./prompts/system.txt"
diff --git a/apps/aelis-backend/src/enhancement/prompts/system.txt b/apps/freya-backend/src/enhancement/prompts/system.txt
similarity index 95%
rename from apps/aelis-backend/src/enhancement/prompts/system.txt
rename to apps/freya-backend/src/enhancement/prompts/system.txt
index 70d247f..d3e6cb0 100644
--- a/apps/aelis-backend/src/enhancement/prompts/system.txt
+++ b/apps/freya-backend/src/enhancement/prompts/system.txt
@@ -1,4 +1,4 @@
-You are AELIS, a personal assistant. You enhance a user's feed by filling slots and optionally generating synthetic items.
+You are FREYA, a personal assistant. You enhance a user's feed by filling slots and optionally generating synthetic items.
The user message is a JSON object with:
- "items": feed items with data and named slots to fill. Each slot has a description of what to write.
diff --git a/apps/aelis-backend/src/enhancement/schema.test.ts b/apps/freya-backend/src/enhancement/schema.test.ts
similarity index 100%
rename from apps/aelis-backend/src/enhancement/schema.test.ts
rename to apps/freya-backend/src/enhancement/schema.test.ts
diff --git a/apps/aelis-backend/src/enhancement/schema.ts b/apps/freya-backend/src/enhancement/schema.ts
similarity index 100%
rename from apps/aelis-backend/src/enhancement/schema.ts
rename to apps/freya-backend/src/enhancement/schema.ts
diff --git a/apps/aelis-backend/src/lib/crypto.test.ts b/apps/freya-backend/src/lib/crypto.test.ts
similarity index 100%
rename from apps/aelis-backend/src/lib/crypto.test.ts
rename to apps/freya-backend/src/lib/crypto.test.ts
diff --git a/apps/aelis-backend/src/lib/crypto.ts b/apps/freya-backend/src/lib/crypto.ts
similarity index 100%
rename from apps/aelis-backend/src/lib/crypto.ts
rename to apps/freya-backend/src/lib/crypto.ts
diff --git a/apps/aelis-backend/src/lib/error.ts b/apps/freya-backend/src/lib/error.ts
similarity index 100%
rename from apps/aelis-backend/src/lib/error.ts
rename to apps/freya-backend/src/lib/error.ts
diff --git a/apps/aelis-backend/src/location/http.ts b/apps/freya-backend/src/location/http.ts
similarity index 96%
rename from apps/aelis-backend/src/location/http.ts
rename to apps/freya-backend/src/location/http.ts
index 6223031..d62e872 100644
--- a/apps/aelis-backend/src/location/http.ts
+++ b/apps/freya-backend/src/location/http.ts
@@ -57,7 +57,7 @@ async function handleUpdateLocation(c: Context) {
return c.json({ error: "Service unavailable" }, 503)
}
- await session.engine.executeAction("aelis.location", "update-location", {
+ await session.engine.executeAction("freya.location", "update-location", {
lat: result.lat,
lng: result.lng,
accuracy: result.accuracy,
diff --git a/apps/aelis-backend/src/location/provider.ts b/apps/freya-backend/src/location/provider.ts
similarity index 76%
rename from apps/aelis-backend/src/location/provider.ts
rename to apps/freya-backend/src/location/provider.ts
index 18e56b9..5a8fe6d 100644
--- a/apps/aelis-backend/src/location/provider.ts
+++ b/apps/freya-backend/src/location/provider.ts
@@ -1,9 +1,9 @@
-import { LocationSource } from "@aelis/source-location"
+import { LocationSource } from "@freya/source-location"
import type { FeedSourceProvider } from "../session/feed-source-provider.ts"
export class LocationSourceProvider implements FeedSourceProvider {
- readonly sourceId = "aelis.location"
+ readonly sourceId = "freya.location"
async feedSourceForUser(
_userId: string,
diff --git a/apps/aelis-backend/src/scripts/create-admin.ts b/apps/freya-backend/src/scripts/create-admin.ts
similarity index 100%
rename from apps/aelis-backend/src/scripts/create-admin.ts
rename to apps/freya-backend/src/scripts/create-admin.ts
diff --git a/apps/aelis-backend/src/server.ts b/apps/freya-backend/src/server.ts
similarity index 100%
rename from apps/aelis-backend/src/server.ts
rename to apps/freya-backend/src/server.ts
diff --git a/apps/aelis-backend/src/session/feed-source-provider.ts b/apps/freya-backend/src/session/feed-source-provider.ts
similarity index 75%
rename from apps/aelis-backend/src/session/feed-source-provider.ts
rename to apps/freya-backend/src/session/feed-source-provider.ts
index f3a587b..da1d95b 100644
--- a/apps/aelis-backend/src/session/feed-source-provider.ts
+++ b/apps/freya-backend/src/session/feed-source-provider.ts
@@ -1,10 +1,10 @@
-import type { FeedSource } from "@aelis/core"
+import type { FeedSource } from "@freya/core"
import type { type } from "arktype"
export type ConfigSchema = ReturnType
export interface FeedSourceProvider {
- /** The source ID this provider is responsible for (e.g., "aelis.location"). */
+ /** The source ID this provider is responsible for (e.g., "freya.location"). */
readonly sourceId: string
/** Arktype schema for validating user-provided config. Omit if the source has no config. */
readonly configSchema?: ConfigSchema
diff --git a/apps/aelis-backend/src/session/index.ts b/apps/freya-backend/src/session/index.ts
similarity index 100%
rename from apps/aelis-backend/src/session/index.ts
rename to apps/freya-backend/src/session/index.ts
diff --git a/apps/aelis-backend/src/session/user-session-manager.test.ts b/apps/freya-backend/src/session/user-session-manager.test.ts
similarity index 90%
rename from apps/aelis-backend/src/session/user-session-manager.test.ts
rename to apps/freya-backend/src/session/user-session-manager.test.ts
index 781dc9f..faad31d 100644
--- a/apps/aelis-backend/src/session/user-session-manager.test.ts
+++ b/apps/freya-backend/src/session/user-session-manager.test.ts
@@ -1,7 +1,7 @@
-import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@freya/core"
-import { LocationSource } from "@aelis/source-location"
-import { WeatherSource } from "@aelis/source-weatherkit"
+import { LocationSource } from "@freya/source-location"
+import { WeatherSource } from "@freya/source-weatherkit"
import { beforeEach, describe, expect, mock, spyOn, test } from "bun:test"
import type { Database } from "../db/index.ts"
@@ -145,14 +145,14 @@ function createStubProvider(
}
const locationProvider: FeedSourceProvider = {
- sourceId: "aelis.location",
+ sourceId: "freya.location",
async feedSourceForUser() {
return new LocationSource()
},
}
const weatherProvider: FeedSourceProvider = {
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
async feedSourceForUser() {
return new WeatherSource({ client: { fetch: async () => ({}) as never } })
},
@@ -167,7 +167,7 @@ beforeEach(() => {
describe("UserSessionManager", () => {
test("getOrCreate creates session on first call", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session = await manager.getOrCreate("user-1")
@@ -177,7 +177,7 @@ describe("UserSessionManager", () => {
})
test("getOrCreate returns same session for same user", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session1 = await manager.getOrCreate("user-1")
@@ -187,7 +187,7 @@ describe("UserSessionManager", () => {
})
test("getOrCreate returns different sessions for different users", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session1 = await manager.getOrCreate("user-1")
@@ -197,20 +197,20 @@ describe("UserSessionManager", () => {
})
test("each user gets independent source instances", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session1 = await manager.getOrCreate("user-1")
const session2 = await manager.getOrCreate("user-2")
- const source1 = session1.getSource("aelis.location")
- const source2 = session2.getSource("aelis.location")
+ const source1 = session1.getSource("freya.location")
+ const source2 = session2.getSource("freya.location")
expect(source1).not.toBe(source2)
})
test("remove destroys session and allows re-creation", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session1 = await manager.getOrCreate("user-1")
@@ -221,14 +221,14 @@ describe("UserSessionManager", () => {
})
test("remove is no-op for unknown user", () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
expect(() => manager.remove("unknown")).not.toThrow()
})
test("registers multiple providers", async () => {
- setEnabledSources(["aelis.location", "aelis.weather"])
+ setEnabledSources(["freya.location", "freya.weather"])
const manager = new UserSessionManager({
db: fakeDb,
providers: [locationProvider, weatherProvider],
@@ -236,12 +236,12 @@ describe("UserSessionManager", () => {
const session = await manager.getOrCreate("user-1")
- expect(session.getSource("aelis.location")).toBeDefined()
- expect(session.getSource("aelis.weather")).toBeDefined()
+ expect(session.getSource("freya.location")).toBeDefined()
+ expect(session.getSource("freya.weather")).toBeDefined()
})
test("refresh returns feed result through session", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session = await manager.getOrCreate("user-1")
@@ -254,30 +254,30 @@ describe("UserSessionManager", () => {
})
test("location update via executeAction works", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const session = await manager.getOrCreate("user-1")
- await session.engine.executeAction("aelis.location", "update-location", {
+ await session.engine.executeAction("freya.location", "update-location", {
lat: 51.5074,
lng: -0.1278,
accuracy: 10,
timestamp: new Date(),
})
- const source = session.getSource("aelis.location")
+ const source = session.getSource("freya.location")
expect(source?.lastLocation?.lat).toBe(51.5074)
})
test("subscribe receives updates after location push", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const callback = mock()
const session = await manager.getOrCreate("user-1")
session.engine.subscribe(callback)
- await session.engine.executeAction("aelis.location", "update-location", {
+ await session.engine.executeAction("freya.location", "update-location", {
lat: 51.5074,
lng: -0.1278,
accuracy: 10,
@@ -291,7 +291,7 @@ describe("UserSessionManager", () => {
})
test("remove stops reactive updates", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
const callback = mock()
@@ -302,7 +302,7 @@ describe("UserSessionManager", () => {
// Create new session and push location — old callback should not fire
const session2 = await manager.getOrCreate("user-1")
- await session2.engine.executeAction("aelis.location", "update-location", {
+ await session2.engine.executeAction("freya.location", "update-location", {
lat: 51.5074,
lng: -0.1278,
accuracy: 10,
@@ -315,9 +315,9 @@ describe("UserSessionManager", () => {
})
test("creates session with successful providers when some fail", async () => {
- setEnabledSources(["aelis.location", "aelis.failing"])
+ setEnabledSources(["freya.location", "freya.failing"])
const failingProvider: FeedSourceProvider = {
- sourceId: "aelis.failing",
+ sourceId: "freya.failing",
async feedSourceForUser() {
throw new Error("provider failed")
},
@@ -333,25 +333,25 @@ describe("UserSessionManager", () => {
const session = await manager.getOrCreate("user-1")
expect(session).toBeDefined()
- expect(session.getSource("aelis.location")).toBeDefined()
+ expect(session.getSource("freya.location")).toBeDefined()
expect(spy).toHaveBeenCalled()
spy.mockRestore()
})
test("throws AggregateError when all providers fail", async () => {
- setEnabledSources(["aelis.fail-1", "aelis.fail-2"])
+ setEnabledSources(["freya.fail-1", "freya.fail-2"])
const manager = new UserSessionManager({
db: fakeDb,
providers: [
{
- sourceId: "aelis.fail-1",
+ sourceId: "freya.fail-1",
async feedSourceForUser() {
throw new Error("first failed")
},
},
{
- sourceId: "aelis.fail-2",
+ sourceId: "freya.fail-2",
async feedSourceForUser() {
throw new Error("second failed")
},
@@ -363,13 +363,13 @@ describe("UserSessionManager", () => {
})
test("concurrent getOrCreate for same user returns same session", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
let callCount = 0
const manager = new UserSessionManager({
db: fakeDb,
providers: [
{
- sourceId: "aelis.location",
+ sourceId: "freya.location",
async feedSourceForUser() {
callCount++
await new Promise((resolve) => setTimeout(resolve, 10))
@@ -389,7 +389,7 @@ describe("UserSessionManager", () => {
})
test("remove during in-flight getOrCreate prevents session from being stored", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
let resolveProvider: () => void
const providerGate = new Promise((r) => {
resolveProvider = r
@@ -399,7 +399,7 @@ describe("UserSessionManager", () => {
db: fakeDb,
providers: [
{
- sourceId: "aelis.location",
+ sourceId: "freya.location",
async feedSourceForUser() {
await providerGate
return new LocationSource()
@@ -425,15 +425,15 @@ describe("UserSessionManager", () => {
})
test("only invokes providers for sources enabled for the user", async () => {
- setEnabledSources(["aelis.location"])
- const locationFactory = mock(async () => createStubSource("aelis.location"))
- const weatherFactory = mock(async () => createStubSource("aelis.weather"))
+ setEnabledSources(["freya.location"])
+ const locationFactory = mock(async () => createStubSource("freya.location"))
+ const weatherFactory = mock(async () => createStubSource("freya.weather"))
const manager = new UserSessionManager({
db: fakeDb,
providers: [
- { sourceId: "aelis.location", feedSourceForUser: locationFactory },
- { sourceId: "aelis.weather", feedSourceForUser: weatherFactory },
+ { sourceId: "freya.location", feedSourceForUser: locationFactory },
+ { sourceId: "freya.weather", feedSourceForUser: weatherFactory },
],
})
@@ -441,43 +441,43 @@ describe("UserSessionManager", () => {
expect(locationFactory).toHaveBeenCalledTimes(1)
expect(weatherFactory).not.toHaveBeenCalled()
- expect(session.getSource("aelis.location")).toBeDefined()
- expect(session.getSource("aelis.weather")).toBeUndefined()
+ expect(session.getSource("freya.location")).toBeDefined()
+ expect(session.getSource("freya.weather")).toBeUndefined()
})
test("creates empty session when no sources are enabled", async () => {
setEnabledSources([])
- const factory = mock(async () => createStubSource("aelis.location"))
+ const factory = mock(async () => createStubSource("freya.location"))
const manager = new UserSessionManager({
db: fakeDb,
- providers: [{ sourceId: "aelis.location", feedSourceForUser: factory }],
+ providers: [{ sourceId: "freya.location", feedSourceForUser: factory }],
})
const session = await manager.getOrCreate("user-1")
expect(factory).not.toHaveBeenCalled()
expect(session).toBeDefined()
- expect(session.getSource("aelis.location")).toBeUndefined()
+ expect(session.getSource("freya.location")).toBeUndefined()
})
test("per-user enabled sources are respected", async () => {
enabledByUser.clear()
- setEnabledSourcesForUser("user-1", ["aelis.location"])
- setEnabledSourcesForUser("user-2", ["aelis.weather"])
+ setEnabledSourcesForUser("user-1", ["freya.location"])
+ setEnabledSourcesForUser("user-2", ["freya.weather"])
const manager = new UserSessionManager({
db: fakeDb,
- providers: [createStubProvider("aelis.location"), createStubProvider("aelis.weather")],
+ providers: [createStubProvider("freya.location"), createStubProvider("freya.weather")],
})
const session1 = await manager.getOrCreate("user-1")
const session2 = await manager.getOrCreate("user-2")
- expect(session1.getSource("aelis.location")).toBeDefined()
- expect(session1.getSource("aelis.weather")).toBeUndefined()
- expect(session2.getSource("aelis.location")).toBeUndefined()
- expect(session2.getSource("aelis.weather")).toBeDefined()
+ expect(session1.getSource("freya.location")).toBeDefined()
+ expect(session1.getSource("freya.weather")).toBeUndefined()
+ expect(session2.getSource("freya.location")).toBeUndefined()
+ expect(session2.getSource("freya.weather")).toBeDefined()
})
})
@@ -525,10 +525,10 @@ describe("UserSessionManager.replaceProvider", () => {
})
test("throws for unknown provider sourceId", async () => {
- setEnabledSources(["aelis.location"])
+ setEnabledSources(["freya.location"])
const manager = new UserSessionManager({ db: fakeDb, providers: [locationProvider] })
- const unknownProvider = createStubProvider("aelis.unknown")
+ const unknownProvider = createStubProvider("freya.unknown")
await expect(manager.replaceProvider(unknownProvider)).rejects.toThrow(
"no existing provider with that sourceId",
diff --git a/apps/aelis-backend/src/session/user-session-manager.ts b/apps/freya-backend/src/session/user-session-manager.ts
similarity index 99%
rename from apps/aelis-backend/src/session/user-session-manager.ts
rename to apps/freya-backend/src/session/user-session-manager.ts
index bb7eb25..ab2f875 100644
--- a/apps/aelis-backend/src/session/user-session-manager.ts
+++ b/apps/freya-backend/src/session/user-session-manager.ts
@@ -1,4 +1,4 @@
-import type { FeedSource } from "@aelis/core"
+import type { FeedSource } from "@freya/core"
import { type } from "arktype"
import merge from "lodash.merge"
diff --git a/apps/aelis-backend/src/session/user-session.test.ts b/apps/freya-backend/src/session/user-session.test.ts
similarity index 98%
rename from apps/aelis-backend/src/session/user-session.test.ts
rename to apps/freya-backend/src/session/user-session.test.ts
index 2ec8967..e7a75a4 100644
--- a/apps/aelis-backend/src/session/user-session.test.ts
+++ b/apps/freya-backend/src/session/user-session.test.ts
@@ -1,6 +1,6 @@
-import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@freya/core"
-import { LocationSource } from "@aelis/source-location"
+import { LocationSource } from "@freya/source-location"
import { describe, expect, spyOn, test } from "bun:test"
import { UserSession } from "./user-session.ts"
@@ -39,7 +39,7 @@ describe("UserSession", () => {
const location = new LocationSource()
const session = new UserSession("test-user", [location])
- const result = session.getSource("aelis.location")
+ const result = session.getSource("freya.location")
expect(result).toBe(location)
})
@@ -62,7 +62,7 @@ describe("UserSession", () => {
const location = new LocationSource()
const session = new UserSession("test-user", [location])
- await session.engine.executeAction("aelis.location", "update-location", {
+ await session.engine.executeAction("freya.location", "update-location", {
lat: 51.5,
lng: -0.1,
accuracy: 10,
diff --git a/apps/aelis-backend/src/session/user-session.ts b/apps/freya-backend/src/session/user-session.ts
similarity index 99%
rename from apps/aelis-backend/src/session/user-session.ts
rename to apps/freya-backend/src/session/user-session.ts
index aa0d24e..7745609 100644
--- a/apps/aelis-backend/src/session/user-session.ts
+++ b/apps/freya-backend/src/session/user-session.ts
@@ -1,4 +1,4 @@
-import { FeedEngine, type FeedItem, type FeedResult, type FeedSource } from "@aelis/core"
+import { FeedEngine, type FeedItem, type FeedResult, type FeedSource } from "@freya/core"
import type { FeedEnhancer } from "../enhancement/enhance-feed.ts"
diff --git a/apps/aelis-backend/src/sources/errors.ts b/apps/freya-backend/src/sources/errors.ts
similarity index 100%
rename from apps/aelis-backend/src/sources/errors.ts
rename to apps/freya-backend/src/sources/errors.ts
diff --git a/apps/aelis-backend/src/sources/http.test.ts b/apps/freya-backend/src/sources/http.test.ts
similarity index 73%
rename from apps/aelis-backend/src/sources/http.test.ts
rename to apps/freya-backend/src/sources/http.test.ts
index 3e3a34d..8a856e9 100644
--- a/apps/aelis-backend/src/sources/http.test.ts
+++ b/apps/freya-backend/src/sources/http.test.ts
@@ -1,4 +1,4 @@
-import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItem, FeedSource } from "@freya/core"
import { describe, expect, mock, spyOn, test } from "bun:test"
import { Hono } from "hono"
@@ -193,16 +193,16 @@ function put(app: Hono, sourceId: string, body: unknown) {
describe("GET /api/sources/:sourceId", () => {
test("returns 401 without auth", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)])
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)])
- const res = await get(app, "aelis.weather")
+ const res = await get(app, "freya.weather")
expect(res.status).toBe(401)
})
test("returns 404 for unknown source", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
const res = await get(app, "unknown.source")
@@ -213,13 +213,13 @@ describe("GET /api/sources/:sourceId", () => {
test("returns enabled and config for existing source", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
enabled: true,
config: { units: "metric" },
})
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await get(app, "aelis.weather")
+ const res = await get(app, "freya.weather")
expect(res.status).toBe(200)
const body = (await res.json()) as { enabled: boolean; config: unknown }
@@ -229,9 +229,9 @@ describe("GET /api/sources/:sourceId", () => {
test("returns defaults when user has no row for source", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await get(app, "aelis.weather")
+ const res = await get(app, "freya.weather")
expect(res.status).toBe(200)
const body = (await res.json()) as { enabled: boolean; config: unknown }
@@ -241,13 +241,13 @@ describe("GET /api/sources/:sourceId", () => {
test("returns disabled source", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
enabled: false,
config: { units: "imperial" },
})
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await get(app, "aelis.weather")
+ const res = await get(app, "freya.weather")
expect(res.status).toBe(200)
const body = (await res.json()) as { enabled: boolean; config: unknown }
@@ -259,16 +259,16 @@ describe("GET /api/sources/:sourceId", () => {
describe("PATCH /api/sources/:sourceId", () => {
test("returns 401 without auth", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)])
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)])
- const res = await patch(app, "aelis.weather", { enabled: true })
+ const res = await patch(app, "freya.weather", { enabled: true })
expect(res.status).toBe(401)
})
test("returns 404 for unknown source", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
const res = await patch(app, "unknown.source", { enabled: true })
@@ -279,9 +279,9 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 404 when user has no existing row for source", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", { enabled: true })
+ const res = await patch(app, "freya.weather", { enabled: true })
expect(res.status).toBe(404)
const body = (await res.json()) as { error: string }
@@ -290,29 +290,29 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 204 when body is empty object (no-op) on existing source", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather")
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.weather")
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {})
+ const res = await patch(app, "freya.weather", {})
expect(res.status).toBe(204)
})
test("returns 404 when body is empty object on nonexistent user source", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {})
+ const res = await patch(app, "freya.weather", {})
expect(res.status).toBe(404)
})
test("returns 400 for invalid JSON body", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather")
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.weather")
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await app.request("/api/sources/aelis.weather", {
+ const res = await app.request("/api/sources/freya.weather", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: "not json",
@@ -325,10 +325,10 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 400 when request body contains unknown fields", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather")
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.weather")
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {
+ const res = await patch(app, "freya.weather", {
enabled: true,
unknownField: "hello",
})
@@ -338,10 +338,10 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 400 when weather config contains unknown fields", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather")
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.weather")
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {
+ const res = await patch(app, "freya.weather", {
config: { units: "metric", unknownField: "hello" },
})
@@ -350,10 +350,10 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 400 when weather config fails validation", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather")
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.weather")
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {
+ const res = await patch(app, "freya.weather", {
config: { units: "invalid" },
})
@@ -362,65 +362,65 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 204 and updates enabled", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
enabled: true,
config: { units: "metric" },
})
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", { enabled: false })
+ const res = await patch(app, "freya.weather", { enabled: false })
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.weather`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.weather`)
expect(row!.enabled).toBe(false)
expect(row!.config).toEqual({ units: "metric" })
})
test("returns 204 and updates config", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
config: { units: "metric" },
})
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {
+ const res = await patch(app, "freya.weather", {
config: { units: "imperial" },
})
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.weather`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.weather`)
expect(row!.config).toEqual({ units: "imperial" })
})
test("preserves config when only updating enabled", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.tfl", {
+ activeStore.seed(MOCK_USER_ID, "freya.tfl", {
enabled: true,
config: { lines: ["bakerloo"] },
})
- const { app } = createApp([createStubProvider("aelis.tfl", tflConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.tfl", tflConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.tfl", { enabled: false })
+ const res = await patch(app, "freya.tfl", { enabled: false })
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.tfl`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.tfl`)
expect(row!.enabled).toBe(false)
expect(row!.config).toEqual({ lines: ["bakerloo"] })
})
test("deep-merges config on update", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
config: { units: "metric", hourlyLimit: 12 },
})
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await patch(app, "aelis.weather", {
+ const res = await patch(app, "freya.weather", {
config: { dailyLimit: 5 },
})
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.weather`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.weather`)
expect(row!.config).toEqual({
units: "metric",
hourlyLimit: 12,
@@ -430,18 +430,18 @@ describe("PATCH /api/sources/:sourceId", () => {
test("refreshes source in active session after config update", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
config: { units: "metric" },
})
const { app, sessionManager } = createApp(
- [createStubProvider("aelis.weather", weatherConfig)],
+ [createStubProvider("freya.weather", weatherConfig)],
MOCK_USER_ID,
)
const session = await sessionManager.getOrCreate(MOCK_USER_ID)
const replaceSpy = spyOn(session, "replaceSource")
- const res = await patch(app, "aelis.weather", {
+ const res = await patch(app, "freya.weather", {
config: { units: "imperial" },
})
@@ -452,31 +452,31 @@ describe("PATCH /api/sources/:sourceId", () => {
test("removes source from session when disabled", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
enabled: true,
config: { units: "metric" },
})
const { app, sessionManager } = createApp(
- [createStubProvider("aelis.weather", weatherConfig)],
+ [createStubProvider("freya.weather", weatherConfig)],
MOCK_USER_ID,
)
const session = await sessionManager.getOrCreate(MOCK_USER_ID)
const removeSpy = spyOn(session, "removeSource")
- const res = await patch(app, "aelis.weather", { enabled: false })
+ const res = await patch(app, "freya.weather", { enabled: false })
expect(res.status).toBe(204)
- expect(removeSpy).toHaveBeenCalledWith("aelis.weather")
+ expect(removeSpy).toHaveBeenCalledWith("freya.weather")
removeSpy.mockRestore()
})
test("returns 400 when config is provided for source without schema", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.location")
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.location")
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await patch(app, "aelis.location", {
+ const res = await patch(app, "freya.location", {
config: { something: "value" },
})
@@ -485,10 +485,10 @@ describe("PATCH /api/sources/:sourceId", () => {
test("returns 400 when empty config is provided for source without schema", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.location")
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.location")
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await patch(app, "aelis.location", {
+ const res = await patch(app, "freya.location", {
config: {},
})
@@ -497,13 +497,13 @@ describe("PATCH /api/sources/:sourceId", () => {
test("updates enabled on location source", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.location", { enabled: true })
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.location", { enabled: true })
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await patch(app, "aelis.location", { enabled: false })
+ const res = await patch(app, "freya.location", { enabled: false })
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.location`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.location`)
expect(row!.enabled).toBe(false)
})
})
@@ -515,16 +515,16 @@ describe("PATCH /api/sources/:sourceId", () => {
describe("PUT /api/sources/:sourceId", () => {
test("returns 401 without auth", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)])
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)])
- const res = await put(app, "aelis.weather", { enabled: true, config: {} })
+ const res = await put(app, "freya.weather", { enabled: true, config: {} })
expect(res.status).toBe(401)
})
test("returns 404 for unknown source", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
const res = await put(app, "unknown.source", { enabled: true, config: {} })
@@ -535,9 +535,9 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 400 for invalid JSON", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await app.request("/api/sources/aelis.weather", {
+ const res = await app.request("/api/sources/freya.weather", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: "not json",
@@ -550,27 +550,27 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 400 when enabled is missing", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", { config: {} })
+ const res = await put(app, "freya.weather", { config: {} })
expect(res.status).toBe(400)
})
test("returns 400 when config is missing", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", { enabled: true })
+ const res = await put(app, "freya.weather", { enabled: true })
expect(res.status).toBe(400)
})
test("returns 400 when request body contains unknown fields", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "metric" },
unknownField: "hello",
@@ -581,9 +581,9 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 400 when weather config contains unknown fields", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "metric", unknownField: "hello" },
})
@@ -593,9 +593,9 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 400 when config fails schema validation", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "invalid" },
})
@@ -605,15 +605,15 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 204 and inserts when row does not exist", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "metric" },
})
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.weather`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.weather`)
expect(row).toBeDefined()
expect(row!.enabled).toBe(true)
expect(row!.config).toEqual({ units: "metric" })
@@ -621,19 +621,19 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 204 and fully replaces existing row", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
enabled: true,
config: { units: "metric", hourlyLimit: 12 },
})
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: false,
config: { units: "imperial" },
})
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.weather`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.weather`)
expect(row!.enabled).toBe(false)
// hourlyLimit should be gone — full replace, not merge
expect(row!.config).toEqual({ units: "imperial" })
@@ -641,18 +641,18 @@ describe("PUT /api/sources/:sourceId", () => {
test("refreshes source in active session after upsert", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
config: { units: "metric" },
})
const { app, sessionManager } = createApp(
- [createStubProvider("aelis.weather", weatherConfig)],
+ [createStubProvider("freya.weather", weatherConfig)],
MOCK_USER_ID,
)
const session = await sessionManager.getOrCreate(MOCK_USER_ID)
const replaceSpy = spyOn(session, "replaceSource")
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "imperial" },
})
@@ -664,56 +664,56 @@ describe("PUT /api/sources/:sourceId", () => {
test("removes source from session when disabled via upsert", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.weather", {
+ activeStore.seed(MOCK_USER_ID, "freya.weather", {
enabled: true,
config: { units: "metric" },
})
const { app, sessionManager } = createApp(
- [createStubProvider("aelis.weather", weatherConfig)],
+ [createStubProvider("freya.weather", weatherConfig)],
MOCK_USER_ID,
)
const session = await sessionManager.getOrCreate(MOCK_USER_ID)
const removeSpy = spyOn(session, "removeSource")
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: false,
config: { units: "metric" },
})
expect(res.status).toBe(204)
- expect(removeSpy).toHaveBeenCalledWith("aelis.weather")
+ expect(removeSpy).toHaveBeenCalledWith("freya.weather")
removeSpy.mockRestore()
})
test("adds source to active session when inserting a new source", async () => {
activeStore = createInMemoryStore()
// Seed a different source so the session can be created
- activeStore.seed(MOCK_USER_ID, "aelis.location", { enabled: true })
+ activeStore.seed(MOCK_USER_ID, "freya.location", { enabled: true })
const { app, sessionManager } = createApp(
- [createStubProvider("aelis.location"), createStubProvider("aelis.weather", weatherConfig)],
+ [createStubProvider("freya.location"), createStubProvider("freya.weather", weatherConfig)],
MOCK_USER_ID,
)
- // Create session — only has aelis.location
+ // Create session — only has freya.location
const session = await sessionManager.getOrCreate(MOCK_USER_ID)
- expect(session.hasSource("aelis.weather")).toBe(false)
+ expect(session.hasSource("freya.weather")).toBe(false)
// PUT a new source that didn't exist before
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "metric" },
})
expect(res.status).toBe(204)
- expect(session.hasSource("aelis.weather")).toBe(true)
+ expect(session.hasSource("freya.weather")).toBe(true)
})
test("returns 400 when config is provided for source without schema", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await put(app, "aelis.location", {
+ const res = await put(app, "freya.location", {
enabled: true,
config: { something: "value" },
})
@@ -723,9 +723,9 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 400 when empty config is provided for source without schema", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await put(app, "aelis.location", {
+ const res = await put(app, "freya.location", {
enabled: true,
config: {},
})
@@ -735,9 +735,9 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 204 without config field for source without schema", async () => {
activeStore = createInMemoryStore()
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await put(app, "aelis.location", {
+ const res = await put(app, "freya.location", {
enabled: true,
})
@@ -747,18 +747,18 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 204 when credentials are included alongside config", async () => {
activeStore = createInMemoryStore()
const { app } = createAppWithEncryptor(
- [createStubProvider("aelis.weather", weatherConfig)],
+ [createStubProvider("freya.weather", weatherConfig)],
MOCK_USER_ID,
)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "metric" },
credentials: { apiKey: "secret123" },
})
expect(res.status).toBe(204)
- const row = activeStore.rows.get(`${MOCK_USER_ID}:aelis.weather`)
+ const row = activeStore.rows.get(`${MOCK_USER_ID}:freya.weather`)
expect(row).toBeDefined()
expect(row!.enabled).toBe(true)
expect(row!.config).toEqual({ units: "metric" })
@@ -767,9 +767,9 @@ describe("PUT /api/sources/:sourceId", () => {
test("returns 503 when credentials are provided but no encryptor is configured", async () => {
activeStore = createInMemoryStore()
// createApp does NOT configure an encryptor
- const { app } = createApp([createStubProvider("aelis.weather", weatherConfig)], MOCK_USER_ID)
+ const { app } = createApp([createStubProvider("freya.weather", weatherConfig)], MOCK_USER_ID)
- const res = await put(app, "aelis.weather", {
+ const res = await put(app, "freya.weather", {
enabled: true,
config: { units: "metric" },
credentials: { apiKey: "secret123" },
@@ -784,16 +784,16 @@ describe("PUT /api/sources/:sourceId", () => {
describe("PUT /api/sources/:sourceId/credentials", () => {
test("returns 401 without auth", async () => {
activeStore = createInMemoryStore()
- const { app } = createAppWithEncryptor([createStubProvider("aelis.location")])
+ const { app } = createAppWithEncryptor([createStubProvider("freya.location")])
- const res = await putCredentials(app, "aelis.location", { token: "x" })
+ const res = await putCredentials(app, "freya.location", { token: "x" })
expect(res.status).toBe(401)
})
test("returns 404 for unknown source", async () => {
activeStore = createInMemoryStore()
- const { app } = createAppWithEncryptor([createStubProvider("aelis.location")], MOCK_USER_ID)
+ const { app } = createAppWithEncryptor([createStubProvider("freya.location")], MOCK_USER_ID)
const res = await putCredentials(app, "unknown.source", { token: "x" })
@@ -802,10 +802,10 @@ describe("PUT /api/sources/:sourceId/credentials", () => {
test("returns 400 for invalid JSON", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.location")
- const { app } = createAppWithEncryptor([createStubProvider("aelis.location")], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.location")
+ const { app } = createAppWithEncryptor([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await app.request("/api/sources/aelis.location/credentials", {
+ const res = await app.request("/api/sources/freya.location/credentials", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: "not-json",
@@ -818,10 +818,10 @@ describe("PUT /api/sources/:sourceId/credentials", () => {
test("returns 204 and persists credentials", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.location")
- const { app } = createAppWithEncryptor([createStubProvider("aelis.location")], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.location")
+ const { app } = createAppWithEncryptor([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await putCredentials(app, "aelis.location", { token: "secret" })
+ const res = await putCredentials(app, "freya.location", { token: "secret" })
expect(res.status).toBe(204)
})
@@ -853,10 +853,10 @@ describe("PUT /api/sources/:sourceId/credentials", () => {
test("returns 503 when credential encryption is not configured", async () => {
activeStore = createInMemoryStore()
- activeStore.seed(MOCK_USER_ID, "aelis.location")
- const { app } = createApp([createStubProvider("aelis.location")], MOCK_USER_ID)
+ activeStore.seed(MOCK_USER_ID, "freya.location")
+ const { app } = createApp([createStubProvider("freya.location")], MOCK_USER_ID)
- const res = await putCredentials(app, "aelis.location", { token: "x" })
+ const res = await putCredentials(app, "freya.location", { token: "x" })
expect(res.status).toBe(503)
const body = (await res.json()) as { error: string }
diff --git a/apps/aelis-backend/src/sources/http.ts b/apps/freya-backend/src/sources/http.ts
similarity index 100%
rename from apps/aelis-backend/src/sources/http.ts
rename to apps/freya-backend/src/sources/http.ts
diff --git a/apps/aelis-backend/src/sources/user-sources.ts b/apps/freya-backend/src/sources/user-sources.ts
similarity index 100%
rename from apps/aelis-backend/src/sources/user-sources.ts
rename to apps/freya-backend/src/sources/user-sources.ts
diff --git a/apps/aelis-backend/src/tfl/provider.ts b/apps/freya-backend/src/tfl/provider.ts
similarity index 91%
rename from apps/aelis-backend/src/tfl/provider.ts
rename to apps/freya-backend/src/tfl/provider.ts
index 2fe4a6c..9367f91 100644
--- a/apps/aelis-backend/src/tfl/provider.ts
+++ b/apps/freya-backend/src/tfl/provider.ts
@@ -1,4 +1,4 @@
-import { TflSource, type ITflApi, type TflLineId } from "@aelis/source-tfl"
+import { TflSource, type ITflApi, type TflLineId } from "@freya/source-tfl"
import { type } from "arktype"
import type { FeedSourceProvider } from "../session/feed-source-provider.ts"
@@ -13,7 +13,7 @@ export const tflConfig = type({
})
export class TflSourceProvider implements FeedSourceProvider {
- readonly sourceId = "aelis.tfl"
+ readonly sourceId = "freya.tfl"
readonly configSchema = tflConfig
private readonly apiKey: string | undefined
private readonly client: ITflApi | undefined
diff --git a/apps/aelis-backend/src/weather/provider.ts b/apps/freya-backend/src/weather/provider.ts
similarity index 92%
rename from apps/aelis-backend/src/weather/provider.ts
rename to apps/freya-backend/src/weather/provider.ts
index 861ad4b..28663c7 100644
--- a/apps/aelis-backend/src/weather/provider.ts
+++ b/apps/freya-backend/src/weather/provider.ts
@@ -1,4 +1,4 @@
-import { WeatherSource, type WeatherSourceOptions } from "@aelis/source-weatherkit"
+import { WeatherSource, type WeatherSourceOptions } from "@freya/source-weatherkit"
import { type } from "arktype"
import type { FeedSourceProvider } from "../session/feed-source-provider.ts"
@@ -16,7 +16,7 @@ export const weatherConfig = type({
})
export class WeatherSourceProvider implements FeedSourceProvider {
- readonly sourceId = "aelis.weather"
+ readonly sourceId = "freya.weather"
readonly configSchema = weatherConfig
private readonly credentials: WeatherSourceOptions["credentials"]
private readonly client: WeatherSourceOptions["client"]
diff --git a/apps/aelis-backend/tsconfig.json b/apps/freya-backend/tsconfig.json
similarity index 100%
rename from apps/aelis-backend/tsconfig.json
rename to apps/freya-backend/tsconfig.json
diff --git a/apps/aelis-client/.gitignore b/apps/freya-client/.gitignore
similarity index 100%
rename from apps/aelis-client/.gitignore
rename to apps/freya-client/.gitignore
diff --git a/apps/aelis-client/.vscode/extensions.json b/apps/freya-client/.vscode/extensions.json
similarity index 100%
rename from apps/aelis-client/.vscode/extensions.json
rename to apps/freya-client/.vscode/extensions.json
diff --git a/apps/aelis-client/.vscode/settings.json b/apps/freya-client/.vscode/settings.json
similarity index 100%
rename from apps/aelis-client/.vscode/settings.json
rename to apps/freya-client/.vscode/settings.json
diff --git a/apps/aelis-client/README.md b/apps/freya-client/README.md
similarity index 100%
rename from apps/aelis-client/README.md
rename to apps/freya-client/README.md
diff --git a/apps/aelis-client/app.json b/apps/freya-client/app.json
similarity index 98%
rename from apps/aelis-client/app.json
rename to apps/freya-client/app.json
index 17ffba8..9e29755 100644
--- a/apps/aelis-client/app.json
+++ b/apps/freya-client/app.json
@@ -1,11 +1,11 @@
{
"expo": {
- "name": "Aelis",
- "slug": "aelis-client",
+ "name": "Freya",
+ "slug": "freya-client",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
- "scheme": "aelis",
+ "scheme": "freya",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
@@ -15,7 +15,7 @@
},
"ITSAppUsesNonExemptEncryption": false
},
- "bundleIdentifier": "sh.nym.aelis"
+ "bundleIdentifier": "sh.nym.freya"
},
"android": {
"adaptiveIcon": {
@@ -26,7 +26,7 @@
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false,
- "package": "sh.nym.aelis"
+ "package": "sh.nym.freya"
},
"web": {
"output": "static",
diff --git a/apps/aelis-client/assets/fonts/Inter_100Thin.ttf b/apps/freya-client/assets/fonts/Inter_100Thin.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_100Thin.ttf
rename to apps/freya-client/assets/fonts/Inter_100Thin.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_100Thin_Italic.ttf b/apps/freya-client/assets/fonts/Inter_100Thin_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_100Thin_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_100Thin_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_200ExtraLight.ttf b/apps/freya-client/assets/fonts/Inter_200ExtraLight.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_200ExtraLight.ttf
rename to apps/freya-client/assets/fonts/Inter_200ExtraLight.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_200ExtraLight_Italic.ttf b/apps/freya-client/assets/fonts/Inter_200ExtraLight_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_200ExtraLight_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_200ExtraLight_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_300Light.ttf b/apps/freya-client/assets/fonts/Inter_300Light.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_300Light.ttf
rename to apps/freya-client/assets/fonts/Inter_300Light.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_300Light_Italic.ttf b/apps/freya-client/assets/fonts/Inter_300Light_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_300Light_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_300Light_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_400Regular.ttf b/apps/freya-client/assets/fonts/Inter_400Regular.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_400Regular.ttf
rename to apps/freya-client/assets/fonts/Inter_400Regular.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_400Regular_Italic.ttf b/apps/freya-client/assets/fonts/Inter_400Regular_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_400Regular_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_400Regular_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_500Medium.ttf b/apps/freya-client/assets/fonts/Inter_500Medium.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_500Medium.ttf
rename to apps/freya-client/assets/fonts/Inter_500Medium.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_500Medium_Italic.ttf b/apps/freya-client/assets/fonts/Inter_500Medium_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_500Medium_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_500Medium_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_600SemiBold.ttf b/apps/freya-client/assets/fonts/Inter_600SemiBold.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_600SemiBold.ttf
rename to apps/freya-client/assets/fonts/Inter_600SemiBold.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_600SemiBold_Italic.ttf b/apps/freya-client/assets/fonts/Inter_600SemiBold_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_600SemiBold_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_600SemiBold_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_700Bold.ttf b/apps/freya-client/assets/fonts/Inter_700Bold.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_700Bold.ttf
rename to apps/freya-client/assets/fonts/Inter_700Bold.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_700Bold_Italic.ttf b/apps/freya-client/assets/fonts/Inter_700Bold_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_700Bold_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_700Bold_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_800ExtraBold.ttf b/apps/freya-client/assets/fonts/Inter_800ExtraBold.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_800ExtraBold.ttf
rename to apps/freya-client/assets/fonts/Inter_800ExtraBold.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_800ExtraBold_Italic.ttf b/apps/freya-client/assets/fonts/Inter_800ExtraBold_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_800ExtraBold_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_800ExtraBold_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_900Black.ttf b/apps/freya-client/assets/fonts/Inter_900Black.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_900Black.ttf
rename to apps/freya-client/assets/fonts/Inter_900Black.ttf
diff --git a/apps/aelis-client/assets/fonts/Inter_900Black_Italic.ttf b/apps/freya-client/assets/fonts/Inter_900Black_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/Inter_900Black_Italic.ttf
rename to apps/freya-client/assets/fonts/Inter_900Black_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_200ExtraLight.ttf b/apps/freya-client/assets/fonts/SourceSerif4_200ExtraLight.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_200ExtraLight.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_200ExtraLight.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_200ExtraLight_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_200ExtraLight_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_200ExtraLight_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_200ExtraLight_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_300Light.ttf b/apps/freya-client/assets/fonts/SourceSerif4_300Light.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_300Light.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_300Light.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_300Light_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_300Light_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_300Light_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_300Light_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_400Regular.ttf b/apps/freya-client/assets/fonts/SourceSerif4_400Regular.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_400Regular.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_400Regular.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_400Regular_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_400Regular_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_400Regular_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_400Regular_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_500Medium.ttf b/apps/freya-client/assets/fonts/SourceSerif4_500Medium.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_500Medium.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_500Medium.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_500Medium_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_500Medium_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_500Medium_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_500Medium_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_600SemiBold.ttf b/apps/freya-client/assets/fonts/SourceSerif4_600SemiBold.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_600SemiBold.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_600SemiBold.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_600SemiBold_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_600SemiBold_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_600SemiBold_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_600SemiBold_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_700Bold.ttf b/apps/freya-client/assets/fonts/SourceSerif4_700Bold.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_700Bold.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_700Bold.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_700Bold_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_700Bold_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_700Bold_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_700Bold_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_800ExtraBold.ttf b/apps/freya-client/assets/fonts/SourceSerif4_800ExtraBold.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_800ExtraBold.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_800ExtraBold.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_800ExtraBold_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_800ExtraBold_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_800ExtraBold_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_800ExtraBold_Italic.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_900Black.ttf b/apps/freya-client/assets/fonts/SourceSerif4_900Black.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_900Black.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_900Black.ttf
diff --git a/apps/aelis-client/assets/fonts/SourceSerif4_900Black_Italic.ttf b/apps/freya-client/assets/fonts/SourceSerif4_900Black_Italic.ttf
similarity index 100%
rename from apps/aelis-client/assets/fonts/SourceSerif4_900Black_Italic.ttf
rename to apps/freya-client/assets/fonts/SourceSerif4_900Black_Italic.ttf
diff --git a/apps/aelis-client/assets/images/android-icon-background.png b/apps/freya-client/assets/images/android-icon-background.png
similarity index 100%
rename from apps/aelis-client/assets/images/android-icon-background.png
rename to apps/freya-client/assets/images/android-icon-background.png
diff --git a/apps/aelis-client/assets/images/android-icon-foreground.png b/apps/freya-client/assets/images/android-icon-foreground.png
similarity index 100%
rename from apps/aelis-client/assets/images/android-icon-foreground.png
rename to apps/freya-client/assets/images/android-icon-foreground.png
diff --git a/apps/aelis-client/assets/images/android-icon-monochrome.png b/apps/freya-client/assets/images/android-icon-monochrome.png
similarity index 100%
rename from apps/aelis-client/assets/images/android-icon-monochrome.png
rename to apps/freya-client/assets/images/android-icon-monochrome.png
diff --git a/apps/aelis-client/assets/images/favicon.png b/apps/freya-client/assets/images/favicon.png
similarity index 100%
rename from apps/aelis-client/assets/images/favicon.png
rename to apps/freya-client/assets/images/favicon.png
diff --git a/apps/aelis-client/assets/images/icon.png b/apps/freya-client/assets/images/icon.png
similarity index 100%
rename from apps/aelis-client/assets/images/icon.png
rename to apps/freya-client/assets/images/icon.png
diff --git a/apps/aelis-client/assets/images/partial-react-logo.png b/apps/freya-client/assets/images/partial-react-logo.png
similarity index 100%
rename from apps/aelis-client/assets/images/partial-react-logo.png
rename to apps/freya-client/assets/images/partial-react-logo.png
diff --git a/apps/aelis-client/assets/images/react-logo.png b/apps/freya-client/assets/images/react-logo.png
similarity index 100%
rename from apps/aelis-client/assets/images/react-logo.png
rename to apps/freya-client/assets/images/react-logo.png
diff --git a/apps/aelis-client/assets/images/react-logo@2x.png b/apps/freya-client/assets/images/react-logo@2x.png
similarity index 100%
rename from apps/aelis-client/assets/images/react-logo@2x.png
rename to apps/freya-client/assets/images/react-logo@2x.png
diff --git a/apps/aelis-client/assets/images/react-logo@3x.png b/apps/freya-client/assets/images/react-logo@3x.png
similarity index 100%
rename from apps/aelis-client/assets/images/react-logo@3x.png
rename to apps/freya-client/assets/images/react-logo@3x.png
diff --git a/apps/aelis-client/assets/images/splash-icon.png b/apps/freya-client/assets/images/splash-icon.png
similarity index 100%
rename from apps/aelis-client/assets/images/splash-icon.png
rename to apps/freya-client/assets/images/splash-icon.png
diff --git a/apps/aelis-client/eas.json b/apps/freya-client/eas.json
similarity index 100%
rename from apps/aelis-client/eas.json
rename to apps/freya-client/eas.json
diff --git a/apps/aelis-client/eslint.config.js b/apps/freya-client/eslint.config.js
similarity index 100%
rename from apps/aelis-client/eslint.config.js
rename to apps/freya-client/eslint.config.js
diff --git a/apps/aelis-client/package.json b/apps/freya-client/package.json
similarity index 98%
rename from apps/aelis-client/package.json
rename to apps/freya-client/package.json
index 8a1d2a2..8879401 100644
--- a/apps/aelis-client/package.json
+++ b/apps/freya-client/package.json
@@ -1,5 +1,5 @@
{
- "name": "aelis-client",
+ "name": "freya-client",
"version": "1.0.0",
"private": true,
"main": "expo-router/entry",
diff --git a/apps/aelis-client/scripts/dev-proxy.ts b/apps/freya-client/scripts/dev-proxy.ts
similarity index 100%
rename from apps/aelis-client/scripts/dev-proxy.ts
rename to apps/freya-client/scripts/dev-proxy.ts
diff --git a/apps/aelis-client/scripts/open-debugger.ts b/apps/freya-client/scripts/open-debugger.ts
similarity index 100%
rename from apps/aelis-client/scripts/open-debugger.ts
rename to apps/freya-client/scripts/open-debugger.ts
diff --git a/apps/aelis-client/scripts/reset-project.js b/apps/freya-client/scripts/reset-project.js
similarity index 100%
rename from apps/aelis-client/scripts/reset-project.js
rename to apps/freya-client/scripts/reset-project.js
diff --git a/apps/aelis-client/scripts/run-dev-server.sh b/apps/freya-client/scripts/run-dev-server.sh
similarity index 100%
rename from apps/aelis-client/scripts/run-dev-server.sh
rename to apps/freya-client/scripts/run-dev-server.sh
diff --git a/apps/aelis-client/src/api/auth-middleware.ts b/apps/freya-client/src/api/auth-middleware.ts
similarity index 100%
rename from apps/aelis-client/src/api/auth-middleware.ts
rename to apps/freya-client/src/api/auth-middleware.ts
diff --git a/apps/aelis-client/src/api/client.ts b/apps/freya-client/src/api/client.ts
similarity index 100%
rename from apps/aelis-client/src/api/client.ts
rename to apps/freya-client/src/api/client.ts
diff --git a/apps/aelis-client/src/app/_layout.tsx b/apps/freya-client/src/app/_layout.tsx
similarity index 100%
rename from apps/aelis-client/src/app/_layout.tsx
rename to apps/freya-client/src/app/_layout.tsx
diff --git a/apps/aelis-client/src/app/components/[name].tsx b/apps/freya-client/src/app/components/[name].tsx
similarity index 100%
rename from apps/aelis-client/src/app/components/[name].tsx
rename to apps/freya-client/src/app/components/[name].tsx
diff --git a/apps/aelis-client/src/app/components/index.tsx b/apps/freya-client/src/app/components/index.tsx
similarity index 100%
rename from apps/aelis-client/src/app/components/index.tsx
rename to apps/freya-client/src/app/components/index.tsx
diff --git a/apps/aelis-client/src/app/index.tsx b/apps/freya-client/src/app/index.tsx
similarity index 100%
rename from apps/aelis-client/src/app/index.tsx
rename to apps/freya-client/src/app/index.tsx
diff --git a/apps/aelis-client/src/components/showcase.tsx b/apps/freya-client/src/components/showcase.tsx
similarity index 100%
rename from apps/aelis-client/src/components/showcase.tsx
rename to apps/freya-client/src/components/showcase.tsx
diff --git a/apps/aelis-client/src/components/ui/button.showcase.tsx b/apps/freya-client/src/components/ui/button.showcase.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/button.showcase.tsx
rename to apps/freya-client/src/components/ui/button.showcase.tsx
diff --git a/apps/aelis-client/src/components/ui/button.tsx b/apps/freya-client/src/components/ui/button.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/button.tsx
rename to apps/freya-client/src/components/ui/button.tsx
diff --git a/apps/aelis-client/src/components/ui/feed-card.showcase.tsx b/apps/freya-client/src/components/ui/feed-card.showcase.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/feed-card.showcase.tsx
rename to apps/freya-client/src/components/ui/feed-card.showcase.tsx
diff --git a/apps/aelis-client/src/components/ui/feed-card.tsx b/apps/freya-client/src/components/ui/feed-card.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/feed-card.tsx
rename to apps/freya-client/src/components/ui/feed-card.tsx
diff --git a/apps/aelis-client/src/components/ui/monospace-text.showcase.tsx b/apps/freya-client/src/components/ui/monospace-text.showcase.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/monospace-text.showcase.tsx
rename to apps/freya-client/src/components/ui/monospace-text.showcase.tsx
diff --git a/apps/aelis-client/src/components/ui/monospace-text.tsx b/apps/freya-client/src/components/ui/monospace-text.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/monospace-text.tsx
rename to apps/freya-client/src/components/ui/monospace-text.tsx
diff --git a/apps/aelis-client/src/components/ui/sans-serif-text.showcase.tsx b/apps/freya-client/src/components/ui/sans-serif-text.showcase.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/sans-serif-text.showcase.tsx
rename to apps/freya-client/src/components/ui/sans-serif-text.showcase.tsx
diff --git a/apps/aelis-client/src/components/ui/sans-serif-text.tsx b/apps/freya-client/src/components/ui/sans-serif-text.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/sans-serif-text.tsx
rename to apps/freya-client/src/components/ui/sans-serif-text.tsx
diff --git a/apps/aelis-client/src/components/ui/serif-text.showcase.tsx b/apps/freya-client/src/components/ui/serif-text.showcase.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/serif-text.showcase.tsx
rename to apps/freya-client/src/components/ui/serif-text.showcase.tsx
diff --git a/apps/aelis-client/src/components/ui/serif-text.tsx b/apps/freya-client/src/components/ui/serif-text.tsx
similarity index 100%
rename from apps/aelis-client/src/components/ui/serif-text.tsx
rename to apps/freya-client/src/components/ui/serif-text.tsx
diff --git a/apps/aelis-client/src/feed/queries.ts b/apps/freya-client/src/feed/queries.ts
similarity index 100%
rename from apps/aelis-client/src/feed/queries.ts
rename to apps/freya-client/src/feed/queries.ts
diff --git a/apps/aelis-client/src/feed/types.ts b/apps/freya-client/src/feed/types.ts
similarity index 100%
rename from apps/aelis-client/src/feed/types.ts
rename to apps/freya-client/src/feed/types.ts
diff --git a/apps/aelis-client/src/json-render/catalog.ts b/apps/freya-client/src/json-render/catalog.ts
similarity index 100%
rename from apps/aelis-client/src/json-render/catalog.ts
rename to apps/freya-client/src/json-render/catalog.ts
diff --git a/apps/aelis-client/src/json-render/index.ts b/apps/freya-client/src/json-render/index.ts
similarity index 100%
rename from apps/aelis-client/src/json-render/index.ts
rename to apps/freya-client/src/json-render/index.ts
diff --git a/apps/aelis-client/src/json-render/registry.tsx b/apps/freya-client/src/json-render/registry.tsx
similarity index 100%
rename from apps/aelis-client/src/json-render/registry.tsx
rename to apps/freya-client/src/json-render/registry.tsx
diff --git a/apps/aelis-client/tsconfig.json b/apps/freya-client/tsconfig.json
similarity index 100%
rename from apps/aelis-client/tsconfig.json
rename to apps/freya-client/tsconfig.json
diff --git a/apps/waitlist-website/app/chat/message.ts b/apps/waitlist-website/app/chat/message.ts
index 2327c8b..dfc90c1 100644
--- a/apps/waitlist-website/app/chat/message.ts
+++ b/apps/waitlist-website/app/chat/message.ts
@@ -30,7 +30,7 @@ export const INITIAL_MESSAGES: Message[] = [
},
{
role: "system",
- message: `Hey! I'm **Aelis** — your personal assistant that brings you the right thing, at the right time, in the right place.
+ message: `Hey! I'm **Freya** — your personal assistant that brings you the right thing, at the right time, in the right place.
- Jubilee line down? I've already found you an alternative route.
- Dinner reservation at 8? I'll have the restaurant, directions, and the menu ready before you head out.
diff --git a/apps/waitlist-website/app/routes/home.tsx b/apps/waitlist-website/app/routes/home.tsx
index d9a0f75..5758307 100644
--- a/apps/waitlist-website/app/routes/home.tsx
+++ b/apps/waitlist-website/app/routes/home.tsx
@@ -24,9 +24,9 @@ import { ProgressiveBlur } from "~/components/progressive-blur"
import type { Route } from "./+types/home"
-const PAGE_TITLE = "Aelis - Next Generation AI Assistant"
+const PAGE_TITLE = "Freya - Next Generation AI Assistant"
const PAGE_DESCRIPTION =
- "Meet Aelis, a personal assistant that stays one step ahead of your day. Join the waitlist now."
+ "Meet Freya, a personal assistant that stays one step ahead of your day. Join the waitlist now."
export function meta({}: Route.MetaArgs) {
return [
@@ -84,7 +84,7 @@ export async function action({ request }: Route.ActionArgs) {
await new Promise((resolve) => setTimeout(resolve, 1000))
const emailRes = await resend.emails.send({
- from: "Aelis ",
+ from: "Freya ",
to: email,
template: {
id: "waitlist-confirmation",
diff --git a/apps/waitlist-website/app/routes/privacy-policy.tsx b/apps/waitlist-website/app/routes/privacy-policy.tsx
index fc83a0a..d707443 100644
--- a/apps/waitlist-website/app/routes/privacy-policy.tsx
+++ b/apps/waitlist-website/app/routes/privacy-policy.tsx
@@ -7,8 +7,8 @@ import type { Route } from "./+types/privacy-policy"
export function meta({}: Route.MetaArgs) {
return [
- { title: "Privacy Policy — Aelis" },
- { name: "description", content: "Aelis privacy policy" },
+ { title: "Privacy Policy — Freya" },
+ { name: "description", content: "Freya privacy policy" },
]
}
@@ -40,7 +40,7 @@ const POLICY = `# Privacy Policy
**Last updated:** March 5, 2026
-This Privacy Policy describes how **Aelis** ("we", "us", or "our") collects, uses, and protects your personal information when you visit **https://ael.is** or interact with our services.
+This Privacy Policy describes how **Freya** ("we", "us", or "our") collects, uses, and protects your personal information when you visit **https://ael.is** or interact with our services.
If you do not agree with this Privacy Policy, please do not use the website.
@@ -230,7 +230,7 @@ We encourage users to review this Privacy Policy regularly.
If you have questions or comments about this Privacy Policy, you may contact us:
-**Aelis**
+**Freya**
Email: **[kenneth@nym.sh](mailto:kenneth@nym.sh)**
diff --git a/apps/waitlist-website/fly.toml b/apps/waitlist-website/fly.toml
index e0c7e8e..1be7fc4 100644
--- a/apps/waitlist-website/fly.toml
+++ b/apps/waitlist-website/fly.toml
@@ -1,9 +1,9 @@
-# fly.toml app configuration file generated for aelis-waitlist-website on 2026-03-08T01:11:12Z
+# fly.toml app configuration file generated for freya-waitlist-website on 2026-03-08T01:11:12Z
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
-app = 'aelis-waitlist-website'
+app = 'freya-waitlist-website'
primary_region = 'lhr'
[build]
diff --git a/bun.lock b/bun.lock
index e6a481f..4a9631b 100644
--- a/bun.lock
+++ b/bun.lock
@@ -3,7 +3,7 @@
"configVersion": 1,
"workspaces": {
"": {
- "name": "aelis",
+ "name": "freya",
"devDependencies": {
"@json-render/core": "^0.12.1",
"@nym.sh/jrx": "^0.2.0",
@@ -46,16 +46,16 @@
"vite": "^7.2.4",
},
},
- "apps/aelis-backend": {
- "name": "@aelis/backend",
+ "apps/freya-backend": {
+ "name": "@freya/backend",
"version": "0.0.0",
"dependencies": {
- "@aelis/core": "workspace:*",
- "@aelis/source-caldav": "workspace:*",
- "@aelis/source-google-calendar": "workspace:*",
- "@aelis/source-location": "workspace:*",
- "@aelis/source-tfl": "workspace:*",
- "@aelis/source-weatherkit": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-caldav": "workspace:*",
+ "@freya/source-google-calendar": "workspace:*",
+ "@freya/source-location": "workspace:*",
+ "@freya/source-tfl": "workspace:*",
+ "@freya/source-weatherkit": "workspace:*",
"@openrouter/sdk": "^0.9.11",
"arktype": "^2.1.29",
"better-auth": "^1",
@@ -68,8 +68,8 @@
"drizzle-kit": "^0.31.9",
},
},
- "apps/aelis-client": {
- "name": "aelis-client",
+ "apps/freya-client": {
+ "name": "freya-client",
"version": "1.0.0",
"dependencies": {
"@expo-google-fonts/inter": "^0.4.2",
@@ -144,16 +144,16 @@
"vite-tsconfig-paths": "^5.1.4",
},
},
- "packages/aelis-components": {
- "name": "@aelis/components",
+ "packages/freya-components": {
+ "name": "@freya/components",
"version": "0.0.0",
"peerDependencies": {
"@json-render/core": "*",
"@nym.sh/jrx": "*",
},
},
- "packages/aelis-core": {
- "name": "@aelis/core",
+ "packages/freya-core": {
+ "name": "@freya/core",
"version": "0.0.0",
"dependencies": {
"@standard-schema/spec": "^1.1.0",
@@ -163,50 +163,50 @@
"@nym.sh/jrx": "*",
},
},
- "packages/aelis-feed-enhancers": {
- "name": "@aelis/feed-enhancers",
+ "packages/freya-feed-enhancers": {
+ "name": "@freya/feed-enhancers",
"version": "0.0.0",
"dependencies": {
- "@aelis/core": "workspace:*",
- "@aelis/source-caldav": "workspace:*",
- "@aelis/source-google-calendar": "workspace:*",
- "@aelis/source-tfl": "workspace:*",
- "@aelis/source-weatherkit": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-caldav": "workspace:*",
+ "@freya/source-google-calendar": "workspace:*",
+ "@freya/source-tfl": "workspace:*",
+ "@freya/source-weatherkit": "workspace:*",
},
},
- "packages/aelis-source-caldav": {
- "name": "@aelis/source-caldav",
+ "packages/freya-source-caldav": {
+ "name": "@freya/source-caldav",
"version": "0.0.0",
"dependencies": {
- "@aelis/components": "workspace:*",
- "@aelis/core": "workspace:*",
+ "@freya/components": "workspace:*",
+ "@freya/core": "workspace:*",
"ical.js": "^2.1.0",
"tsdav": "^2.1.7",
},
},
- "packages/aelis-source-google-calendar": {
- "name": "@aelis/source-google-calendar",
+ "packages/freya-source-google-calendar": {
+ "name": "@freya/source-google-calendar",
"version": "0.0.0",
"dependencies": {
- "@aelis/core": "workspace:*",
+ "@freya/core": "workspace:*",
"arktype": "^2.1.0",
},
},
- "packages/aelis-source-location": {
- "name": "@aelis/source-location",
+ "packages/freya-source-location": {
+ "name": "@freya/source-location",
"version": "0.0.0",
"dependencies": {
- "@aelis/core": "workspace:*",
+ "@freya/core": "workspace:*",
"arktype": "^2.1.0",
},
},
- "packages/aelis-source-tfl": {
- "name": "@aelis/source-tfl",
+ "packages/freya-source-tfl": {
+ "name": "@freya/source-tfl",
"version": "0.0.0",
"dependencies": {
- "@aelis/components": "workspace:*",
- "@aelis/core": "workspace:*",
- "@aelis/source-location": "workspace:*",
+ "@freya/components": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-location": "workspace:*",
"arktype": "^2.1.0",
},
"peerDependencies": {
@@ -214,12 +214,12 @@
"@nym.sh/jrx": "*",
},
},
- "packages/aelis-source-weatherkit": {
- "name": "@aelis/source-weatherkit",
+ "packages/freya-source-weatherkit": {
+ "name": "@freya/source-weatherkit",
"version": "0.0.0",
"dependencies": {
- "@aelis/core": "workspace:*",
- "@aelis/source-location": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-location": "workspace:*",
"arktype": "^2.1.0",
},
},
@@ -227,23 +227,23 @@
"packages": {
"@0no-co/graphql.web": ["@0no-co/graphql.web@1.2.0", "", { "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" }, "optionalPeers": ["graphql"] }, "sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw=="],
- "@aelis/backend": ["@aelis/backend@workspace:apps/aelis-backend"],
+ "@freya/backend": ["@freya/backend@workspace:apps/freya-backend"],
- "@aelis/components": ["@aelis/components@workspace:packages/aelis-components"],
+ "@freya/components": ["@freya/components@workspace:packages/freya-components"],
- "@aelis/core": ["@aelis/core@workspace:packages/aelis-core"],
+ "@freya/core": ["@freya/core@workspace:packages/freya-core"],
- "@aelis/feed-enhancers": ["@aelis/feed-enhancers@workspace:packages/aelis-feed-enhancers"],
+ "@freya/feed-enhancers": ["@freya/feed-enhancers@workspace:packages/freya-feed-enhancers"],
- "@aelis/source-caldav": ["@aelis/source-caldav@workspace:packages/aelis-source-caldav"],
+ "@freya/source-caldav": ["@freya/source-caldav@workspace:packages/freya-source-caldav"],
- "@aelis/source-google-calendar": ["@aelis/source-google-calendar@workspace:packages/aelis-source-google-calendar"],
+ "@freya/source-google-calendar": ["@freya/source-google-calendar@workspace:packages/freya-source-google-calendar"],
- "@aelis/source-location": ["@aelis/source-location@workspace:packages/aelis-source-location"],
+ "@freya/source-location": ["@freya/source-location@workspace:packages/freya-source-location"],
- "@aelis/source-tfl": ["@aelis/source-tfl@workspace:packages/aelis-source-tfl"],
+ "@freya/source-tfl": ["@freya/source-tfl@workspace:packages/freya-source-tfl"],
- "@aelis/source-weatherkit": ["@aelis/source-weatherkit@workspace:packages/aelis-source-weatherkit"],
+ "@freya/source-weatherkit": ["@freya/source-weatherkit@workspace:packages/freya-source-weatherkit"],
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
@@ -1529,7 +1529,7 @@
"admin-dashboard": ["admin-dashboard@workspace:apps/admin-dashboard"],
- "aelis-client": ["aelis-client@workspace:apps/aelis-client"],
+ "freya-client": ["freya-client@workspace:apps/freya-client"],
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
@@ -3921,11 +3921,11 @@
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
- "aelis-client/@types/react": ["@types/react@19.1.17", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA=="],
+ "freya-client/@types/react": ["@types/react@19.1.17", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA=="],
- "aelis-client/react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
+ "freya-client/react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
- "aelis-client/react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
+ "freya-client/react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
"ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
@@ -4559,7 +4559,7 @@
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="],
- "aelis-client/react-dom/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
+ "freya-client/react-dom/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
"better-opn/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="],
diff --git a/docs/ai-agent-ideas.md b/docs/ai-agent-ideas.md
index a5e81ab..be86a7f 100644
--- a/docs/ai-agent-ideas.md
+++ b/docs/ai-agent-ideas.md
@@ -1,4 +1,4 @@
-# AELIS Agent Vision
+# FREYA Agent Vision
## What We're Building
@@ -43,7 +43,7 @@ Sources → Source Graph → FeedEngine
The "agents" in this doc describe _behaviors_, not separate running processes. A human PA is one person — they don't have a "calendar agent" and a "follow-up agent" in their head. They look at your whole situation and act on whatever matters.
-AELIS works the same way. One LLM harness receives all feed items, all context, all user memory, and all available tools. It returns a single `FeedEnhancement`. Every behavior (preparation, follow-up, anomaly detection, tone adjustment, cross-source reasoning) is an instruction in the system prompt, not a separate agent.
+FREYA works the same way. One LLM harness receives all feed items, all context, all user memory, and all available tools. It returns a single `FeedEnhancement`. Every behavior (preparation, follow-up, anomaly detection, tone adjustment, cross-source reasoning) is an instruction in the system prompt, not a separate agent.
The advantage: the LLM sees everything at once. It doesn't need agent-to-agent communication because there's no separation. It naturally connects "rain at 6pm" with "dinner at 7pm" because both are in the same context window.
@@ -101,9 +101,9 @@ const agentContext = new AgentContext({
})
```
-This keeps the engine usable as a pure feed library without the AI layer — useful for testing and for anyone who wants `aelis-core` without the agent features.
+This keeps the engine usable as a pure feed library without the AI layer — useful for testing and for anyone who wants `freya-core` without the agent features.
-**Implementation:** `AgentContext` lives in a new package (`packages/aelis-agent-context` or alongside the enhancement layer). It wraps a `FeedEngine` instance and the persistence stores. The ring buffer for recent items (last N=10 refreshes) lives here, not on the engine — `AgentContext` subscribes to the engine via `engine.subscribe()` and accumulates snapshots. The `itemsFrom(sourceId)` method filters the ring buffer by item type prefix. This is Phase 0 work.
+**Implementation:** `AgentContext` lives in a new package (`packages/freya-agent-context` or alongside the enhancement layer). It wraps a `FeedEngine` instance and the persistence stores. The ring buffer for recent items (last N=10 refreshes) lives here, not on the engine — `AgentContext` subscribes to the engine via `engine.subscribe()` and accumulates snapshots. The `itemsFrom(sourceId)` method filters the ring buffer by item type prefix. This is Phase 0 work.
---
@@ -201,7 +201,7 @@ interface UserAffinityModel {
}
```
-**Implementation:** Build these as individual `FeedPostProcessor` implementations in a `packages/aelis-feed-enhancers` package. Each enhancer is a pure function: items in, enhancement out. Start with three: `TimeOfDayEnhancer`, `CalendarGroupingEnhancer`, `UserAffinityEnhancer`. The affinity model needs a persistence layer — a simple JSON blob per user stored in the database, updated on each dismiss/tap event sent from the client via the WebSocket `feed.interact` method (new JSON-RPC method to add). Time buckets: morning (6-12), afternoon (12-17), evening (17-22), night (22-6).
+**Implementation:** Build these as individual `FeedPostProcessor` implementations in a `packages/freya-feed-enhancers` package. Each enhancer is a pure function: items in, enhancement out. Start with three: `TimeOfDayEnhancer`, `CalendarGroupingEnhancer`, `UserAffinityEnhancer`. The affinity model needs a persistence layer — a simple JSON blob per user stored in the database, updated on each dismiss/tap event sent from the client via the WebSocket `feed.interact` method (new JSON-RPC method to add). Time buckets: morning (6-12), afternoon (12-17), evening (17-22), night (22-6).
### LLM-Powered Enhancements
@@ -288,7 +288,7 @@ These enhancements are delivered via slots on source-produced feed items. Each s
## Emergent Behavior
-Most of what makes AELIS feel like a person isn't hardcoded. It emerges from giving the LLM the right context and the right prompt.
+Most of what makes FREYA feel like a person isn't hardcoded. It emerges from giving the LLM the right context and the right prompt.
### What's hardcoded vs. what's emergent
@@ -340,10 +340,10 @@ These are ~10 small pure functions. Everything else is the LLM reading context a
### The system prompt
-The core of AELIS's behavior is one prompt. Roughly:
+The core of FREYA's behavior is one prompt. Roughly:
```
-You are AELIS, a personal assistant. Here is everything happening
+You are FREYA, a personal assistant. Here is everything happening
in the user's life right now:
[serialized feed items from all sources]
@@ -565,7 +565,7 @@ Surfaces things that break routine, because those are the things you miss.
- "Your calendar is empty tomorrow — did you mean to block time?"
- "You have 3 meetings that overlap between 2-3pm"
-**Implementation:** Mostly rule-based — no LLM needed for detection. Build as a `FeedSource` (`aelis.anomaly`) that depends on calendar sources. Maintain a rolling histogram of the user's meeting start times (stored in the preference/memory DB). On each refresh, compare upcoming events against the histogram. Flag events outside 2 standard deviations. Overlap detection is comparing time ranges. "First free afternoon in N weeks" requires storing daily busyness scores. The anomaly items are `FeedItem`s with type `anomaly` — the LLM is only needed to phrase the message naturally, which can be done with simple templates for v1 ("You have a meeting at {time} — that's unusual for you").
+**Implementation:** Mostly rule-based — no LLM needed for detection. Build as a `FeedSource` (`freya.anomaly`) that depends on calendar sources. Maintain a rolling histogram of the user's meeting start times (stored in the preference/memory DB). On each refresh, compare upcoming events against the histogram. Flag events outside 2 standard deviations. Overlap detection is comparing time ranges. "First free afternoon in N weeks" requires storing daily busyness scores. The anomaly items are `FeedItem`s with type `anomaly` — the LLM is only needed to phrase the message naturally, which can be done with simple templates for v1 ("You have a meeting at {time} — that's unusual for you").
---
@@ -586,7 +586,7 @@ The key difference from task tracking: this catches things that fell through the
The realistic v1 has two channels:
-1. **AELIS conversations (free, no privacy concerns).** Every conversation flows through the Query Agent. When the user says "I'll send that to Sarah tomorrow," the system extracts the intent (action: send something, person: Sarah, deadline: tomorrow) and stores it. No extra permissions needed — the user is already talking to AELIS.
+1. **FREYA conversations (free, no privacy concerns).** Every conversation flows through the Query Agent. When the user says "I'll send that to Sarah tomorrow," the system extracts the intent (action: send something, person: Sarah, deadline: tomorrow) and stores it. No extra permissions needed — the user is already talking to FREYA.
2. **Email scanning (opt-in).** Connect Gmail/Outlook as a source. Scan outbound emails for commitment language: "I'll get back to you," "let me check on that," "I'll send this by Friday." LLM extracts intent + deadline + person. This catches most professional commitments since email is where they're made. Privacy-sensitive — must be explicit opt-in.
@@ -596,7 +596,7 @@ Later channels (harder, deferred): meeting transcripts (Otter, Fireflies, Google
Surfaces gentle reminders — not nagging, more like "hey, just in case." Learns which follow-ups the user appreciates vs. dismisses. Backs off on topics the user ignores repeatedly.
-**Implementation:** Two parts: extraction and surfacing. Extraction runs as a side-effect of the Query Agent — after every conversation turn, pass the user's message through an LLM with a structured output schema: `{ hasCommitment: boolean, action?: string, person?: string, deadline?: string }`. Store extracted commitments in a `commitments` table (user_id, action, person, deadline, status, created_at, dismissed_count). Surfacing is a `FeedSource` (`aelis.followup`) that queries the commitments table for items past their deadline or approaching it. If the user dismisses a follow-up, increment `dismissed_count`; stop showing after 3 dismissals. Email scanning (v2) adds a second extraction path: a background job that processes new sent emails through the same LLM extraction.
+**Implementation:** Two parts: extraction and surfacing. Extraction runs as a side-effect of the Query Agent — after every conversation turn, pass the user's message through an LLM with a structured output schema: `{ hasCommitment: boolean, action?: string, person?: string, deadline?: string }`. Store extracted commitments in a `commitments` table (user_id, action, person, deadline, status, created_at, dismissed_count). Surfacing is a `FeedSource` (`freya.followup`) that queries the commitments table for items past their deadline or approaching it. If the user dismisses a follow-up, increment `dismissed_count`; stop showing after 3 dismissals. Email scanning (v2) adds a second extraction path: a background job that processes new sent emails through the same LLM extraction.
#### Memory
@@ -731,7 +731,7 @@ Beyond frequency, the assistant can understand relationship _dynamics_:
- "You've cancelled on Tom three times — he might be feeling deprioritized."
- "Your meetings with the design team have been getting longer — they averaged 30 min last month, now they're 50 min."
-**Implementation:** Requires a contacts source (Apple Contacts via CardDAV, or Google People API) — build this as a new `FeedSource` that provides contact context (birthdays, anniversaries) to the graph. The social awareness agent is a `FeedSource` (`aelis.social`) that depends on the contacts source and calendar sources. Birthday/anniversary detection: compare contact dates against current date, surface items 7 days before. Meeting frequency: query calendar history for events containing a contact's name, compute average interval, flag when current gap exceeds 2x the average. The "Sarah mentioned she's been sick" level requires email/message scanning — defer to v2. For v1, stick to birthdays + meeting frequency, which are purely rule-based.
+**Implementation:** Requires a contacts source (Apple Contacts via CardDAV, or Google People API) — build this as a new `FeedSource` that provides contact context (birthdays, anniversaries) to the graph. The social awareness agent is a `FeedSource` (`freya.social`) that depends on the contacts source and calendar sources. Birthday/anniversary detection: compare contact dates against current date, surface items 7 days before. Meeting frequency: query calendar history for events containing a contact's name, compute average interval, flag when current gap exceeds 2x the average. The "Sarah mentioned she's been sick" level requires email/message scanning — defer to v2. For v1, stick to birthdays + meeting frequency, which are purely rule-based.
#### Ambient Context
@@ -747,7 +747,7 @@ Monitors the world for things that affect you, beyond weather and location.
A human assistant would flag these without being asked. You shouldn't have to go looking for problems.
-**Implementation:** A collection of specialized `FeedSource` nodes, each monitoring a specific external signal. Start with what's closest to existing sources: `aelis.tfl` already handles transit — extend it to check for planned strikes/closures (TfL API has this data). Package tracking: a new source (`aelis.packages`) that polls tracking APIs (Royal Mail, UPS) given tracking numbers extracted from email (requires email source). News: a source (`aelis.news`) that uses a news API (NewsAPI, Google News) filtered by user interests from the preference store. Each of these is independent and produces its own feed items. The cross-source connection ("train strike affects your commute") happens in the LLM enhancement layer, not in the source itself.
+**Implementation:** A collection of specialized `FeedSource` nodes, each monitoring a specific external signal. Start with what's closest to existing sources: `freya.tfl` already handles transit — extend it to check for planned strikes/closures (TfL API has this data). Package tracking: a new source (`freya.packages`) that polls tracking APIs (Royal Mail, UPS) given tracking numbers extracted from email (requires email source). News: a source (`freya.news`) that uses a news API (NewsAPI, Google News) filtered by user interests from the preference store. Each of these is independent and produces its own feed items. The cross-source connection ("train strike affects your commute") happens in the LLM enhancement layer, not in the source itself.
#### Energy Awareness
@@ -852,7 +852,7 @@ Reduces notification fatigue while ensuring important items aren't missed.
The primary interface. This isn't a feed query tool — it's the person you talk to.
-The user should be able to ask AELIS anything they'd ask a knowledgeable friend. Some questions are about their data. Most aren't.
+The user should be able to ask FREYA anything they'd ask a knowledgeable friend. Some questions are about their data. Most aren't.
**About their life (reads from the source graph):**
@@ -885,7 +885,7 @@ This is also where intent extraction happens for the Gentle Follow-up Agent. Eve
#### Web Search
-The backbone for general knowledge. Makes AELIS a person you can ask things, not just a dashboard you look at.
+The backbone for general knowledge. Makes FREYA a person you can ask things, not just a dashboard you look at.
**Reactive (user asks):**
@@ -947,7 +947,7 @@ Handles practical logistics a human assistant would manage.
Combines tasks, calendar, location, and business hours. Groups nearby errands. Warns about deadlines.
-**Implementation:** A `FeedSource` (`aelis.errands`) that depends on a task source (Todoist, Apple Reminders — needs to be built), calendar sources, and location. On each refresh, it queries tasks tagged as errands or with locations, cross-references against calendar free slots and current location, and uses a simple greedy algorithm to suggest optimal windows. Business hours: either hardcode common defaults or use Google Places API for specific venues. For v1, skip route optimization — just identify "you have a gap near this errand's location." The LLM enhancer can phrase the suggestion naturally. Requires a task source to exist first.
+**Implementation:** A `FeedSource` (`freya.errands`) that depends on a task source (Todoist, Apple Reminders — needs to be built), calendar sources, and location. On each refresh, it queries tasks tagged as errands or with locations, cross-references against calendar free slots and current location, and uses a simple greedy algorithm to suggest optimal windows. Business hours: either hardcode common defaults or use Google Places API for specific venues. For v1, skip route optimization — just identify "you have a gap near this errand's location." The LLM enhancer can phrase the suggestion naturally. Requires a task source to exist first.
#### Delegation
@@ -1023,7 +1023,7 @@ These aren't features — they're qualities that run through everything the assi
#### Personality & Voice
-A human assistant has a consistent personality. AELIS needs one too.
+A human assistant has a consistent personality. FREYA needs one too.
The voice should be: warm but not bubbly, concise but not robotic, occasionally witty but never trying too hard. It says "I" not "we." It has opinions when asked ("I'd skip the design sync — you've been to the last 8 and nothing changes") but defers on big decisions.
@@ -1139,7 +1139,7 @@ Expose the source graph to the enhancement layer. Without this, every behavior s
- Add `FeedEnhancement` type and merge logic in `refresh()`
- Remove `priority` from `FeedItem` — ranking is now entirely post-processing
- Add `signals` field to `FeedItem` for source-provided hints (optional urgency, time relevance)
-- Create `packages/aelis-feed-enhancers` for post-processor implementations
+- Create `packages/freya-feed-enhancers` for post-processor implementations
- Add `feed.interact` JSON-RPC method for tap/dismiss/dwell events from client
- Add `memories` table to database schema (user_id, key, value_json, confidence, updated_at, source)
- Add `feed_snapshots` table for routine learning (user_id, items_json, context_json, timestamp)
@@ -1150,10 +1150,10 @@ Expose the source graph to the enhancement layer. Without this, every behavior s
The minimum for "this is an AI assistant."
1. **Personality spec** — write the voice/tone document included in all LLM calls. ~500 tokens. This shapes everything that follows.
-2. **Rule-based post-processors** — `TimeOfDayEnhancer`, `CalendarGroupingEnhancer`, `DeduplicationEnhancer`, silence/"all clear" card logic in `aelis-feed-enhancers`. Pure functions, no external dependencies.
+2. **Rule-based post-processors** — `TimeOfDayEnhancer`, `CalendarGroupingEnhancer`, `DeduplicationEnhancer`, silence/"all clear" card logic in `freya-feed-enhancers`. Pure functions, no external dependencies.
3. **Query Agent** — `query.ask` JSON-RPC method, LLM with tool use, conversation history table. Start with a single model (GPT-4.1 mini or Gemini Flash for cost).
4. **Web Search** — Tavily or Brave Search API wrapper, exposed as an LLM tool. Cache layer with TTL.
-5. **Daily Briefing** — `aelis.briefing` FeedSource, depends on all content sources, runs in morning/evening time windows.
+5. **Daily Briefing** — `freya.briefing` FeedSource, depends on all content sources, runs in morning/evening time windows.
6. **Graceful degradation** — ensure all post-processors and the LLM harness work with any subset of sources connected.
### Phase 2: It Feels Human
@@ -1162,7 +1162,7 @@ The features that make people say "whoa."
7. **LLM Enhancement slow path** — background timer, serializes feed + context into prompt, returns `FeedEnhancement`, caches result. This enables card rewriting, cross-source synthesis, tone adjustment, and ambient personality. Include confidence/uncertainty instructions in the prompt.
8. **User Affinity model** — `UserAffinityEnhancer` post-processor + `feed.interact` event handling. Writes to `memories` table. No LLM.
-9. **Contextual Preparation** — `aelis.preparation` FeedSource, depends on calendar + web search tool. Includes anticipatory logistics and anticipating questions. Cache prep cards per event ID.
+9. **Contextual Preparation** — `freya.preparation` FeedSource, depends on calendar + web search tool. Includes anticipatory logistics and anticipating questions. Cache prep cards per event ID.
10. **Tone & Timing + Temporal Empathy** — post-processor that infers user state, adjusts suppression, sets `notify` flags, holds emotionally heavy items for appropriate windows.
11. **Context Switching Buffers** — rule-based detection of activity transitions, LLM-generated transition cards.
@@ -1172,7 +1172,7 @@ The long-term relationship.
12. **Memory store + decay model** — `memories` table with confidence scores, `last_reinforced` timestamps, nightly decay job. Include in all LLM prompts.
13. **Learning from corrections** — correction extraction as Query Agent side-effect, writes to memory with confidence 1.0.
-14. **Gentle Follow-up** — intent extraction as Query Agent side-effect, `commitments` table, `aelis.followup` FeedSource.
+14. **Gentle Follow-up** — intent extraction as Query Agent side-effect, `commitments` table, `freya.followup` FeedSource.
15. **Routine Learning** — feed snapshot storage, daily summary compression, weekly LLM pattern discovery with dynamic `DiscoveredPattern[]` output.
16. **Social Awareness** — contacts source (CardDAV or Google People API), birthday detection, meeting frequency analysis.
@@ -1181,9 +1181,9 @@ The long-term relationship.
Background intelligence.
17. **Push notification infrastructure** — Expo push notifications, driven by `notify` flag from Tone & Timing processor.
-18. **Ambient Context sources** — extend TfL for planned disruptions, add `aelis.packages` (tracking APIs), add `aelis.news` (news API filtered by interests).
+18. **Ambient Context sources** — extend TfL for planned disruptions, add `freya.packages` (tracking APIs), add `freya.news` (news API filtered by interests).
19. **Energy Awareness + Health Nudges** — rule-based detection (meeting density, sedentary time, late nights), LLM-phrased nudge cards with cooldowns.
-20. **Anomaly Detection** — `aelis.anomaly` FeedSource, meeting time histogram, overlap detection. Mostly rule-based.
+20. **Anomaly Detection** — `freya.anomaly` FeedSource, meeting time histogram, overlap detection. Mostly rule-based.
21. **Cross-Source Reasoning** — handled by LLM enhancement layer with explicit cross-source instructions in prompt.
22. **Celebration** — positive pattern detection in LLM harness, comparison against daily summary baselines, one per day max.
23. **Seasonal Awareness** — static annual events dataset per locale + personal annual patterns from 6+ months of summaries.
@@ -1192,11 +1192,11 @@ Background intelligence.
The full PA experience.
-24. **Task source** — new `aelis.tasks` FeedSource (Todoist API or Apple Reminders). Required for Errand & Logistics.
+24. **Task source** — new `freya.tasks` FeedSource (Todoist API or Apple Reminders). Required for Errand & Logistics.
25. **Decision Support** — conflict detection (rule-based) + comparison card generation (LLM). Structured comparison data for client rendering.
26. **Micro-Moments** — gap detection post-processor + LLM micro-briefing generation for 2-10 minute windows.
27. **Financial Awareness** — financial event extraction from email, `financial_events` table, 48-hour reminder post-processor.
-28. **Errand & Logistics** — `aelis.errands` FeedSource, depends on tasks + calendar + location. Greedy gap-matching algorithm.
+28. **Errand & Logistics** — `freya.errands` FeedSource, depends on tasks + calendar + location. Greedy gap-matching algorithm.
29. **Actions** — extend OAuth scopes for write access, add `actions` field to `FeedItem`, `feed.action` JSON-RPC method, confirmation flow.
30. **Delegation** — extend Query Agent with write tools, `delegation.confirm` notification, confirmation UI on client.
@@ -1222,7 +1222,7 @@ The full PA experience.
- Feed snapshot storage cost at scale: compress after N days, or summarize and discard?
- System prompt size: as behaviors accumulate, the prompt grows. When does it need to be split or dynamically composed?
- Personality consistency: how to ensure the voice stays consistent across enhancement runs and query responses?
-- Health nudge liability: should AELIS ever comment on health-related patterns, or is that too risky?
+- Health nudge liability: should FREYA ever comment on health-related patterns, or is that too risky?
- Celebration frequency: how often is encouraging vs. patronizing?
- Emotional weight classification: can the LLM reliably assess how stressful a piece of information is?
- Multi-device: how to sync seen-item state and hold queues across phone, laptop, watch?
diff --git a/docs/architecture-draft.md b/docs/architecture-draft.md
index 7c89e3f..abfee93 100644
--- a/docs/architecture-draft.md
+++ b/docs/architecture-draft.md
@@ -1,10 +1,10 @@
-# AELIS Architecture Draft
+# FREYA Architecture Draft
> This is a working draft from initial architecture discussions. Not final documentation.
## Overview
-AELIS is an AI-powered personal assistant. The core aggregates data from various sources and compiles a feed of contextually relevant items - similar to Google Now. The feed shows users useful information based on their current context (date, time, location).
+FREYA is an AI-powered personal assistant. The core aggregates data from various sources and compiles a feed of contextually relevant items - similar to Google Now. The feed shows users useful information based on their current context (date, time, location).
Examples of feed items:
@@ -26,7 +26,7 @@ Examples of feed items:
┌─────────────────────────────────────────────────────────────┐
│ Backend │
│ ┌─────────────┐ ┌─────────────┐ │
-│ │ aelis-core │ │ Sources │ │
+│ │ freya-core │ │ Sources │ │
│ │ │ │ (plugins) │ │
│ │ - FeedEngine│◄───│ - Calendar │ │
│ │ - Context │ │ - Weather │ │
@@ -51,7 +51,7 @@ Examples of feed items:
└─────────────────────────────────────────────────────────────┘
```
-## Core Package (`aelis-core`)
+## Core Package (`freya-core`)
The core is responsible for:
@@ -64,7 +64,7 @@ The core is responsible for:
- **Context**: Time and location (with accuracy) passed to all sources. Sources can contribute to context (e.g., location source provides coordinates, weather source provides conditions).
- **FeedItem**: Has an ID (source-generated, stable), type, timestamp, JSON-serializable data, optional actions, an optional `ui` tree, and optional `slots` for LLM-fillable content.
-- **FeedSource**: Interface that first and third parties implement to provide context, feed items, and actions. Uses reverse-domain IDs (e.g., `aelis.weather`, `com.spotify`).
+- **FeedSource**: Interface that first and third parties implement to provide context, feed items, and actions. Uses reverse-domain IDs (e.g., `freya.weather`, `com.spotify`).
- **FeedEngine**: Orchestrates sources respecting their dependency graph, runs independent sources in parallel, returns items and any errors. Routes action execution to the correct source.
## Data Sources
@@ -113,7 +113,7 @@ The UI for feed items is **server-driven**. Sources describe how their items loo
### Two tiers of UI
- **Server-driven (default):** Any source can return a `ui` tree. Covers most cards — weather, tasks, alerts, package tracking, news, etc. Simple interactions go through source actions. This is the default path for both first-party and third-party sources.
-- **Bespoke native:** For cards that need rich client interaction (gestures, animations, real-time updates), a native React Native component is registered in the json-render component map and referenced by type. Third parties that need this level of richness work with the AELIS team to get it integrated.
+- **Bespoke native:** For cards that need rich client interaction (gestures, animations, real-time updates), a native React Native component is registered in the json-render component map and referenced by type. Third parties that need this level of richness work with the FREYA team to get it integrated.
### Why server-driven
diff --git a/docs/backend-service-architecture-spec.md b/docs/backend-service-architecture-spec.md
index ed385e6..886a3f6 100644
--- a/docs/backend-service-architecture-spec.md
+++ b/docs/backend-service-architecture-spec.md
@@ -32,7 +32,7 @@ server.ts
## Scope
-**Backend only** (`apps/aelis-backend`). No changes to `aelis-core` or source packages (`packages/aelis-source-*`). The `FeedSource` interface and source implementations remain unchanged.
+**Backend only** (`apps/freya-backend`). No changes to `freya-core` or source packages (`packages/freya-source-*`). The `FeedSource` interface and source implementations remain unchanged.
## Architectural Options
diff --git a/docs/backend-spec.md b/docs/backend-spec.md
index 17d5d59..9245bff 100644
--- a/docs/backend-spec.md
+++ b/docs/backend-spec.md
@@ -1,8 +1,8 @@
-# AELIS Backend Specification
+# FREYA Backend Specification
## Problem Statement
-AELIS needs a backend service that manages per-user FeedEngine instances and delivers real-time feed updates to clients. The backend must handle authentication, maintain WebSocket connections for live updates, and accept context updates (like location) that trigger feed recalculations.
+FREYA needs a backend service that manages per-user FeedEngine instances and delivers real-time feed updates to clients. The backend must handle authentication, maintain WebSocket connections for live updates, and accept context updates (like location) that trigger feed recalculations.
## Requirements
@@ -105,7 +105,7 @@ All WebSocket communication uses JSON-RPC 2.0.
### Phase 1: Project Setup
-1. Create `apps/aelis-backend` with Hono
+1. Create `apps/freya-backend` with Hono
2. Configure TypeScript, add dependencies (hono, better-auth, postgres driver)
3. Set up database connection and BetterAuth
@@ -152,7 +152,7 @@ All WebSocket communication uses JSON-RPC 2.0.
## Package Structure
```
-apps/aelis-backend/
+apps/freya-backend/
├── package.json
├── src/
│ ├── index.ts # Entry point, Hono app
@@ -177,10 +177,10 @@ apps/aelis-backend/
"hono": "^4",
"better-auth": "^1",
"postgres": "^3",
- "@aelis/core": "workspace:*",
- "@aelis/source-location": "workspace:*",
- "@aelis/source-weatherkit": "workspace:*",
- "@aelis/data-source-tfl": "workspace:*"
+ "@freya/core": "workspace:*",
+ "@freya/source-location": "workspace:*",
+ "@freya/source-weatherkit": "workspace:*",
+ "@freya/data-source-tfl": "workspace:*"
}
}
```
diff --git a/docs/db-persistence-layer-spec.md b/docs/db-persistence-layer-spec.md
index 49512ee..09deae1 100644
--- a/docs/db-persistence-layer-spec.md
+++ b/docs/db-persistence-layer-spec.md
@@ -2,7 +2,7 @@
## Problem Statement
-AELIS currently hardcodes the same set of feed sources for every user. Source configuration (TFL lines, weather units, calendar IDs, etc.) and credentials (OAuth tokens) are not persisted. Users cannot customize which sources appear in their feed or configure source-specific settings.
+FREYA currently hardcodes the same set of feed sources for every user. Source configuration (TFL lines, weather units, calendar IDs, etc.) and credentials (OAuth tokens) are not persisted. Users cannot customize which sources appear in their feed or configure source-specific settings.
The backend uses a raw `pg` Pool for Better Auth and has no ORM. We need a persistence layer that stores per-user source configuration and credentials, using Drizzle ORM with Bun.sql as the Postgres driver.
@@ -28,7 +28,7 @@ A `user_sources` table stores per-user source state:
| ------------- | --------------------- | -------------------------------------------------------------- |
| `id` | `uuid` PK | Row ID |
| `user_id` | `text` FK → `user.id` | Owner |
-| `source_id` | `text` | Source identifier (e.g., `aelis.tfl`, `aelis.weather`) |
+| `source_id` | `text` | Source identifier (e.g., `freya.tfl`, `freya.weather`) |
| `enabled` | `boolean` | Whether this source is active in the user's feed |
| `config` | `jsonb` | Source-specific configuration (validated by source at runtime) |
| `credentials` | `bytea` | Encrypted OAuth tokens / secrets (AES-256-GCM) |
@@ -52,9 +52,9 @@ When a new user is created, seed `user_sources` rows for default sources:
| Source | Default config |
| ---------------- | ----------------------------------------------------------- |
-| `aelis.location` | `{}` |
-| `aelis.weather` | `{ "units": "metric", "hourlyLimit": 12, "dailyLimit": 7 }` |
-| `aelis.tfl` | `{ "lines": }` |
+| `freya.location` | `{}` |
+| `freya.weather` | `{ "units": "metric", "hourlyLimit": 12, "dailyLimit": 7 }` |
+| `freya.tfl` | `{ "lines": }` |
- Seeding happens via a Better Auth `after` hook on user creation, or via application-level logic after signup.
- Sources requiring credentials (Google Calendar, CalDAV) are **not** enabled by default — they require the user to connect an account first.
@@ -79,14 +79,14 @@ class TflSourceProvider implements FeedSourceProvider {
.where(
and(
eq(userSources.userId, userId),
- eq(userSources.sourceId, "aelis.tfl"),
+ eq(userSources.sourceId, "freya.tfl"),
eq(userSources.enabled, true),
),
)
.limit(1)
if (!row[0]) {
- throw new SourceDisabledError("aelis.tfl", userId)
+ throw new SourceDisabledError("freya.tfl", userId)
}
const config = tflSourceConfig(row[0].config ?? {})
@@ -104,8 +104,8 @@ No interface changes are needed — the existing async `FeedSourceProvider` and
### 7. Drizzle Kit migrations
- Use `drizzle-kit` for schema migrations
-- `drizzle.config.ts` at `apps/aelis-backend/drizzle.config.ts`
-- Migration files stored in `apps/aelis-backend/drizzle/`
+- `drizzle.config.ts` at `apps/freya-backend/drizzle.config.ts`
+- Migration files stored in `apps/freya-backend/drizzle/`
- Scripts in `package.json`: `db:generate`, `db:migrate`, `db:studio`
## Acceptance Criteria
@@ -190,7 +190,7 @@ _`FeedSourceProvider` is already async and `UserSessionManager.getOrCreate` alre
## File Structure (new/modified)
```
-apps/aelis-backend/
+apps/freya-backend/
├── drizzle.config.ts # NEW
├── drizzle/ # NEW — migration files
├── src/
diff --git a/docs/feed-source-actions-spec.md b/docs/feed-source-actions-spec.md
index 2774ab7..462f8b8 100644
--- a/docs/feed-source-actions-spec.md
+++ b/docs/feed-source-actions-spec.md
@@ -6,7 +6,7 @@
## Scope
-**`aelis-core` only.** Add action support to `FeedSource` and `FeedItem`. No changes to existing fields or methods — purely additive.
+**`freya-core` only.** Add action support to `FeedSource` and `FeedItem`. No changes to existing fields or methods — purely additive.
## Design
@@ -16,7 +16,7 @@ MCP was considered. It doesn't fit because:
- MCP resources don't accept input context (FeedSource needs accumulated context as input)
- MCP has no structured feed items (priority, timestamp, type)
-- MCP's isolation model conflicts with AELIS's dependency graph
+- MCP's isolation model conflicts with FREYA's dependency graph
- Adding these as MCP extensions would mean the extensions are the entire protocol
The interface is designed to be **protocol-compatible** — a future `RemoteFeedSource` adapter can map each field/method to a JSON-RPC operation without changing the interface:
@@ -35,20 +35,20 @@ No interface changes needed when the transport layer is built.
### Source ID & Action ID Convention
-Source IDs use reverse domain notation. Built-in sources use `aelis.`. Third parties use their own domain.
+Source IDs use reverse domain notation. Built-in sources use `freya.`. Third parties use their own domain.
Action IDs are descriptive verb-noun pairs in kebab-case, scoped to their source. The globally unique form is `/`.
| Source ID | Action IDs |
| ---------------- | -------------------------------------------------------------- |
-| `aelis.location` | `update-location` (migrated from `pushLocation()`) |
-| `aelis.tfl` | `set-lines-of-interest` (migrated from `setLinesOfInterest()`) |
-| `aelis.weather` | _(none)_ |
+| `freya.location` | `update-location` (migrated from `pushLocation()`) |
+| `freya.tfl` | `set-lines-of-interest` (migrated from `setLinesOfInterest()`) |
+| `freya.weather` | _(none)_ |
| `com.spotify` | `play-track`, `pause-playback`, `skip-track`, `like-track` |
-| `aelis.calendar` | `rsvp`, `create-event` |
+| `freya.calendar` | `rsvp`, `create-event` |
| `com.todoist` | `complete-task`, `snooze-task` |
-This means existing source packages need their `id` updated (e.g., `"location"` → `"aelis.location"`).
+This means existing source packages need their `id` updated (e.g., `"location"` → `"freya.location"`).
### New Types
@@ -278,17 +278,17 @@ class SpotifySource implements FeedSource {
## Implementation Steps
-1. Create `action.ts` in `aelis-core/src` with `ActionDefinition`, `ActionResult`, `ItemAction`
+1. Create `action.ts` in `freya-core/src` with `ActionDefinition`, `ActionResult`, `ItemAction`
2. Add optional `actions` and `executeAction` to `FeedSource` interface in `feed-source.ts`
3. Add optional `actions` field to `FeedItem` interface in `feed.ts`
4. Add `executeAction()` and `listActions()` to `FeedEngine` in `feed-engine.ts`
-5. Export new types from `aelis-core/index.ts`
+5. Export new types from `freya-core/index.ts`
6. Add tests for `FeedEngine.executeAction()` routing
7. Add tests for `FeedEngine.listActions()` aggregation
8. Add tests for error cases (unknown action, unknown source, source without actions)
-9. Update source IDs to reverse-domain format (`"location"` → `"aelis.location"`, etc.) across all source packages
-10. Migrate `LocationSource.pushLocation()` → action `update-location` on `aelis.location`
-11. Migrate `TflSource.setLinesOfInterest()` → action `set-lines-of-interest` on `aelis.tfl`
+9. Update source IDs to reverse-domain format (`"location"` → `"freya.location"`, etc.) across all source packages
+10. Migrate `LocationSource.pushLocation()` → action `update-location` on `freya.location`
+11. Migrate `TflSource.setLinesOfInterest()` → action `set-lines-of-interest` on `freya.tfl`
12. Add `async listActions() { return {} }` and no-op `executeAction()` to sources without actions (WeatherSource, GoogleCalendarSource, AppleCalendarSource)
13. Update any tests or code referencing old source IDs
14. Run all tests to confirm nothing breaks
diff --git a/package.json b/package.json
index f709723..f0d8081 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "aelis",
+ "name": "freya",
"private": true,
"workspaces": [
"packages/*",
@@ -7,9 +7,9 @@
],
"type": "module",
"scripts": {
- "expo": "cd apps/aelis-client && bun run start",
- "drizzle-studio": "TS_IP=$(tailscale ip -4); echo \"Drizzle Studio: https://local.drizzle.studio/?host=${TS_IP}&port=4983\"; cd apps/aelis-backend && bunx drizzle-kit studio --host 0.0.0.0 --port 4983",
- "aelis-backend": "TS_IP=$(tailscale ip -4); echo \"Aelis Backend: http://${TS_IP}:3000\"; echo \"\"; echo \"------------------ Bun Debugger ------------------\"; echo \"https://debug.bun.sh/#${TS_IP}:6499\"; echo \"------------------ Bun Debugger ------------------\"; echo \"\"; cd apps/aelis-backend && bun run dev",
+ "expo": "cd apps/freya-client && bun run start",
+ "drizzle-studio": "TS_IP=$(tailscale ip -4); echo \"Drizzle Studio: https://local.drizzle.studio/?host=${TS_IP}&port=4983\"; cd apps/freya-backend && bunx drizzle-kit studio --host 0.0.0.0 --port 4983",
+ "freya-backend": "TS_IP=$(tailscale ip -4); echo \"Freya Backend: http://${TS_IP}:3000\"; echo \"\"; echo \"------------------ Bun Debugger ------------------\"; echo \"https://debug.bun.sh/#${TS_IP}:6499\"; echo \"------------------ Bun Debugger ------------------\"; echo \"\"; cd apps/freya-backend && bun run dev",
"admin-dashboard": "TS_IP=$(tailscale ip -4); echo \"Admin Dashboard: http://${TS_IP}:5174\"; cd apps/admin-dashboard && bun run dev --host 0.0.0.0",
"test": "bun run --filter '*' test",
"lint": "oxlint .",
diff --git a/packages/aelis-feed-enhancers/package.json b/packages/aelis-feed-enhancers/package.json
deleted file mode 100644
index 39a37d0..0000000
--- a/packages/aelis-feed-enhancers/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "@aelis/feed-enhancers",
- "version": "0.0.0",
- "type": "module",
- "main": "src/index.ts",
- "types": "src/index.ts",
- "scripts": {
- "test": "bun test src/"
- },
- "dependencies": {
- "@aelis/core": "workspace:*",
- "@aelis/source-caldav": "workspace:*",
- "@aelis/source-google-calendar": "workspace:*",
- "@aelis/source-tfl": "workspace:*",
- "@aelis/source-weatherkit": "workspace:*"
- }
-}
diff --git a/packages/aelis-source-google-calendar/src/calendar-context.ts b/packages/aelis-source-google-calendar/src/calendar-context.ts
deleted file mode 100644
index 9543c1c..0000000
--- a/packages/aelis-source-google-calendar/src/calendar-context.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { ContextKey } from "@aelis/core"
-
-import { contextKey } from "@aelis/core"
-
-export interface NextEvent {
- title: string
- startTime: Date
- endTime: Date
- minutesUntilStart: number
- location: string | null
-}
-
-export const NextEventKey: ContextKey = contextKey("aelis.google-calendar", "nextEvent")
diff --git a/packages/aelis-components/package.json b/packages/freya-components/package.json
similarity index 87%
rename from packages/aelis-components/package.json
rename to packages/freya-components/package.json
index dd379d3..dfab219 100644
--- a/packages/aelis-components/package.json
+++ b/packages/freya-components/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/components",
+ "name": "@freya/components",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
diff --git a/packages/aelis-components/src/button.ts b/packages/freya-components/src/button.ts
similarity index 100%
rename from packages/aelis-components/src/button.ts
rename to packages/freya-components/src/button.ts
diff --git a/packages/aelis-components/src/components.test.tsx b/packages/freya-components/src/components.test.tsx
similarity index 100%
rename from packages/aelis-components/src/components.test.tsx
rename to packages/freya-components/src/components.test.tsx
diff --git a/packages/aelis-components/src/feed-card.ts b/packages/freya-components/src/feed-card.ts
similarity index 100%
rename from packages/aelis-components/src/feed-card.ts
rename to packages/freya-components/src/feed-card.ts
diff --git a/packages/aelis-components/src/index.ts b/packages/freya-components/src/index.ts
similarity index 100%
rename from packages/aelis-components/src/index.ts
rename to packages/freya-components/src/index.ts
diff --git a/packages/aelis-components/src/monospace-text.ts b/packages/freya-components/src/monospace-text.ts
similarity index 100%
rename from packages/aelis-components/src/monospace-text.ts
rename to packages/freya-components/src/monospace-text.ts
diff --git a/packages/aelis-components/src/sans-serif-text.ts b/packages/freya-components/src/sans-serif-text.ts
similarity index 100%
rename from packages/aelis-components/src/sans-serif-text.ts
rename to packages/freya-components/src/sans-serif-text.ts
diff --git a/packages/aelis-components/src/serif-text.ts b/packages/freya-components/src/serif-text.ts
similarity index 100%
rename from packages/aelis-components/src/serif-text.ts
rename to packages/freya-components/src/serif-text.ts
diff --git a/packages/aelis-components/tsconfig.json b/packages/freya-components/tsconfig.json
similarity index 100%
rename from packages/aelis-components/tsconfig.json
rename to packages/freya-components/tsconfig.json
diff --git a/packages/aelis-core/README.md b/packages/freya-core/README.md
similarity index 94%
rename from packages/aelis-core/README.md
rename to packages/freya-core/README.md
index 1d7e2e8..d62ee14 100644
--- a/packages/aelis-core/README.md
+++ b/packages/freya-core/README.md
@@ -1,6 +1,6 @@
-# @aelis/core
+# @freya/core
-Core orchestration layer for AELIS feed reconciliation.
+Core orchestration layer for FREYA feed reconciliation.
## Overview
@@ -63,7 +63,7 @@ A source may:
Each package exports typed context keys for type-safe access:
```ts
-import { contextKey, type ContextKey } from "@aelis/core"
+import { contextKey, type ContextKey } from "@freya/core"
interface Location {
lat: number
@@ -78,7 +78,7 @@ export const LocationKey: ContextKey = contextKey("location")
### Define a Context-Only Source
```ts
-import type { FeedSource } from "@aelis/core"
+import type { FeedSource } from "@freya/core"
const locationSource: FeedSource = {
id: "location",
@@ -104,8 +104,8 @@ const locationSource: FeedSource = {
### Define a Source with Dependencies
```ts
-import type { FeedSource, FeedItem } from "@aelis/core"
-import { contextValue } from "@aelis/core"
+import type { FeedSource, FeedItem } from "@freya/core"
+import { contextValue } from "@freya/core"
type WeatherItem = FeedItem<"weather", { temp: number; condition: string }>
diff --git a/packages/aelis-core/package.json b/packages/freya-core/package.json
similarity index 91%
rename from packages/aelis-core/package.json
rename to packages/freya-core/package.json
index 7abee30..b2a9775 100644
--- a/packages/aelis-core/package.json
+++ b/packages/freya-core/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/core",
+ "name": "@freya/core",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
diff --git a/packages/aelis-core/src/action.ts b/packages/freya-core/src/action.ts
similarity index 93%
rename from packages/aelis-core/src/action.ts
rename to packages/freya-core/src/action.ts
index b26b7b1..a1f34f4 100644
--- a/packages/aelis-core/src/action.ts
+++ b/packages/freya-core/src/action.ts
@@ -5,7 +5,7 @@ import type { StandardSchemaV1 } from "@standard-schema/spec"
*
* Action IDs use descriptive verb-noun kebab-case (e.g., "update-location", "play-track").
* Combined with the source's reverse-domain ID, they form a globally unique identifier:
- * `/` (e.g., "aelis.location/update-location").
+ * `/` (e.g., "freya.location/update-location").
*/
export class UnknownActionError extends Error {
readonly actionId: string
diff --git a/packages/aelis-core/src/context-bridge.ts b/packages/freya-core/src/context-bridge.ts
similarity index 100%
rename from packages/aelis-core/src/context-bridge.ts
rename to packages/freya-core/src/context-bridge.ts
diff --git a/packages/aelis-core/src/context-provider.ts b/packages/freya-core/src/context-provider.ts
similarity index 100%
rename from packages/aelis-core/src/context-provider.ts
rename to packages/freya-core/src/context-provider.ts
diff --git a/packages/aelis-core/src/context.test.ts b/packages/freya-core/src/context.test.ts
similarity index 82%
rename from packages/aelis-core/src/context.test.ts
rename to packages/freya-core/src/context.test.ts
index 2ef4d45..4cf2ccf 100644
--- a/packages/aelis-core/src/context.test.ts
+++ b/packages/freya-core/src/context.test.ts
@@ -12,8 +12,8 @@ interface NextEvent {
title: string
}
-const WeatherKey: ContextKey = contextKey("aelis.weather", "current")
-const NextEventKey: ContextKey = contextKey("aelis.google-calendar", "nextEvent")
+const WeatherKey: ContextKey = contextKey("freya.weather", "current")
+const NextEventKey: ContextKey = contextKey("freya.google-calendar", "nextEvent")
describe("Context", () => {
describe("get", () => {
@@ -66,10 +66,10 @@ describe("Context", () => {
})
test("prefix match returns multiple instances", () => {
- const workKey = contextKey("aelis.google-calendar", "nextEvent", {
+ const workKey = contextKey("freya.google-calendar", "nextEvent", {
account: "work",
})
- const personalKey = contextKey("aelis.google-calendar", "nextEvent", {
+ const personalKey = contextKey("freya.google-calendar", "nextEvent", {
account: "personal",
})
@@ -79,7 +79,7 @@ describe("Context", () => {
[personalKey, { title: "Dentist" }],
])
- const prefix = contextKey("aelis.google-calendar", "nextEvent")
+ const prefix = contextKey("freya.google-calendar", "nextEvent")
const results = ctx.find(prefix)
expect(results).toHaveLength(2)
@@ -88,8 +88,8 @@ describe("Context", () => {
})
test("prefix match includes exact match and longer keys", () => {
- const baseKey = contextKey("aelis.google-calendar", "nextEvent")
- const instanceKey = contextKey("aelis.google-calendar", "nextEvent", {
+ const baseKey = contextKey("freya.google-calendar", "nextEvent")
+ const instanceKey = contextKey("freya.google-calendar", "nextEvent", {
account: "work",
})
@@ -104,8 +104,8 @@ describe("Context", () => {
})
test("does not match keys that share a string prefix but differ at segment boundary", () => {
- const keyA = contextKey("aelis.calendar", "next")
- const keyB = contextKey("aelis.calendar", "nextEvent")
+ const keyA = contextKey("freya.calendar", "next")
+ const keyB = contextKey("freya.calendar", "nextEvent")
const ctx = new Context()
ctx.set([
@@ -137,20 +137,20 @@ describe("Context", () => {
test("single-segment prefix matches all keys starting with that segment", () => {
const ctx = new Context()
ctx.set([
- [contextKey("aelis.weather", "current"), { temperature: 20 }],
- [contextKey("aelis.weather", "forecast"), { high: 25 }],
- [contextKey("aelis.calendar", "nextEvent"), { title: "Meeting" }],
+ [contextKey("freya.weather", "current"), { temperature: 20 }],
+ [contextKey("freya.weather", "forecast"), { high: 25 }],
+ [contextKey("freya.calendar", "nextEvent"), { title: "Meeting" }],
])
- const results = ctx.find(contextKey("aelis.weather"))
+ const results = ctx.find(contextKey("freya.weather"))
expect(results).toHaveLength(2)
})
test("does not match shorter keys", () => {
const ctx = new Context()
- ctx.set([[contextKey("aelis.weather"), "short"]])
+ ctx.set([[contextKey("freya.weather"), "short"]])
- const results = ctx.find(contextKey("aelis.weather", "current"))
+ const results = ctx.find(contextKey("freya.weather", "current"))
expect(results).toHaveLength(0)
})
diff --git a/packages/aelis-core/src/context.ts b/packages/freya-core/src/context.ts
similarity index 98%
rename from packages/aelis-core/src/context.ts
rename to packages/freya-core/src/context.ts
index c2cf12d..ef20b62 100644
--- a/packages/aelis-core/src/context.ts
+++ b/packages/freya-core/src/context.ts
@@ -2,7 +2,7 @@
* Tuple-keyed context system inspired by React Query's query keys.
*
* Context keys are arrays that form a hierarchy. Sources write to specific
- * keys (e.g., ["aelis.google-calendar", "nextEvent", { account: "work" }])
+ * keys (e.g., ["freya.google-calendar", "nextEvent", { account: "work" }])
* and consumers can query by exact match or prefix match to get all values
* of a given type across source instances.
*/
diff --git a/packages/aelis-core/src/data-source.ts b/packages/freya-core/src/data-source.ts
similarity index 96%
rename from packages/aelis-core/src/data-source.ts
rename to packages/freya-core/src/data-source.ts
index f001640..bafa7d9 100644
--- a/packages/aelis-core/src/data-source.ts
+++ b/packages/freya-core/src/data-source.ts
@@ -17,7 +17,7 @@ import type { FeedItem } from "./feed"
* const data = await fetchWeather(location)
* return [{
* id: `weather-${Date.now()}`,
- * sourceId: "aelis.weather",
+ * sourceId: "freya.weather",
* type: this.type,
* timestamp: context.time,
* data: { temp: data.temperature },
diff --git a/packages/aelis-core/src/feed-controller.ts b/packages/freya-core/src/feed-controller.ts
similarity index 100%
rename from packages/aelis-core/src/feed-controller.ts
rename to packages/freya-core/src/feed-controller.ts
diff --git a/packages/aelis-core/src/feed-engine.test.ts b/packages/freya-core/src/feed-engine.test.ts
similarity index 100%
rename from packages/aelis-core/src/feed-engine.test.ts
rename to packages/freya-core/src/feed-engine.test.ts
diff --git a/packages/aelis-core/src/feed-engine.ts b/packages/freya-core/src/feed-engine.ts
similarity index 100%
rename from packages/aelis-core/src/feed-engine.ts
rename to packages/freya-core/src/feed-engine.ts
diff --git a/packages/aelis-core/src/feed-post-processor.test.ts b/packages/freya-core/src/feed-post-processor.test.ts
similarity index 99%
rename from packages/aelis-core/src/feed-post-processor.test.ts
rename to packages/freya-core/src/feed-post-processor.test.ts
index 7982e98..03a871a 100644
--- a/packages/aelis-core/src/feed-post-processor.test.ts
+++ b/packages/freya-core/src/feed-post-processor.test.ts
@@ -29,13 +29,13 @@ type WeatherItem = FeedItem<"weather", { temp: number }>
type CalendarItem = FeedItem<"calendar", { title: string }>
function weatherItem(id: string, temp: number): WeatherItem {
- return { id, sourceId: "aelis.weather", type: "weather", timestamp: new Date(), data: { temp } }
+ return { id, sourceId: "freya.weather", type: "weather", timestamp: new Date(), data: { temp } }
}
function calendarItem(id: string, title: string): CalendarItem {
return {
id,
- sourceId: "aelis.calendar",
+ sourceId: "freya.calendar",
type: "calendar",
timestamp: new Date(),
data: { title },
@@ -48,7 +48,7 @@ function calendarItem(id: string, title: string): CalendarItem {
function createWeatherSource(items: WeatherItem[]) {
return {
- id: "aelis.weather",
+ id: "freya.weather",
...noActions,
async fetchContext() {
return null
@@ -61,7 +61,7 @@ function createWeatherSource(items: WeatherItem[]) {
function createCalendarSource(items: CalendarItem[]) {
return {
- id: "aelis.calendar",
+ id: "freya.calendar",
...noActions,
async fetchContext() {
return null
@@ -486,7 +486,7 @@ describe("FeedPostProcessor", () => {
let triggerUpdate: ((entries: readonly ContextEntry[]) => void) | null = null
const source: FeedSource = {
- id: "aelis.reactive",
+ id: "freya.reactive",
...noActions,
async fetchContext() {
return null
@@ -528,7 +528,7 @@ describe("FeedPostProcessor", () => {
let triggerItemsUpdate: ((items: FeedItem[]) => void) | null = null
const source: FeedSource = {
- id: "aelis.reactive",
+ id: "freya.reactive",
...noActions,
async fetchContext() {
return null
diff --git a/packages/aelis-core/src/feed-post-processor.ts b/packages/freya-core/src/feed-post-processor.ts
similarity index 100%
rename from packages/aelis-core/src/feed-post-processor.ts
rename to packages/freya-core/src/feed-post-processor.ts
diff --git a/packages/aelis-core/src/feed-source.test.ts b/packages/freya-core/src/feed-source.test.ts
similarity index 100%
rename from packages/aelis-core/src/feed-source.test.ts
rename to packages/freya-core/src/feed-source.test.ts
diff --git a/packages/aelis-core/src/feed-source.ts b/packages/freya-core/src/feed-source.ts
similarity index 98%
rename from packages/aelis-core/src/feed-source.ts
rename to packages/freya-core/src/feed-source.ts
index eae7ed7..7e248a1 100644
--- a/packages/aelis-core/src/feed-source.ts
+++ b/packages/freya-core/src/feed-source.ts
@@ -9,7 +9,7 @@ import type { FeedItem } from "./feed"
* it depends on, and the graph ensures dependencies are resolved before
* dependents run.
*
- * Source IDs use reverse domain notation. Built-in sources use `aelis.`,
+ * Source IDs use reverse domain notation. Built-in sources use `freya.`,
* third parties use their own domain (e.g., `com.spotify`).
*
* Every method maps to a protocol operation for remote source support:
@@ -24,7 +24,7 @@ import type { FeedItem } from "./feed"
* @example
* ```ts
* const locationSource: FeedSource = {
- * id: "aelis.location",
+ * id: "freya.location",
* async listActions() { return { "update-location": { id: "update-location" } } },
* async executeAction(actionId) { throw new UnknownActionError(actionId) },
* async fetchContext() { ... },
diff --git a/packages/aelis-core/src/feed.test.ts b/packages/freya-core/src/feed.test.ts
similarity index 97%
rename from packages/aelis-core/src/feed.test.ts
rename to packages/freya-core/src/feed.test.ts
index 7e0893e..96ced2b 100644
--- a/packages/aelis-core/src/feed.test.ts
+++ b/packages/freya-core/src/feed.test.ts
@@ -18,7 +18,7 @@ describe("FeedItem slots", () => {
test("FeedItem with unfilled slots", () => {
const item: FeedItem<"weather", { temp: number }> = {
id: "weather-1",
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: "weather",
timestamp: new Date(),
data: { temp: 18 },
@@ -43,7 +43,7 @@ describe("FeedItem slots", () => {
test("FeedItem with filled slots", () => {
const item: FeedItem<"weather", { temp: number }> = {
id: "weather-1",
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: "weather",
timestamp: new Date(),
data: { temp: 18 },
diff --git a/packages/aelis-core/src/feed.ts b/packages/freya-core/src/feed.ts
similarity index 98%
rename from packages/aelis-core/src/feed.ts
rename to packages/freya-core/src/feed.ts
index ba8c848..3b53708 100644
--- a/packages/aelis-core/src/feed.ts
+++ b/packages/freya-core/src/feed.ts
@@ -48,7 +48,7 @@ export interface Slot {
*
* const item: WeatherItem = {
* id: "weather-123",
- * sourceId: "aelis.weatherkit",
+ * sourceId: "freya.weatherkit",
* type: "weather",
* timestamp: new Date(),
* data: { temp: 18, condition: "cloudy" },
diff --git a/packages/aelis-core/src/index.ts b/packages/freya-core/src/index.ts
similarity index 100%
rename from packages/aelis-core/src/index.ts
rename to packages/freya-core/src/index.ts
diff --git a/packages/aelis-core/src/reconciler.ts b/packages/freya-core/src/reconciler.ts
similarity index 100%
rename from packages/aelis-core/src/reconciler.ts
rename to packages/freya-core/src/reconciler.ts
diff --git a/packages/freya-feed-enhancers/package.json b/packages/freya-feed-enhancers/package.json
new file mode 100644
index 0000000..356b450
--- /dev/null
+++ b/packages/freya-feed-enhancers/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@freya/feed-enhancers",
+ "version": "0.0.0",
+ "type": "module",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "scripts": {
+ "test": "bun test src/"
+ },
+ "dependencies": {
+ "@freya/core": "workspace:*",
+ "@freya/source-caldav": "workspace:*",
+ "@freya/source-google-calendar": "workspace:*",
+ "@freya/source-tfl": "workspace:*",
+ "@freya/source-weatherkit": "workspace:*"
+ }
+}
diff --git a/packages/aelis-feed-enhancers/src/index.ts b/packages/freya-feed-enhancers/src/index.ts
similarity index 100%
rename from packages/aelis-feed-enhancers/src/index.ts
rename to packages/freya-feed-enhancers/src/index.ts
diff --git a/packages/aelis-feed-enhancers/src/time-of-day-enhancer.test.ts b/packages/freya-feed-enhancers/src/time-of-day-enhancer.test.ts
similarity index 97%
rename from packages/aelis-feed-enhancers/src/time-of-day-enhancer.test.ts
rename to packages/freya-feed-enhancers/src/time-of-day-enhancer.test.ts
index 1ce9c9a..6f0be28 100644
--- a/packages/aelis-feed-enhancers/src/time-of-day-enhancer.test.ts
+++ b/packages/freya-feed-enhancers/src/time-of-day-enhancer.test.ts
@@ -1,10 +1,10 @@
-import type { FeedItem, FeedItemSignals } from "@aelis/core"
+import type { FeedItem, FeedItemSignals } from "@freya/core"
-import { Context, TimeRelevance } from "@aelis/core"
-import { CalDavFeedItemType } from "@aelis/source-caldav"
-import { CalendarFeedItemType } from "@aelis/source-google-calendar"
-import { TflFeedItemType } from "@aelis/source-tfl"
-import { WeatherFeedItemType } from "@aelis/source-weatherkit"
+import { Context, TimeRelevance } from "@freya/core"
+import { CalDavFeedItemType } from "@freya/source-caldav"
+import { CalendarFeedItemType } from "@freya/source-google-calendar"
+import { TflFeedItemType } from "@freya/source-tfl"
+import { WeatherFeedItemType } from "@freya/source-weatherkit"
import { describe, expect, test } from "bun:test"
import {
@@ -40,7 +40,7 @@ function saturday(hour: number, minute = 0): Date {
function weatherCurrent(id = "w-current"): FeedItem {
return {
id,
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: WeatherFeedItemType.Current,
timestamp: new Date(),
data: { temperature: 18, precipitationIntensity: 0 },
@@ -50,7 +50,7 @@ function weatherCurrent(id = "w-current"): FeedItem {
function weatherCurrentRainy(id = "w-current-rain"): FeedItem {
return {
id,
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: WeatherFeedItemType.Current,
timestamp: new Date(),
data: { temperature: 12, precipitationIntensity: 2.5 },
@@ -60,7 +60,7 @@ function weatherCurrentRainy(id = "w-current-rain"): FeedItem {
function weatherCurrentExtreme(id = "w-current-extreme"): FeedItem {
return {
id,
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: WeatherFeedItemType.Current,
timestamp: new Date(),
data: { temperature: -5, precipitationIntensity: 0 },
@@ -70,7 +70,7 @@ function weatherCurrentExtreme(id = "w-current-extreme"): FeedItem {
function weatherHourly(id = "w-hourly"): FeedItem {
return {
id,
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: WeatherFeedItemType.Hourly,
timestamp: new Date(),
data: { forecastTime: new Date(), temperature: 20 },
@@ -80,7 +80,7 @@ function weatherHourly(id = "w-hourly"): FeedItem {
function weatherDaily(id = "w-daily"): FeedItem {
return {
id,
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: WeatherFeedItemType.Daily,
timestamp: new Date(),
data: { forecastDate: new Date() },
@@ -90,7 +90,7 @@ function weatherDaily(id = "w-daily"): FeedItem {
function weatherAlert(id = "w-alert", urgency = 0.9): FeedItem {
return {
id,
- sourceId: "aelis.weather",
+ sourceId: "freya.weather",
type: WeatherFeedItemType.Alert,
timestamp: new Date(),
data: { severity: "extreme" },
@@ -105,7 +105,7 @@ function calendarEvent(
): FeedItem {
return {
id,
- sourceId: "aelis.google-calendar",
+ sourceId: "freya.google-calendar",
type: CalendarFeedItemType.Event,
timestamp: new Date(),
data: {
@@ -127,7 +127,7 @@ function calendarEvent(
function calendarAllDay(id: string): FeedItem {
return {
id,
- sourceId: "aelis.google-calendar",
+ sourceId: "freya.google-calendar",
type: CalendarFeedItemType.AllDay,
timestamp: new Date(),
data: {
@@ -153,7 +153,7 @@ function caldavEvent(
): FeedItem {
return {
id,
- sourceId: "aelis.caldav",
+ sourceId: "freya.caldav",
type: CalDavFeedItemType.Event,
timestamp: new Date(),
data: {
@@ -179,7 +179,7 @@ function caldavEvent(
function tflAlert(id = "tfl-1", urgency = 0.8): FeedItem {
return {
id,
- sourceId: "aelis.tfl",
+ sourceId: "freya.tfl",
type: TflFeedItemType.Alert,
timestamp: new Date(),
data: {
diff --git a/packages/aelis-feed-enhancers/src/time-of-day-enhancer.ts b/packages/freya-feed-enhancers/src/time-of-day-enhancer.ts
similarity index 97%
rename from packages/aelis-feed-enhancers/src/time-of-day-enhancer.ts
rename to packages/freya-feed-enhancers/src/time-of-day-enhancer.ts
index da5ee63..2d9347e 100644
--- a/packages/aelis-feed-enhancers/src/time-of-day-enhancer.ts
+++ b/packages/freya-feed-enhancers/src/time-of-day-enhancer.ts
@@ -1,13 +1,13 @@
-import type { Context, FeedEnhancement, FeedItem, FeedPostProcessor } from "@aelis/core"
-import type { CalDavEventData } from "@aelis/source-caldav"
-import type { CalendarEventData } from "@aelis/source-google-calendar"
-import type { CurrentWeatherData } from "@aelis/source-weatherkit"
+import type { Context, FeedEnhancement, FeedItem, FeedPostProcessor } from "@freya/core"
+import type { CalDavEventData } from "@freya/source-caldav"
+import type { CalendarEventData } from "@freya/source-google-calendar"
+import type { CurrentWeatherData } from "@freya/source-weatherkit"
-import { TimeRelevance } from "@aelis/core"
-import { CalDavFeedItemType } from "@aelis/source-caldav"
-import { CalendarFeedItemType } from "@aelis/source-google-calendar"
-import { TflFeedItemType } from "@aelis/source-tfl"
-import { WeatherFeedItemType } from "@aelis/source-weatherkit"
+import { TimeRelevance } from "@freya/core"
+import { CalDavFeedItemType } from "@freya/source-caldav"
+import { CalendarFeedItemType } from "@freya/source-google-calendar"
+import { TflFeedItemType } from "@freya/source-tfl"
+import { WeatherFeedItemType } from "@freya/source-weatherkit"
export const TimePeriod = {
Morning: "morning",
diff --git a/packages/aelis-source-caldav/README.md b/packages/freya-source-caldav/README.md
similarity index 95%
rename from packages/aelis-source-caldav/README.md
rename to packages/freya-source-caldav/README.md
index 93d4800..2389586 100644
--- a/packages/aelis-source-caldav/README.md
+++ b/packages/freya-source-caldav/README.md
@@ -1,11 +1,11 @@
-# @aelis/source-caldav
+# @freya/source-caldav
A FeedSource that fetches calendar events from any CalDAV server.
## Usage
```ts
-import { CalDavSource } from "@aelis/source-caldav"
+import { CalDavSource } from "@freya/source-caldav"
// Basic auth (Nextcloud, Radicale, Baikal, iCloud, etc.)
const source = new CalDavSource({
diff --git a/packages/aelis-source-caldav/fixtures/all-day-event.ics b/packages/freya-source-caldav/fixtures/all-day-event.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/all-day-event.ics
rename to packages/freya-source-caldav/fixtures/all-day-event.ics
diff --git a/packages/aelis-source-caldav/fixtures/cancelled-event.ics b/packages/freya-source-caldav/fixtures/cancelled-event.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/cancelled-event.ics
rename to packages/freya-source-caldav/fixtures/cancelled-event.ics
diff --git a/packages/aelis-source-caldav/fixtures/daily-recurring-allday.ics b/packages/freya-source-caldav/fixtures/daily-recurring-allday.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/daily-recurring-allday.ics
rename to packages/freya-source-caldav/fixtures/daily-recurring-allday.ics
diff --git a/packages/aelis-source-caldav/fixtures/minimal-event.ics b/packages/freya-source-caldav/fixtures/minimal-event.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/minimal-event.ics
rename to packages/freya-source-caldav/fixtures/minimal-event.ics
diff --git a/packages/aelis-source-caldav/fixtures/recurring-event.ics b/packages/freya-source-caldav/fixtures/recurring-event.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/recurring-event.ics
rename to packages/freya-source-caldav/fixtures/recurring-event.ics
diff --git a/packages/aelis-source-caldav/fixtures/single-event.ics b/packages/freya-source-caldav/fixtures/single-event.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/single-event.ics
rename to packages/freya-source-caldav/fixtures/single-event.ics
diff --git a/packages/aelis-source-caldav/fixtures/weekly-recurring-with-exception.ics b/packages/freya-source-caldav/fixtures/weekly-recurring-with-exception.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/weekly-recurring-with-exception.ics
rename to packages/freya-source-caldav/fixtures/weekly-recurring-with-exception.ics
diff --git a/packages/aelis-source-caldav/fixtures/weekly-recurring.ics b/packages/freya-source-caldav/fixtures/weekly-recurring.ics
similarity index 100%
rename from packages/aelis-source-caldav/fixtures/weekly-recurring.ics
rename to packages/freya-source-caldav/fixtures/weekly-recurring.ics
diff --git a/packages/aelis-source-caldav/package.json b/packages/freya-source-caldav/package.json
similarity index 70%
rename from packages/aelis-source-caldav/package.json
rename to packages/freya-source-caldav/package.json
index 917f588..e8ed127 100644
--- a/packages/aelis-source-caldav/package.json
+++ b/packages/freya-source-caldav/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/source-caldav",
+ "name": "@freya/source-caldav",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
@@ -9,8 +9,8 @@
"test:live": "bun run scripts/test-live.ts"
},
"dependencies": {
- "@aelis/components": "workspace:*",
- "@aelis/core": "workspace:*",
+ "@freya/components": "workspace:*",
+ "@freya/core": "workspace:*",
"ical.js": "^2.1.0",
"tsdav": "^2.1.7"
}
diff --git a/packages/aelis-source-caldav/scripts/test-live.ts b/packages/freya-source-caldav/scripts/test-live.ts
similarity index 98%
rename from packages/aelis-source-caldav/scripts/test-live.ts
rename to packages/freya-source-caldav/scripts/test-live.ts
index 21dd7f5..746d862 100644
--- a/packages/aelis-source-caldav/scripts/test-live.ts
+++ b/packages/freya-source-caldav/scripts/test-live.ts
@@ -7,7 +7,7 @@
* Writes feed items (with slots) to scripts/.cache/feed-items.json for inspection.
*/
-import { Context } from "@aelis/core"
+import { Context } from "@freya/core"
import { mkdirSync, writeFileSync } from "node:fs"
import { join } from "node:path"
diff --git a/packages/aelis-source-caldav/src/caldav-source.test.ts b/packages/freya-source-caldav/src/caldav-source.test.ts
similarity index 99%
rename from packages/aelis-source-caldav/src/caldav-source.test.ts
rename to packages/freya-source-caldav/src/caldav-source.test.ts
index 84d1ad5..5fe4816 100644
--- a/packages/aelis-source-caldav/src/caldav-source.test.ts
+++ b/packages/freya-source-caldav/src/caldav-source.test.ts
@@ -1,6 +1,6 @@
-import type { ContextEntry } from "@aelis/core"
+import type { ContextEntry } from "@freya/core"
-import { Context, TimeRelevance } from "@aelis/core"
+import { Context, TimeRelevance } from "@freya/core"
import { describe, expect, test } from "bun:test"
import { readFileSync } from "node:fs"
import { join } from "node:path"
@@ -76,7 +76,7 @@ describe("CalDavSource", () => {
test("has correct id", () => {
const client = new MockDAVClient([], {})
const source = createSource(client)
- expect(source.id).toBe("aelis.caldav")
+ expect(source.id).toBe("freya.caldav")
})
test("returns empty array when no calendars exist", async () => {
diff --git a/packages/aelis-source-caldav/src/caldav-source.ts b/packages/freya-source-caldav/src/caldav-source.ts
similarity index 98%
rename from packages/aelis-source-caldav/src/caldav-source.ts
rename to packages/freya-source-caldav/src/caldav-source.ts
index c37e9d9..cd85945 100644
--- a/packages/aelis-source-caldav/src/caldav-source.ts
+++ b/packages/freya-source-caldav/src/caldav-source.ts
@@ -1,6 +1,6 @@
-import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource, Slot } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource, Slot } from "@freya/core"
-import { Context, TimeRelevance, UnknownActionError } from "@aelis/core"
+import { Context, TimeRelevance, UnknownActionError } from "@freya/core"
import { DAVClient } from "tsdav"
import type { CalDavDAVClient, CalDavEventData, CalDavFeedItem } from "./types.ts"
@@ -71,7 +71,7 @@ const DEFAULT_LOOK_AHEAD_DAYS = 0
* ```
*/
export class CalDavSource implements FeedSource {
- readonly id = "aelis.caldav"
+ readonly id = "freya.caldav"
private options: CalDavSourceOptions | null
private readonly lookAheadDays: number
@@ -180,7 +180,7 @@ export class CalDavSource implements FeedSource {
const allEvents: CalDavEventData[] = []
for (const result of results) {
if (result.status === "rejected") {
- console.warn("[aelis.caldav] Failed to fetch calendar:", result.reason)
+ console.warn("[freya.caldav] Failed to fetch calendar:", result.reason)
continue
}
const { objects, calendarName } = result.value
diff --git a/packages/aelis-source-caldav/src/calendar-context.ts b/packages/freya-source-caldav/src/calendar-context.ts
similarity index 83%
rename from packages/aelis-source-caldav/src/calendar-context.ts
rename to packages/freya-source-caldav/src/calendar-context.ts
index 6c4ef6e..d30e1b0 100644
--- a/packages/aelis-source-caldav/src/calendar-context.ts
+++ b/packages/freya-source-caldav/src/calendar-context.ts
@@ -1,6 +1,6 @@
-import type { ContextKey } from "@aelis/core"
+import type { ContextKey } from "@freya/core"
-import { contextKey } from "@aelis/core"
+import { contextKey } from "@freya/core"
import type { CalDavEventData } from "./types.ts"
@@ -21,4 +21,4 @@ export interface CalendarContext {
todayEventCount: number
}
-export const CalDavCalendarKey: ContextKey = contextKey("aelis.caldav", "calendar")
+export const CalDavCalendarKey: ContextKey = contextKey("freya.caldav", "calendar")
diff --git a/packages/aelis-source-caldav/src/ical-parser.test.ts b/packages/freya-source-caldav/src/ical-parser.test.ts
similarity index 100%
rename from packages/aelis-source-caldav/src/ical-parser.test.ts
rename to packages/freya-source-caldav/src/ical-parser.test.ts
diff --git a/packages/aelis-source-caldav/src/ical-parser.ts b/packages/freya-source-caldav/src/ical-parser.ts
similarity index 99%
rename from packages/aelis-source-caldav/src/ical-parser.ts
rename to packages/freya-source-caldav/src/ical-parser.ts
index e8244dc..0c4b09f 100644
--- a/packages/aelis-source-caldav/src/ical-parser.ts
+++ b/packages/freya-source-caldav/src/ical-parser.ts
@@ -125,7 +125,7 @@ export function parseICalEvents(
while (next) {
if (++iterations > MAX_RECURRENCE_ITERATIONS) {
console.warn(
- `[aelis.caldav] Recurrence expansion for "${masterEvent.uid}" hit iteration limit (${MAX_RECURRENCE_ITERATIONS}), stopping`,
+ `[freya.caldav] Recurrence expansion for "${masterEvent.uid}" hit iteration limit (${MAX_RECURRENCE_ITERATIONS}), stopping`,
)
break
}
diff --git a/packages/aelis-source-caldav/src/index.ts b/packages/freya-source-caldav/src/index.ts
similarity index 100%
rename from packages/aelis-source-caldav/src/index.ts
rename to packages/freya-source-caldav/src/index.ts
diff --git a/packages/aelis-source-caldav/src/prompts/cross-source.txt b/packages/freya-source-caldav/src/prompts/cross-source.txt
similarity index 100%
rename from packages/aelis-source-caldav/src/prompts/cross-source.txt
rename to packages/freya-source-caldav/src/prompts/cross-source.txt
diff --git a/packages/aelis-source-caldav/src/prompts/insight.txt b/packages/freya-source-caldav/src/prompts/insight.txt
similarity index 100%
rename from packages/aelis-source-caldav/src/prompts/insight.txt
rename to packages/freya-source-caldav/src/prompts/insight.txt
diff --git a/packages/aelis-source-caldav/src/prompts/preparation.txt b/packages/freya-source-caldav/src/prompts/preparation.txt
similarity index 100%
rename from packages/aelis-source-caldav/src/prompts/preparation.txt
rename to packages/freya-source-caldav/src/prompts/preparation.txt
diff --git a/packages/aelis-source-caldav/src/renderer.tsx b/packages/freya-source-caldav/src/renderer.tsx
similarity index 94%
rename from packages/aelis-source-caldav/src/renderer.tsx
rename to packages/freya-source-caldav/src/renderer.tsx
index 4062b3a..eab11e2 100644
--- a/packages/aelis-source-caldav/src/renderer.tsx
+++ b/packages/freya-source-caldav/src/renderer.tsx
@@ -1,8 +1,8 @@
/** @jsxImportSource @nym.sh/jrx */
-import type { FeedItemRenderer } from "@aelis/core"
+import type { FeedItemRenderer } from "@freya/core"
-import { FeedCard, SansSerifText, SerifText } from "@aelis/components"
+import { FeedCard, SansSerifText, SerifText } from "@freya/components"
import type { CalDavEventData } from "./types.ts"
diff --git a/packages/aelis-source-caldav/src/text.d.ts b/packages/freya-source-caldav/src/text.d.ts
similarity index 100%
rename from packages/aelis-source-caldav/src/text.d.ts
rename to packages/freya-source-caldav/src/text.d.ts
diff --git a/packages/aelis-source-caldav/src/types.ts b/packages/freya-source-caldav/src/types.ts
similarity index 98%
rename from packages/aelis-source-caldav/src/types.ts
rename to packages/freya-source-caldav/src/types.ts
index 859dd0c..9802957 100644
--- a/packages/aelis-source-caldav/src/types.ts
+++ b/packages/freya-source-caldav/src/types.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
// -- Event status --
diff --git a/packages/aelis-source-caldav/tsconfig.json b/packages/freya-source-caldav/tsconfig.json
similarity index 100%
rename from packages/aelis-source-caldav/tsconfig.json
rename to packages/freya-source-caldav/tsconfig.json
diff --git a/packages/aelis-source-google-calendar/fixtures/events.json b/packages/freya-source-google-calendar/fixtures/events.json
similarity index 100%
rename from packages/aelis-source-google-calendar/fixtures/events.json
rename to packages/freya-source-google-calendar/fixtures/events.json
diff --git a/packages/aelis-source-google-calendar/package.json b/packages/freya-source-google-calendar/package.json
similarity index 70%
rename from packages/aelis-source-google-calendar/package.json
rename to packages/freya-source-google-calendar/package.json
index e42a7e0..c5e8847 100644
--- a/packages/aelis-source-google-calendar/package.json
+++ b/packages/freya-source-google-calendar/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/source-google-calendar",
+ "name": "@freya/source-google-calendar",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
@@ -8,7 +8,7 @@
"test": "bun test ."
},
"dependencies": {
- "@aelis/core": "workspace:*",
+ "@freya/core": "workspace:*",
"arktype": "^2.1.0"
}
}
diff --git a/packages/freya-source-google-calendar/src/calendar-context.ts b/packages/freya-source-google-calendar/src/calendar-context.ts
new file mode 100644
index 0000000..b62d035
--- /dev/null
+++ b/packages/freya-source-google-calendar/src/calendar-context.ts
@@ -0,0 +1,13 @@
+import type { ContextKey } from "@freya/core"
+
+import { contextKey } from "@freya/core"
+
+export interface NextEvent {
+ title: string
+ startTime: Date
+ endTime: Date
+ minutesUntilStart: number
+ location: string | null
+}
+
+export const NextEventKey: ContextKey = contextKey("freya.google-calendar", "nextEvent")
diff --git a/packages/aelis-source-google-calendar/src/feed-items.ts b/packages/freya-source-google-calendar/src/feed-items.ts
similarity index 92%
rename from packages/aelis-source-google-calendar/src/feed-items.ts
rename to packages/freya-source-google-calendar/src/feed-items.ts
index 28fa87d..9963edb 100644
--- a/packages/aelis-source-google-calendar/src/feed-items.ts
+++ b/packages/freya-source-google-calendar/src/feed-items.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import type { CalendarEventData } from "./types"
diff --git a/packages/aelis-source-google-calendar/src/google-calendar-api.ts b/packages/freya-source-google-calendar/src/google-calendar-api.ts
similarity index 100%
rename from packages/aelis-source-google-calendar/src/google-calendar-api.ts
rename to packages/freya-source-google-calendar/src/google-calendar-api.ts
diff --git a/packages/aelis-source-google-calendar/src/google-calendar-source.test.ts b/packages/freya-source-google-calendar/src/google-calendar-source.test.ts
similarity index 98%
rename from packages/aelis-source-google-calendar/src/google-calendar-source.test.ts
rename to packages/freya-source-google-calendar/src/google-calendar-source.test.ts
index b4d073f..33a8975 100644
--- a/packages/aelis-source-google-calendar/src/google-calendar-source.test.ts
+++ b/packages/freya-source-google-calendar/src/google-calendar-source.test.ts
@@ -1,4 +1,4 @@
-import { Context, TimeRelevance } from "@aelis/core"
+import { Context, TimeRelevance } from "@freya/core"
import { describe, expect, test } from "bun:test"
import type { ApiCalendarEvent, GoogleCalendarClient, ListEventsOptions } from "./types"
@@ -45,7 +45,7 @@ describe("GoogleCalendarSource", () => {
describe("constructor", () => {
test("has correct id", () => {
const source = new GoogleCalendarSource({ client: defaultMockClient() })
- expect(source.id).toBe("aelis.google-calendar")
+ expect(source.id).toBe("freya.google-calendar")
})
})
diff --git a/packages/aelis-source-google-calendar/src/google-calendar-source.ts b/packages/freya-source-google-calendar/src/google-calendar-source.ts
similarity index 97%
rename from packages/aelis-source-google-calendar/src/google-calendar-source.ts
rename to packages/freya-source-google-calendar/src/google-calendar-source.ts
index d355471..cfb6fee 100644
--- a/packages/aelis-source-google-calendar/src/google-calendar-source.ts
+++ b/packages/freya-source-google-calendar/src/google-calendar-source.ts
@@ -1,6 +1,6 @@
-import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@freya/core"
-import { Context, TimeRelevance, UnknownActionError } from "@aelis/core"
+import { Context, TimeRelevance, UnknownActionError } from "@freya/core"
import type {
ApiCalendarEvent,
@@ -65,7 +65,7 @@ const URGENCY_ALL_DAY = 0.4
* ```
*/
export class GoogleCalendarSource implements FeedSource {
- readonly id = "aelis.google-calendar"
+ readonly id = "freya.google-calendar"
private readonly client: GoogleCalendarClient
private readonly calendarIds: string[] | undefined
diff --git a/packages/aelis-source-google-calendar/src/index.ts b/packages/freya-source-google-calendar/src/index.ts
similarity index 100%
rename from packages/aelis-source-google-calendar/src/index.ts
rename to packages/freya-source-google-calendar/src/index.ts
diff --git a/packages/aelis-source-google-calendar/src/types.ts b/packages/freya-source-google-calendar/src/types.ts
similarity index 100%
rename from packages/aelis-source-google-calendar/src/types.ts
rename to packages/freya-source-google-calendar/src/types.ts
diff --git a/packages/aelis-source-location/README.md b/packages/freya-source-location/README.md
similarity index 84%
rename from packages/aelis-source-location/README.md
rename to packages/freya-source-location/README.md
index 8b7c351..2c2c219 100644
--- a/packages/aelis-source-location/README.md
+++ b/packages/freya-source-location/README.md
@@ -1,6 +1,6 @@
-# @aelis/source-location
+# @freya/source-location
-A FeedSource that provides location context to the AELIS feed graph.
+A FeedSource that provides location context to the FREYA feed graph.
## Overview
@@ -9,14 +9,14 @@ This source accepts external location pushes and does not query location itself.
## Installation
```bash
-bun add @aelis/source-location
+bun add @freya/source-location
```
## Usage
```ts
-import { LocationSource, LocationKey, type Location } from "@aelis/source-location"
-import { contextValue } from "@aelis/core"
+import { LocationSource, LocationKey, type Location } from "@freya/source-location"
+import { contextValue } from "@freya/core"
// Create source with default history size (1)
const locationSource = new LocationSource()
@@ -42,8 +42,8 @@ locationSource.locationHistory // readonly Location[]
### With FeedController
```ts
-import { FeedController } from "@aelis/core"
-import { LocationSource } from "@aelis/source-location"
+import { FeedController } from "@freya/core"
+import { LocationSource } from "@freya/source-location"
const locationSource = new LocationSource()
@@ -63,8 +63,8 @@ locationSource.pushLocation({
### Reading Location in Downstream Sources
```ts
-import { contextValue, type FeedSource } from "@aelis/core"
-import { LocationKey } from "@aelis/source-location"
+import { contextValue, type FeedSource } from "@freya/core"
+import { LocationKey } from "@freya/source-location"
const weatherSource: FeedSource = {
id: "weather",
diff --git a/packages/aelis-source-location/package.json b/packages/freya-source-location/package.json
similarity index 73%
rename from packages/aelis-source-location/package.json
rename to packages/freya-source-location/package.json
index 58b56f4..1ec23de 100644
--- a/packages/aelis-source-location/package.json
+++ b/packages/freya-source-location/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/source-location",
+ "name": "@freya/source-location",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
@@ -8,7 +8,7 @@
"test": "bun test src/"
},
"dependencies": {
- "@aelis/core": "workspace:*",
+ "@freya/core": "workspace:*",
"arktype": "^2.1.0"
}
}
diff --git a/packages/aelis-source-location/src/index.ts b/packages/freya-source-location/src/index.ts
similarity index 100%
rename from packages/aelis-source-location/src/index.ts
rename to packages/freya-source-location/src/index.ts
diff --git a/packages/aelis-source-location/src/location-source.test.ts b/packages/freya-source-location/src/location-source.test.ts
similarity index 99%
rename from packages/aelis-source-location/src/location-source.test.ts
rename to packages/freya-source-location/src/location-source.test.ts
index 8dbcc4e..a3fe138 100644
--- a/packages/aelis-source-location/src/location-source.test.ts
+++ b/packages/freya-source-location/src/location-source.test.ts
@@ -18,7 +18,7 @@ describe("LocationSource", () => {
describe("FeedSource interface", () => {
test("has correct id", () => {
const source = new LocationSource()
- expect(source.id).toBe("aelis.location")
+ expect(source.id).toBe("freya.location")
})
test("fetchItems always returns empty array", async () => {
diff --git a/packages/aelis-source-location/src/location-source.ts b/packages/freya-source-location/src/location-source.ts
similarity index 93%
rename from packages/aelis-source-location/src/location-source.ts
rename to packages/freya-source-location/src/location-source.ts
index 7d959a9..a767553 100644
--- a/packages/aelis-source-location/src/location-source.ts
+++ b/packages/freya-source-location/src/location-source.ts
@@ -1,11 +1,11 @@
-import type { ActionDefinition, ContextEntry, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedSource } from "@freya/core"
-import { Context, UnknownActionError, contextKey, type ContextKey } from "@aelis/core"
+import { Context, UnknownActionError, contextKey, type ContextKey } from "@freya/core"
import { type } from "arktype"
import { Location, type LocationSourceOptions } from "./types.ts"
-export const LocationKey: ContextKey = contextKey("aelis.location", "location")
+export const LocationKey: ContextKey = contextKey("freya.location", "location")
/**
* A FeedSource that provides location context.
@@ -16,7 +16,7 @@ export const LocationKey: ContextKey = contextKey("aelis.location", "l
* Does not produce feed items - always returns empty array from `fetchItems`.
*/
export class LocationSource implements FeedSource {
- readonly id = "aelis.location"
+ readonly id = "freya.location"
private readonly historySize: number
private locations: Location[] = []
diff --git a/packages/aelis-source-location/src/types.ts b/packages/freya-source-location/src/types.ts
similarity index 100%
rename from packages/aelis-source-location/src/types.ts
rename to packages/freya-source-location/src/types.ts
diff --git a/packages/aelis-source-tfl/fixtures/tfl-responses.json b/packages/freya-source-tfl/fixtures/tfl-responses.json
similarity index 100%
rename from packages/aelis-source-tfl/fixtures/tfl-responses.json
rename to packages/freya-source-tfl/fixtures/tfl-responses.json
diff --git a/packages/aelis-source-tfl/package.json b/packages/freya-source-tfl/package.json
similarity index 68%
rename from packages/aelis-source-tfl/package.json
rename to packages/freya-source-tfl/package.json
index 96f4d9e..87ac5cb 100644
--- a/packages/aelis-source-tfl/package.json
+++ b/packages/freya-source-tfl/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/source-tfl",
+ "name": "@freya/source-tfl",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
@@ -9,9 +9,9 @@
"fetch-fixtures": "bun run scripts/fetch-fixtures.ts"
},
"dependencies": {
- "@aelis/components": "workspace:*",
- "@aelis/core": "workspace:*",
- "@aelis/source-location": "workspace:*",
+ "@freya/components": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-location": "workspace:*",
"arktype": "^2.1.0"
},
"peerDependencies": {
diff --git a/packages/aelis-source-tfl/scripts/fetch-fixtures.ts b/packages/freya-source-tfl/scripts/fetch-fixtures.ts
similarity index 100%
rename from packages/aelis-source-tfl/scripts/fetch-fixtures.ts
rename to packages/freya-source-tfl/scripts/fetch-fixtures.ts
diff --git a/packages/aelis-source-tfl/src/index.ts b/packages/freya-source-tfl/src/index.ts
similarity index 100%
rename from packages/aelis-source-tfl/src/index.ts
rename to packages/freya-source-tfl/src/index.ts
diff --git a/packages/aelis-source-tfl/src/renderer.test.tsx b/packages/freya-source-tfl/src/renderer.test.tsx
similarity index 99%
rename from packages/aelis-source-tfl/src/renderer.test.tsx
rename to packages/freya-source-tfl/src/renderer.test.tsx
index 6d4b526..2b25dab 100644
--- a/packages/aelis-source-tfl/src/renderer.test.tsx
+++ b/packages/freya-source-tfl/src/renderer.test.tsx
@@ -20,7 +20,7 @@ function makeAlert(overrides: Partial = {}): TflAlertData {
function makeItem(alerts: TflAlertData[]): TflStatusFeedItem {
return {
id: "tfl-status",
- sourceId: "aelis.tfl",
+ sourceId: "freya.tfl",
type: "tfl-status",
timestamp: new Date("2026-01-15T12:00:00Z"),
data: { alerts },
diff --git a/packages/aelis-source-tfl/src/renderer.tsx b/packages/freya-source-tfl/src/renderer.tsx
similarity index 91%
rename from packages/aelis-source-tfl/src/renderer.tsx
rename to packages/freya-source-tfl/src/renderer.tsx
index b92d5b1..5889e99 100644
--- a/packages/aelis-source-tfl/src/renderer.tsx
+++ b/packages/freya-source-tfl/src/renderer.tsx
@@ -1,7 +1,7 @@
/** @jsxImportSource @nym.sh/jrx */
-import type { FeedItemRenderer } from "@aelis/core"
+import type { FeedItemRenderer } from "@freya/core"
-import { FeedCard, SansSerifText } from "@aelis/components"
+import { FeedCard, SansSerifText } from "@freya/components"
import type { TflAlertData, TflStatusData } from "./types.ts"
diff --git a/packages/aelis-source-tfl/src/tfl-api.ts b/packages/freya-source-tfl/src/tfl-api.ts
similarity index 100%
rename from packages/aelis-source-tfl/src/tfl-api.ts
rename to packages/freya-source-tfl/src/tfl-api.ts
diff --git a/packages/aelis-source-tfl/src/tfl-source.test.ts b/packages/freya-source-tfl/src/tfl-source.test.ts
similarity index 98%
rename from packages/aelis-source-tfl/src/tfl-source.test.ts
rename to packages/freya-source-tfl/src/tfl-source.test.ts
index c95f420..ad109c6 100644
--- a/packages/aelis-source-tfl/src/tfl-source.test.ts
+++ b/packages/freya-source-tfl/src/tfl-source.test.ts
@@ -1,5 +1,5 @@
-import { Context } from "@aelis/core"
-import { LocationKey, type Location } from "@aelis/source-location"
+import { Context } from "@freya/core"
+import { LocationKey, type Location } from "@freya/source-location"
import { describe, expect, test } from "bun:test"
import type {
@@ -93,12 +93,12 @@ describe("TflSource", () => {
describe("interface", () => {
test("has correct id", () => {
const source = new TflSource({ client: api })
- expect(source.id).toBe("aelis.tfl")
+ expect(source.id).toBe("freya.tfl")
})
test("depends on location", () => {
const source = new TflSource({ client: api })
- expect(source.dependencies).toEqual(["aelis.location"])
+ expect(source.dependencies).toEqual(["freya.location"])
})
test("implements fetchItems", () => {
@@ -192,7 +192,7 @@ describe("TflSource", () => {
const item = items[0]!
expect(item.id).toBe("tfl-status")
expect(item.type).toBe("tfl-status")
- expect(item.sourceId).toBe("aelis.tfl")
+ expect(item.sourceId).toBe("freya.tfl")
expect(item.signals).toBeDefined()
expect(typeof item.signals!.urgency).toBe("number")
expect(item.timestamp).toBeInstanceOf(Date)
diff --git a/packages/aelis-source-tfl/src/tfl-source.ts b/packages/freya-source-tfl/src/tfl-source.ts
similarity index 95%
rename from packages/aelis-source-tfl/src/tfl-source.ts
rename to packages/freya-source-tfl/src/tfl-source.ts
index 3165c63..a73b4af 100644
--- a/packages/aelis-source-tfl/src/tfl-source.ts
+++ b/packages/freya-source-tfl/src/tfl-source.ts
@@ -1,7 +1,7 @@
-import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@freya/core"
-import { Context, TimeRelevance, UnknownActionError } from "@aelis/core"
-import { LocationKey } from "@aelis/source-location"
+import { Context, TimeRelevance, UnknownActionError } from "@freya/core"
+import { LocationKey } from "@freya/source-location"
import { type } from "arktype"
import type {
@@ -73,8 +73,8 @@ export class TflSource implements FeedSource {
"elizabeth",
]
- readonly id = "aelis.tfl"
- readonly dependencies = ["aelis.location"]
+ readonly id = "freya.tfl"
+ readonly dependencies = ["freya.location"]
private readonly client: ITflApi
private lines: TflLineId[]
diff --git a/packages/aelis-source-tfl/src/types.ts b/packages/freya-source-tfl/src/types.ts
similarity index 97%
rename from packages/aelis-source-tfl/src/types.ts
rename to packages/freya-source-tfl/src/types.ts
index 3401263..e57c445 100644
--- a/packages/aelis-source-tfl/src/types.ts
+++ b/packages/freya-source-tfl/src/types.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import type { TflLineId } from "./tfl-api.ts"
diff --git a/packages/aelis-source-tfl/tsconfig.json b/packages/freya-source-tfl/tsconfig.json
similarity index 100%
rename from packages/aelis-source-tfl/tsconfig.json
rename to packages/freya-source-tfl/tsconfig.json
diff --git a/packages/aelis-source-weatherkit/README.md b/packages/freya-source-weatherkit/README.md
similarity index 88%
rename from packages/aelis-source-weatherkit/README.md
rename to packages/freya-source-weatherkit/README.md
index f21b96f..c747df1 100644
--- a/packages/aelis-source-weatherkit/README.md
+++ b/packages/freya-source-weatherkit/README.md
@@ -1,4 +1,4 @@
-# @aelis/source-weatherkit
+# @freya/source-weatherkit
Weather feed source using Apple WeatherKit API.
@@ -7,7 +7,7 @@ Weather feed source using Apple WeatherKit API.
### Basic Setup
```ts
-import { WeatherSource, Units } from "@aelis/source-weatherkit"
+import { WeatherSource, Units } from "@freya/source-weatherkit"
const weatherSource = new WeatherSource({
credentials: {
@@ -23,8 +23,8 @@ const weatherSource = new WeatherSource({
### With Feed Source Graph
```ts
-import { LocationSource } from "@aelis/source-location"
-import { WeatherSource } from "@aelis/source-weatherkit"
+import { LocationSource } from "@freya/source-location"
+import { WeatherSource } from "@freya/source-weatherkit"
const locationSource = new LocationSource()
const weatherSource = new WeatherSource({ credentials })
@@ -38,8 +38,8 @@ const sources = [locationSource, weatherSource]
Downstream sources can access weather data:
```ts
-import { contextValue } from "@aelis/core"
-import { WeatherKey } from "@aelis/source-weatherkit"
+import { contextValue } from "@freya/core"
+import { WeatherKey } from "@freya/source-weatherkit"
async function fetchContext(context: Context) {
const weather = contextValue(context, WeatherKey)
diff --git a/packages/aelis-source-weatherkit/fixtures/san-francisco.json b/packages/freya-source-weatherkit/fixtures/san-francisco.json
similarity index 100%
rename from packages/aelis-source-weatherkit/fixtures/san-francisco.json
rename to packages/freya-source-weatherkit/fixtures/san-francisco.json
diff --git a/packages/aelis-source-weatherkit/package.json b/packages/freya-source-weatherkit/package.json
similarity index 61%
rename from packages/aelis-source-weatherkit/package.json
rename to packages/freya-source-weatherkit/package.json
index 1a7b7d3..480e2c9 100644
--- a/packages/aelis-source-weatherkit/package.json
+++ b/packages/freya-source-weatherkit/package.json
@@ -1,5 +1,5 @@
{
- "name": "@aelis/source-weatherkit",
+ "name": "@freya/source-weatherkit",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",
@@ -8,8 +8,8 @@
"test": "bun test ."
},
"dependencies": {
- "@aelis/core": "workspace:*",
- "@aelis/source-location": "workspace:*",
+ "@freya/core": "workspace:*",
+ "@freya/source-location": "workspace:*",
"arktype": "^2.1.0"
}
}
diff --git a/packages/aelis-source-weatherkit/scripts/query.ts b/packages/freya-source-weatherkit/scripts/query.ts
similarity index 97%
rename from packages/aelis-source-weatherkit/scripts/query.ts
rename to packages/freya-source-weatherkit/scripts/query.ts
index b39a3dd..ca79689 100644
--- a/packages/aelis-source-weatherkit/scripts/query.ts
+++ b/packages/freya-source-weatherkit/scripts/query.ts
@@ -6,11 +6,11 @@
* then prints the raw API response and processed feed items.
* Caches credentials locally and writes response JSON to a file.
*
- * Usage: bun packages/aelis-source-weatherkit/scripts/query.ts
+ * Usage: bun packages/freya-source-weatherkit/scripts/query.ts
*/
-import { Context } from "@aelis/core"
-import { LocationKey } from "@aelis/source-location"
+import { Context } from "@freya/core"
+import { LocationKey } from "@freya/source-location"
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
import { join } from "node:path"
import { createInterface } from "node:readline/promises"
diff --git a/packages/aelis-source-weatherkit/src/feed-items.ts b/packages/freya-source-weatherkit/src/feed-items.ts
similarity index 98%
rename from packages/aelis-source-weatherkit/src/feed-items.ts
rename to packages/freya-source-weatherkit/src/feed-items.ts
index 6af7e55..5a5ee67 100644
--- a/packages/aelis-source-weatherkit/src/feed-items.ts
+++ b/packages/freya-source-weatherkit/src/feed-items.ts
@@ -1,4 +1,4 @@
-import type { FeedItem } from "@aelis/core"
+import type { FeedItem } from "@freya/core"
import type { Certainty, ConditionCode, PrecipitationType, Severity, Urgency } from "./weatherkit"
diff --git a/packages/aelis-source-weatherkit/src/index.ts b/packages/freya-source-weatherkit/src/index.ts
similarity index 100%
rename from packages/aelis-source-weatherkit/src/index.ts
rename to packages/freya-source-weatherkit/src/index.ts
diff --git a/packages/aelis-source-weatherkit/src/prompts/current-weather-insight.txt b/packages/freya-source-weatherkit/src/prompts/current-weather-insight.txt
similarity index 100%
rename from packages/aelis-source-weatherkit/src/prompts/current-weather-insight.txt
rename to packages/freya-source-weatherkit/src/prompts/current-weather-insight.txt
diff --git a/packages/aelis-source-weatherkit/src/weather-context.ts b/packages/freya-source-weatherkit/src/weather-context.ts
similarity index 76%
rename from packages/aelis-source-weatherkit/src/weather-context.ts
rename to packages/freya-source-weatherkit/src/weather-context.ts
index f758160..04229bb 100644
--- a/packages/aelis-source-weatherkit/src/weather-context.ts
+++ b/packages/freya-source-weatherkit/src/weather-context.ts
@@ -1,6 +1,6 @@
-import type { ContextKey } from "@aelis/core"
+import type { ContextKey } from "@freya/core"
-import { contextKey } from "@aelis/core"
+import { contextKey } from "@freya/core"
import type { ConditionCode } from "./weatherkit"
@@ -24,4 +24,4 @@ export interface Weather {
daylight: boolean
}
-export const WeatherKey: ContextKey = contextKey("aelis.weather", "weather")
+export const WeatherKey: ContextKey = contextKey("freya.weather", "weather")
diff --git a/packages/aelis-source-weatherkit/src/weather-source.test.ts b/packages/freya-source-weatherkit/src/weather-source.test.ts
similarity index 98%
rename from packages/aelis-source-weatherkit/src/weather-source.test.ts
rename to packages/freya-source-weatherkit/src/weather-source.test.ts
index 6e78417..72b2f7d 100644
--- a/packages/aelis-source-weatherkit/src/weather-source.test.ts
+++ b/packages/freya-source-weatherkit/src/weather-source.test.ts
@@ -1,7 +1,7 @@
-import type { FeedSource } from "@aelis/core"
+import type { FeedSource } from "@freya/core"
-import { Context } from "@aelis/core"
-import { LocationKey } from "@aelis/source-location"
+import { Context } from "@freya/core"
+import { LocationKey } from "@freya/source-location"
import { describe, expect, test } from "bun:test"
import type {
@@ -41,12 +41,12 @@ describe("WeatherSource", () => {
describe("properties", () => {
test("has correct id", () => {
const source = new WeatherSource({ credentials: mockCredentials })
- expect(source.id).toBe("aelis.weather")
+ expect(source.id).toBe("freya.weather")
})
test("depends on location", () => {
const source = new WeatherSource({ credentials: mockCredentials })
- expect(source.dependencies).toEqual(["aelis.location"])
+ expect(source.dependencies).toEqual(["freya.location"])
})
test("throws error if neither client nor credentials provided", () => {
diff --git a/packages/aelis-source-weatherkit/src/weather-source.ts b/packages/freya-source-weatherkit/src/weather-source.ts
similarity index 98%
rename from packages/aelis-source-weatherkit/src/weather-source.ts
rename to packages/freya-source-weatherkit/src/weather-source.ts
index b0fdf31..f6bde19 100644
--- a/packages/aelis-source-weatherkit/src/weather-source.ts
+++ b/packages/freya-source-weatherkit/src/weather-source.ts
@@ -1,7 +1,7 @@
-import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@aelis/core"
+import type { ActionDefinition, ContextEntry, FeedItemSignals, FeedSource } from "@freya/core"
-import { Context, TimeRelevance, UnknownActionError } from "@aelis/core"
-import { LocationKey } from "@aelis/source-location"
+import { Context, TimeRelevance, UnknownActionError } from "@freya/core"
+import { LocationKey } from "@freya/source-location"
import {
WeatherFeedItemType,
@@ -99,8 +99,8 @@ const MODERATE_CONDITIONS = new Set([
* ```
*/
export class WeatherSource implements FeedSource {
- readonly id = "aelis.weather"
- readonly dependencies = ["aelis.location"]
+ readonly id = "freya.weather"
+ readonly dependencies = ["freya.location"]
private readonly client: WeatherKitClient
private readonly hourlyLimit: number
diff --git a/packages/aelis-source-weatherkit/src/weatherkit.ts b/packages/freya-source-weatherkit/src/weatherkit.ts
similarity index 100%
rename from packages/aelis-source-weatherkit/src/weatherkit.ts
rename to packages/freya-source-weatherkit/src/weatherkit.ts