The Coline App SDK: apps, tools, file types and surfaces that run inside Coline workspaces, and public websites with Coline Sites. TypeScript, with an in-memory test workspace. MIT.
| 6 | type ColineAppManifest, |
| 7 | type ColineFileTypeDefinition, |
| 8 | type ColineFileTypeDefinitionInput, |
| 9 | type ColineAppRegistrationPayload, |
| 10 | type CreateNotificationInput, |
| 11 | type NotificationChannelDefinition, |
| 12 | type NotificationChannelDefinitionInput, |
| 13 | notificationChannelDefinitionSchema, |
| 14 | } from "./manifest"; |
| 15 |
| 16 | type UnknownPayload = Record<string, unknown>; |
| 17 |
| 18 | export interface HomeRenderContext extends UnknownPayload {} |
| 19 | export interface FileRenderContext extends UnknownPayload { |
| 20 | fileId?: string; |
| 21 | } |
| 22 | export interface IndexSyncContext extends UnknownPayload { |
| 23 | workspaceId?: string; |
| 24 | } |
| 25 |
| 26 | export type HomeRenderHandler = (context: HomeRenderContext) => unknown | Promise<unknown>; |
| 27 | export type FileRenderHandler = (context: FileRenderContext) => unknown | Promise<unknown>; |
| 28 | export type IndexSyncHandler = (context: IndexSyncContext) => unknown | Promise<unknown>; |
| 29 |
| 30 | export interface ColineAppDefinition { |
| 31 | manifest: ColineAppManifest; |
| 32 | fileTypes: ColineFileTypeDefinition[]; |
| 33 | notificationChannels: NotificationChannelDefinition[]; |
| 34 | handlers: { |
| 35 | homeRender?: HomeRenderHandler; |
| 36 | fileRender?: FileRenderHandler; |
| 37 | indexSync?: IndexSyncHandler; |
| 38 | }; |
| 39 | } |
| 40 |
| 41 | export class ColineApp { |
| 42 | readonly manifest: ColineAppManifest; |
| 43 | private readonly fileTypes = new Map<string, ColineFileTypeDefinition>(); |
| 44 | private readonly notificationChannels = new Map<string, NotificationChannelDefinition>(); |
| 45 | private readonly handlers: ColineAppDefinition["handlers"] = {}; |
| 46 |
| 47 | constructor(manifest: ColineAppManifest) { |
| 48 | this.manifest = colineAppManifestSchema.parse(manifest); |
| 49 | } |
| 50 |
| 51 | defineFileType(fileType: ColineFileTypeDefinitionInput): this { |
| 52 | const parsed = colineFileTypeSchema.parse(fileType); |
| 53 | this.fileTypes.set(parsed.typeKey, parsed); |
| 54 | return this; |
| 55 | } |
| 56 |
| 57 | defineNotificationChannel(channel: NotificationChannelDefinitionInput): this { |
| 58 | const parsed = notificationChannelDefinitionSchema.parse(channel); |
| 59 | this.notificationChannels.set(parsed.key, parsed); |
| 60 | return this; |
| 61 | } |
| 62 |
| 63 | onHomeRender(handler: HomeRenderHandler): this { |
| 64 | this.handlers.homeRender = handler; |
| 65 | return this; |
| 66 | } |
| 67 |
| 68 | onFileRender(handler: FileRenderHandler): this { |
| 69 | this.handlers.fileRender = handler; |
| 70 | return this; |
| 71 | } |
| 72 |
| 73 | onIndexSync(handler: IndexSyncHandler): this { |
| 74 | this.handlers.indexSync = handler; |
| 75 | return this; |
| 76 | } |
| 77 |
| 78 | getDefinition(): ColineAppDefinition { |
| 79 | const notificationChannels = [...this.notificationChannels.values()]; |
| 80 |
| 81 | return { |
| 82 | manifest: { |
| 83 | ...this.manifest, |
| 84 | notificationChannels, |
| 85 | }, |
| 86 | fileTypes: [...this.fileTypes.values()], |
| 87 | notificationChannels, |
| 88 | handlers: { ...this.handlers }, |
| 89 | }; |
| 90 | } |
| 91 |
| 92 | getRegistrationPayload(version: string): ColineAppRegistrationPayload { |
| 93 | const notificationChannels = [...this.notificationChannels.values()]; |
| 94 |
| 95 | return colineAppRegistrationPayloadSchema.parse({ |
| 96 | version, |
| 97 | manifest: { |
| 98 | ...this.manifest, |
| 99 | notificationChannels, |
| 100 | }, |
| 101 | fileTypes: [...this.fileTypes.values()], |
| 102 | }); |
| 103 | } |
| 104 |
| 105 | createNotification(input: CreateNotificationInput): CreateNotificationInput { |
| 106 | return createNotificationInputSchema.parse(input); |
| 107 | } |
| 108 | } |
| 109 |