79 lines
4.1 KiB
TypeScript
79 lines
4.1 KiB
TypeScript
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
|
// A delivery's project comes from the record, inside the delivery's organization (adapters/jobs.ts). The record's
|
|
// workspace and project must exist in that organization before knowledge acts on them; one that names another
|
|
// workspace's project, or one the organization does not have, is refused by name and nothing is enqueued.
|
|
|
|
import { Container, type EventContext, newId, type OrgScope } from "@conusai-kit/core"
|
|
import { createMemoryDataSource, DATA_SOURCE, JOB_QUEUE } from "@conusai-kit/data"
|
|
import { projects, workspaces } from "@conusai-kit/tenancy"
|
|
import { fakeJobQueue } from "@conusai-kit/testing"
|
|
import { describe, expect, it } from "vitest"
|
|
import { KNOWLEDGE_SUBSCRIPTIONS } from "../adapters/jobs.js"
|
|
import { KNOWLEDGE_ENTITIES, KNOWLEDGE_SCOPE } from "../index.js"
|
|
|
|
async function delivery(archivedAt: string | null = null) {
|
|
const data = createMemoryDataSource({ entities: [workspaces, projects, ...KNOWLEDGE_ENTITIES] })
|
|
const orgId = newId()
|
|
const org: OrgScope = { level: "org", actor: { userId: newId() }, orgId }
|
|
const workspace = await data
|
|
.forScope(org)
|
|
.of(workspaces)
|
|
.insert({ slug: "main", name: "Main", isDefault: true, visibility: "org" })
|
|
const other = await data
|
|
.forScope(org)
|
|
.of(workspaces)
|
|
.insert({ slug: "other", name: "Other", isDefault: false, visibility: "org" })
|
|
const project = await data
|
|
.forScope({ level: "workspace", actor: org.actor, orgId, workspaceId: workspace.id })
|
|
.of(projects)
|
|
.insert({ slug: "site", name: "Site", moduleKey: "notes", archivedAt })
|
|
const queue = fakeJobQueue()
|
|
const container = new Container()
|
|
container.value(DATA_SOURCE, data)
|
|
container.value(JOB_QUEUE, queue)
|
|
// The relay's delivery: the organization's scope, with a system actor.
|
|
container.value(KNOWLEDGE_SCOPE, org)
|
|
const ctx = { container } as unknown as EventContext
|
|
return { ctx, queue, orgId, workspaceId: workspace.id, otherWorkspaceId: other.id, projectId: project.id }
|
|
}
|
|
|
|
const indexRequested = KNOWLEDGE_SUBSCRIPTIONS[1]
|
|
const request = (ids: { orgId: string; workspaceId: string; projectId: string }) => ({
|
|
name: "knowledge.DocumentIndexRequested",
|
|
payload: { ...ids, documentId: newId(), collectionName: "contracts", fileId: newId() },
|
|
})
|
|
|
|
describe("a knowledge delivery acts only in a project of its organization", () => {
|
|
it("enqueues the job in the record's project when it exists there", async () => {
|
|
const { ctx, queue, orgId, workspaceId, projectId } = await delivery()
|
|
await indexRequested?.handler(request({ orgId, workspaceId, projectId }) as never, ctx)
|
|
expect(queue.of("knowledge.index")).toHaveLength(1)
|
|
})
|
|
|
|
it("refuses, by name, a workspace the organization does not have", async () => {
|
|
const { ctx, queue, orgId, projectId } = await delivery()
|
|
const workspaceId = newId()
|
|
await expect(indexRequested?.handler(request({ orgId, workspaceId, projectId }) as never, ctx)).rejects.toThrow(
|
|
new RegExp(`workspace ${workspaceId}`),
|
|
)
|
|
expect(queue.of("knowledge.index")).toEqual([])
|
|
})
|
|
|
|
it("refuses, by name, a project that is not in the record's workspace", async () => {
|
|
const { ctx, queue, orgId, otherWorkspaceId, projectId } = await delivery()
|
|
await expect(
|
|
indexRequested?.handler(request({ orgId, workspaceId: otherWorkspaceId, projectId }) as never, ctx),
|
|
).rejects.toThrow(new RegExp(`project ${projectId}`))
|
|
expect(queue.of("knowledge.index")).toEqual([])
|
|
})
|
|
|
|
it("acts on a record of an archived project: an archive hides a project and does not end its work", async () => {
|
|
// The kit's one rule (kit-tenancy suspension.ts): an archived project refuses a person's write, not work with
|
|
// no person behind it. A deleted file's text must still leave the index, and an index request a member made
|
|
// before the archive still completes.
|
|
const { ctx, queue, orgId, workspaceId, projectId } = await delivery(new Date("2026-11-09T00:00:00Z").toISOString())
|
|
await indexRequested?.handler(request({ orgId, workspaceId, projectId }) as never, ctx)
|
|
expect(queue.of("knowledge.index")).toHaveLength(1)
|
|
})
|
|
})
|