Infrastructure build to support third-party app integrations

This commit is contained in:
KS Jannette
2026-08-01 07:35:01 -04:00
parent b4666c5439
commit 15af3465e2
53 changed files with 5864 additions and 659 deletions

55
backend/types/domain.ts Normal file
View File

@@ -0,0 +1,55 @@
export type Note = {
id: string;
text: string;
x: number;
y: number;
author: string;
color: string;
};
/** Shape accepted when writing a note; positional and color fields fall back to defaults. */
export type NoteInput = {
id: string;
text: string;
author: string;
x?: number;
y?: number;
color?: string;
sourceMeta?: Record<string, unknown>;
};
export type Cluster = {
label: string;
noteIds: string[];
};
export type ClusterResponse = {
clusters: Cluster[];
score: number;
};
export type ValidationResult = {
valid: boolean;
reasons: string[];
};
/** noteId to embedding vector. */
export type EmbeddingMap = Map<string, number[]>;
const isStringArray = (value: unknown): value is string[] =>
Array.isArray(value) && value.every((entry) => typeof entry === 'string');
/**
* Runtime guard for LLM output, which arrives as parsed JSON of unknown shape.
* Structural correctness beyond this (complete coverage, no duplicates) is the
* job of validateStructure.
*/
export const isClusterArray = (value: unknown): value is Cluster[] => {
if (!Array.isArray(value)) return false;
return value.every((entry) => {
if (typeof entry !== 'object' || entry === null) return false;
const candidate = entry as Record<string, unknown>;
return typeof candidate.label === 'string' && isStringArray(candidate.noteIds);
});
};

View File

@@ -0,0 +1,43 @@
import type { NoteInput } from './domain.js';
export type ProviderSlug = 'slack' | 'jira' | 'linear' | 'github' | 'rest';
export type SignatureScheme = 'slack-v0' | 'github-sha256' | 'linear-sha256' | 'none';
export type DeliveryStatus = 'pending' | 'processing' | 'done' | 'failed';
/**
* Integration as exposed to application code. Ciphertext columns are
* deliberately absent so a value of this type can never leak a secret.
*/
export type IntegrationRow = {
id: number;
provider: ProviderSlug;
externalWorkspaceId: string | null;
displayName: string | null;
scopes: string[];
tokenExpiresAt: Date | null;
};
export type SignatureResult =
| { ok: true }
| { ok: false; reason: 'missing' | 'malformed' | 'mismatch' | 'stale' };
export type NormalizedDelivery = {
externalId: string;
notes: NoteInput[];
};
/** Provenance recorded on each ingested note's source_meta column. */
export type NoteProvenance = {
provider: ProviderSlug;
externalId: string;
permalink?: string;
authorHandle?: string;
receivedAt: string;
};
const SLUGS: readonly string[] = ['slack', 'jira', 'linear', 'github', 'rest'];
export const isProviderSlug = (value: string): value is ProviderSlug =>
SLUGS.includes(value);