chore: rename aelis to freya (#122)

This commit is contained in:
2026-06-12 17:35:26 +01:00
committed by GitHub
parent 7e77870c13
commit 6b1db0b3d3
247 changed files with 585 additions and 585 deletions

View File

@@ -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:*"
}
}

View File

@@ -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<NextEvent> = contextKey("aelis.google-calendar", "nextEvent")

View File

@@ -1,5 +1,5 @@
{
"name": "@aelis/components",
"name": "@freya/components",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",

View File

@@ -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<Location> = 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 }>

View File

@@ -1,5 +1,5 @@
{
"name": "@aelis/core",
"name": "@freya/core",
"version": "0.0.0",
"type": "module",
"main": "src/index.ts",

View File

@@ -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:
* `<sourceId>/<actionId>` (e.g., "aelis.location/update-location").
* `<sourceId>/<actionId>` (e.g., "freya.location/update-location").
*/
export class UnknownActionError extends Error {
readonly actionId: string

View File

@@ -12,8 +12,8 @@ interface NextEvent {
title: string
}
const WeatherKey: ContextKey<Weather> = contextKey("aelis.weather", "current")
const NextEventKey: ContextKey<NextEvent> = contextKey("aelis.google-calendar", "nextEvent")
const WeatherKey: ContextKey<Weather> = contextKey("freya.weather", "current")
const NextEventKey: ContextKey<NextEvent> = contextKey("freya.google-calendar", "nextEvent")
describe("Context", () => {
describe("get", () => {
@@ -66,10 +66,10 @@ describe("Context", () => {
})
test("prefix match returns multiple instances", () => {
const workKey = contextKey<NextEvent>("aelis.google-calendar", "nextEvent", {
const workKey = contextKey<NextEvent>("freya.google-calendar", "nextEvent", {
account: "work",
})
const personalKey = contextKey<NextEvent>("aelis.google-calendar", "nextEvent", {
const personalKey = contextKey<NextEvent>("freya.google-calendar", "nextEvent", {
account: "personal",
})
@@ -79,7 +79,7 @@ describe("Context", () => {
[personalKey, { title: "Dentist" }],
])
const prefix = contextKey<NextEvent>("aelis.google-calendar", "nextEvent")
const prefix = contextKey<NextEvent>("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<NextEvent>("aelis.google-calendar", "nextEvent")
const instanceKey = contextKey<NextEvent>("aelis.google-calendar", "nextEvent", {
const baseKey = contextKey<NextEvent>("freya.google-calendar", "nextEvent")
const instanceKey = contextKey<NextEvent>("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<string>("aelis.calendar", "next")
const keyB = contextKey<string>("aelis.calendar", "nextEvent")
const keyA = contextKey<string>("freya.calendar", "next")
const keyB = contextKey<string>("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)
})

View File

@@ -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.
*/

View File

@@ -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 },

View File

@@ -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

View File

@@ -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.<name>`,
* Source IDs use reverse domain notation. Built-in sources use `freya.<name>`,
* 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() { ... },

View File

@@ -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 },

View File

@@ -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" },

View File

@@ -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:*"
}
}

View File

@@ -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: {

View File

@@ -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",

View File

@@ -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({

View File

@@ -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"
}

View File

@@ -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"

View File

@@ -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 () => {

View File

@@ -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<CalDavFeedItem> {
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<CalDavFeedItem> {
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

View File

@@ -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<CalendarContext> = contextKey("aelis.caldav", "calendar")
export const CalDavCalendarKey: ContextKey<CalendarContext> = contextKey("freya.caldav", "calendar")

View File

@@ -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
}

View File

@@ -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"

View File

@@ -1,4 +1,4 @@
import type { FeedItem } from "@aelis/core"
import type { FeedItem } from "@freya/core"
// -- Event status --

View File

@@ -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"
}
}

View File

@@ -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<NextEvent> = contextKey("freya.google-calendar", "nextEvent")

View File

@@ -1,4 +1,4 @@
import type { FeedItem } from "@aelis/core"
import type { FeedItem } from "@freya/core"
import type { CalendarEventData } from "./types"

View File

@@ -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")
})
})

View File

@@ -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<CalendarFeedItem> {
readonly id = "aelis.google-calendar"
readonly id = "freya.google-calendar"
private readonly client: GoogleCalendarClient
private readonly calendarIds: string[] | undefined

View File

@@ -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",

View File

@@ -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"
}
}

View File

@@ -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 () => {

View File

@@ -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<Location> = contextKey("aelis.location", "location")
export const LocationKey: ContextKey<Location> = contextKey("freya.location", "location")
/**
* A FeedSource that provides location context.
@@ -16,7 +16,7 @@ export const LocationKey: ContextKey<Location> = 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[] = []

View File

@@ -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": {

View File

@@ -20,7 +20,7 @@ function makeAlert(overrides: Partial<TflAlertData> = {}): 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 },

View File

@@ -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"

View File

@@ -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)

View File

@@ -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<TflStatusFeedItem> {
"elizabeth",
]
readonly id = "aelis.tfl"
readonly dependencies = ["aelis.location"]
readonly id = "freya.tfl"
readonly dependencies = ["freya.location"]
private readonly client: ITflApi
private lines: TflLineId[]

View File

@@ -1,4 +1,4 @@
import type { FeedItem } from "@aelis/core"
import type { FeedItem } from "@freya/core"
import type { TflLineId } from "./tfl-api.ts"

View File

@@ -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)

View File

@@ -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"
}
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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<Weather> = contextKey("aelis.weather", "weather")
export const WeatherKey: ContextKey<Weather> = contextKey("freya.weather", "weather")

View File

@@ -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", () => {

View File

@@ -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<ConditionCode>([
* ```
*/
export class WeatherSource implements FeedSource<WeatherFeedItem> {
readonly id = "aelis.weather"
readonly dependencies = ["aelis.location"]
readonly id = "freya.weather"
readonly dependencies = ["freya.location"]
private readonly client: WeatherKitClient
private readonly hourlyLimit: number