supermemory/packages/validation/connection.ts
2025-09-18 21:03:49 -07:00

191 lines
5.2 KiB
TypeScript

import { z } from "zod";
import { ConnectionProviderEnum } from "./schemas";
export const providers = ConnectionProviderEnum;
export type Provider = z.infer<typeof providers>;
const BaseMetadataSchema = <T extends z.ZodTypeAny>(provider: T) =>
z.object({
provider,
});
export const NotionMetadataSchema = BaseMetadataSchema(
z.literal("notion"),
).extend({
email: z.string().email().optional(),
ownerId: z.string(),
workspaceIcon: z.string().optional(),
workspaceId: z.string(),
workspaceName: z.string(),
});
export type NotionMetadata = z.infer<typeof NotionMetadataSchema>;
export const GoogleDriveMetadataSchema = BaseMetadataSchema(
z.literal("google-drive"),
).extend({
pageToken: z.number(),
webhookChannelId: z.string().optional(),
webhookExpiration: z.number().optional(),
webhookResourceId: z.string().optional(),
});
export type GoogleDriveMetadata = z.infer<typeof GoogleDriveMetadataSchema>;
export const OneDriveMetadataSchema = BaseMetadataSchema(
z.literal("onedrive"),
).extend({
deltaLink: z.string().optional(),
lastRenewalCheck: z.number().optional(),
webhookClientState: z.string().optional(),
webhookExpiration: z.number().optional(),
webhookSubscriptionId: z.string().optional(),
});
export type OneDriveMetadata = z.infer<typeof OneDriveMetadataSchema>;
export const ConnectionMetadataSchema = z.discriminatedUnion("provider", [
NotionMetadataSchema,
GoogleDriveMetadataSchema,
OneDriveMetadataSchema,
]);
export type ConnectionMetadata<T extends Provider> = T extends "notion"
? NotionMetadata
: T extends "google-drive"
? GoogleDriveMetadata
: T extends "onedrive"
? OneDriveMetadata
: never;
export function isNotionMetadata(
metadata: unknown,
): metadata is NotionMetadata {
return NotionMetadataSchema.safeParse(metadata).success;
}
export function isGoogleDriveMetadata(
metadata: unknown,
): metadata is GoogleDriveMetadata {
return GoogleDriveMetadataSchema.safeParse(metadata).success;
}
export function isOneDriveMetadata(
metadata: unknown,
): metadata is OneDriveMetadata {
return OneDriveMetadataSchema.safeParse(metadata).success;
}
export const ConnectionStateSchema = z.object({
createdAt: z.number(),
org: z.string(),
provider: providers,
userId: z.string(),
});
export type ConnectionState = z.infer<typeof ConnectionStateSchema>;
export const TokenDataSchema = z.object({
// Only used for Notion connections since they don't support refresh tokens
accessToken: z.string().optional(),
createdAt: z.number(),
documentLimit: z.number().optional(),
email: z.string().email().optional(),
expiresAt: z.number().optional(),
metadata: ConnectionMetadataSchema.optional(),
refreshToken: z.string().optional(),
userId: z.string().optional(),
});
export type TokenData = z.infer<typeof TokenDataSchema>;
export const NotionTokenResponseSchema = z.object({
access_token: z.string(),
bot_id: z.string().optional(),
duplicated_template_id: z.string().nullable().optional(),
owner: z.union([
z.object({
type: z.literal("user"),
user: z.object({
avatar_url: z.string().url().optional(),
id: z.string(),
name: z.string().optional(),
object: z.literal("user"),
person: z
.object({
email: z.string().email().optional(),
})
.optional(),
type: z.literal("person"),
}),
}),
z.object({
type: z.literal("workspace"),
workspace: z.literal(true),
}),
]),
request_id: z.string().optional(),
token_type: z.literal("bearer"),
workspace_icon: z.string().optional(),
workspace_id: z.string(),
workspace_name: z.string(),
});
export type NotionTokenResponse = z.infer<typeof NotionTokenResponseSchema>;
export const GoogleDriveTokenResponseSchema = z.object({
access_token: z.string(),
expires_in: z.number(),
refresh_token: z.string().optional(),
scope: z.string(),
token_type: z.literal("Bearer"),
});
export type GoogleDriveTokenResponse = z.infer<
typeof GoogleDriveTokenResponseSchema
>;
export const OneDriveTokenResponseSchema = z.object({
access_token: z.string(),
expires_in: z.number(),
refresh_token: z.string().optional(),
scope: z.string(),
token_type: z.literal("Bearer"),
});
export type OneDriveTokenResponse = z.infer<typeof OneDriveTokenResponseSchema>;
export const NotionConfigSchema = z.object({
clientId: z.string(),
clientSecret: z.string(),
endpoints: z.object({
authorize: z.string().url(),
token: z.string().url(),
}),
scopes: z.array(z.string()),
});
export type NotionConfig = z.infer<typeof NotionConfigSchema>;
export const ConnectionQuerySchema = z.object({
id: z.string(),
redirectUrl: z.string().optional(),
});
export const GoogleDrivePageTokenResponseSchema = z.object({
startPageToken: z.union([z.string(), z.number()]),
});
export const GoogleDriveWatchResponseSchema = z.object({
expiration: z.string(),
id: z.string(),
resourceId: z.string(),
});
export const OneDriveSubscriptionResponseSchema = z.object({
changeType: z.string(),
clientState: z.string(),
expirationDateTime: z.string(),
id: z.string(),
notificationUrl: z.string(),
resource: z.string(),
});
export const GoogleUserInfoResponseSchema = z.object({
email: z.string().email(),
});
export const MicrosoftUserInfoResponseSchema = z.object({
mail: z.string().optional(),
userPrincipalName: z.string().optional(),
});