feat: add actions to FeedSource interface

Add listActions() and executeAction() to FeedSource for write
operations back to external services. Actions use arktype schemas
for input validation via StandardSchemaV1.

- ActionDefinition type with optional input schema
- FeedEngine routes actions with existence and ID validation
- Source IDs use reverse-domain format (aris.location, aris.tfl)
- LocationSource: update-location action with schema validation
- TflSource: set-lines-of-interest action with lineId validation
- No-op implementations for sources without actions

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2026-02-15 12:26:23 +00:00
parent 4d6cac7ec8
commit 699155e0d8
29 changed files with 1169 additions and 116 deletions

View File

@@ -45,13 +45,15 @@ describe("GoogleCalendarSource", () => {
describe("constructor", () => {
test("has correct id", () => {
const source = new GoogleCalendarSource({ client: defaultMockClient() })
expect(source.id).toBe("google-calendar")
expect(source.id).toBe("aris.google-calendar")
})
})
describe("fetchItems", () => {
test("returns empty array when no events", async () => {
const source = new GoogleCalendarSource({ client: createMockClient({ primary: [] }) })
const source = new GoogleCalendarSource({
client: createMockClient({ primary: [] }),
})
const items = await source.fetchItems(createContext())
expect(items).toEqual([])
})
@@ -198,7 +200,9 @@ describe("GoogleCalendarSource", () => {
describe("fetchContext", () => {
test("returns null when no events", async () => {
const source = new GoogleCalendarSource({ client: createMockClient({ primary: [] }) })
const source = new GoogleCalendarSource({
client: createMockClient({ primary: [] }),
})
const result = await source.fetchContext(createContext())
expect(result).toBeNull()
})