Files
template-app/modules/notes/core/ports.ts
T

40 lines
1.8 KiB
TypeScript

// The ports the notes module's use cases are written against, and the one it adds: the feature flags.
//
// The audit and usage sinks and the scope of an event delivery are the kernel's own tokens
// (`FILES_AUDIT`, `FILES_USAGE`, `FILES_SCOPE`): the worker binds them once for every module, so a
// module that audits and meters needs no binding of its own and no line in the worker.
import { type Container, type TenantScope, token } from "@conusai-kit/core"
import type { DataSource } from "@conusai-kit/data"
import type { FilesDeps } from "@conusai-kit/files"
import { ATTACHMENTS_FLAG, NOTES_FLAG_DEFAULTS } from "../contract/index.js"
/** A project scope: the only level a note can live at. */
export type NoteScope = TenantScope & { workspaceId: string; projectId: string }
export interface NotesDeps {
readonly data: DataSource
/** The files module's ports: an attachment is one of its files. */
readonly files: FilesDeps
readonly flags: NotesFlags
}
/** What a flag service answers for the project a call runs in. */
export interface NotesFlags {
enabled(flag: keyof typeof NOTES_FLAG_DEFAULTS, scope: NoteScope): boolean | Promise<boolean>
}
/**
* Bound by an app that evaluates flags per organization, project or user (the platform's flag
* service, through `@conusai-sdk/node-sdk/flags`). With nothing bound, a flag is its manifest default.
*/
export const NOTES_FLAGS = token<NotesFlags>("notes.flags")
export const defaultFlags: NotesFlags = { enabled: (flag) => NOTES_FLAG_DEFAULTS[flag] }
export const flagsOf = (container: Container): NotesFlags =>
container.has(NOTES_FLAGS) ? container.resolve(NOTES_FLAGS) : defaultFlags
export const attachmentsEnabled = async (deps: NotesDeps, scope: NoteScope): Promise<boolean> =>
deps.flags.enabled(ATTACHMENTS_FLAG, scope)