cronofy / cronofy-node

Node wrapper for the Cronofy API
https://docs.cronofy.com/developers
MIT License
49 stars 23 forks source link

support for typescript types? #96

Open riccardogiorato opened 2 years ago

riccardogiorato commented 2 years ago

Are you planning to add support for typescript types @victor-cronofy ?

victor-cronofy commented 2 years ago

Thanks for your question.

Typescript support isn't in our plan at the moment. There was a discussion about it but unfortunately it didn't fit in the development roadmap. The effort to support Typescript is not trivial. Hope you understand.

Let us know if there is anything blocking you from using Cronofy API. Thank you

riccardogiorato commented 2 years ago

Hey @victor-cronofy we are still considering if we are going to use Cronofy or a competitor like https://www.nylas.com/

They already provide Typescript support to make the development faster and easier, are you planning to support Typescript in the next future (next month)?

gshutler commented 2 years ago

I'm afraid we're not in a position to provide Typescript types in the near future.

MOIN-AKHTAR commented 1 year ago

It would be great if we can get typecript definition files because while using this sdk i am not able to get suggestion not even for methods which is inside this sdk for that i have to go to implementation files of this sdk and than look there what functions are available and on the other hand for each method i am also not able to find what params or body look like which is kind of very cumbersome to work.

nabilfreeman commented 7 months ago

Hey all, I've started implementing Cronofy in a new TypeScript project today. I can't promise anything on the level of DefinitelyTyped, but I will share any of the types I write here as a jumping off point for basic use cases.

nabilfreeman commented 7 months ago

As promised... I've typed setup, authentication, listing calendars and CRUD events, which is our use case and hopefully many others.

As you can see by all the TODO types, there is a huge number of other methods which I haven't typed.

Earlier today I thought perhaps releasing a community types module was feasible but I think it will take over a week of work to fully type this (despite the documentation being really, really good) and obviously keeping it in sync with new service providers, alpha features etc. has significant ongoing maintenance needs.

But maybe this will help a few people go from zero to one!

I'll edit this comment if/when I update our types file.

// cronofy.d.ts
declare module 'cronofy' {
    export default class Cronofy {
        constructor(config: FactoryOptions);

        requestAccessToken: (options: RequestAccessTokenOptions) => Promise<RequestAccessTokenResponse>;
        refreshAccessToken: () => Promise<RefreshAccessTokenResponse>;
        listCalendars: () => Promise<ListCalendarsResponse>;
        readEvents: (options: ReadEventsOptions) => Promise<ReadEventsResponse>;
        deleteEvent: (options: DeleteEventOptions) => Promise<DeleteEventResponse>;
        createEvent: (options: CreateEventOptions) => Promise<CreateEventResponse>;

        // TODO: Properly type the remaining Cronofy client methods below.
        accountInformation: (TODOInput: TODOInput) => Promise<TODOResponse>;
        addToCalendar: (TODOInput: TODOInput) => Promise<TODOResponse>;
        realTimeScheduling: (TODOInput: TODOInput) => Promise<TODOResponse>;
        realTimeSequencing: (TODOInput: TODOInput) => Promise<TODOResponse>;
        authorizeWithServiceAccount: (TODOInput: TODOInput) => Promise<TODOResponse>;
        availability: (TODOInput: TODOInput) => Promise<TODOResponse>;
        sequencedAvailability: (TODOInput: TODOInput) => Promise<TODOResponse>;
        upsertAvailablePeriod: (TODOInput: TODOInput) => Promise<TODOResponse>;
        listAvailablePeriods: (TODOInput: TODOInput) => Promise<TODOResponse>;
        deleteAvailablePeriods: (TODOInput: TODOInput) => Promise<TODOResponse>;
        listAvailabilityRules: (TODOInput: TODOInput) => Promise<TODOResponse>;
        upsertAvailabilityRule: (TODOInput: TODOInput) => Promise<TODOResponse>;
        readAvailabilityRule: (TODOInput: TODOInput) => Promise<TODOResponse>;
        deleteAvailabilityRule: (TODOInput: TODOInput) => Promise<TODOResponse>;
        createNotificationChannel: (TODOInput: TODOInput) => Promise<TODOResponse>;
        bulkDeleteEvents: (TODOInput: TODOInput) => Promise<TODOResponse>;
        updateExternalEvent: (TODOInput: TODOInput) => Promise<TODOResponse>;
        deleteExternalEvent: (TODOInput: TODOInput) => Promise<TODOResponse>;
        deleteNotificationChannel: (TODOInput: TODOInput) => Promise<TODOResponse>;
        elevatedPermissions: (TODOInput: TODOInput) => Promise<TODOResponse>;
        freeBusy: (TODOInput: TODOInput) => Promise<TODOResponse>;
        createCalendar: (TODOInput: TODOInput) => Promise<TODOResponse>;
        listNotificationChannels: (TODOInput: TODOInput) => Promise<TODOResponse>;
        profileInformation: (TODOInput: TODOInput) => Promise<TODOResponse>;
        applicationCalendar: (TODOInput: TODOInput) => Promise<TODOResponse>;
        revokeProfileAuthorization: (TODOInput: TODOInput) => Promise<TODOResponse>;
        hmacValid: (TODOInput: TODOInput) => Promise<TODOResponse>;
        revokeAuthorization: (TODOInput: TODOInput) => Promise<TODOResponse>;
        getSmartInvite: (TODOInput: TODOInput) => Promise<TODOResponse>;
        createSmartInvite: (TODOInput: TODOInput) => Promise<TODOResponse>;
        cancelSmartInvite: (TODOInput: TODOInput) => Promise<TODOResponse>;
        userInfo: (TODOInput: TODOInput) => Promise<TODOResponse>;
        requestElementToken: (TODOInput: TODOInput) => Promise<TODOResponse>;
        listAccessibleCalendars: (TODOInput: TODOInput) => Promise<TODOResponse>;
        delegatedAuthorizations: (TODOInput: TODOInput) => Promise<TODOResponse>;
        batch: (TODOInput: TODOInput) => Promise<TODOResponse>;
        conferencingServiceAuthorizations: (TODOInput: TODOInput) => Promise<TODOResponse>;
        createBookableEvent: (TODOInput: TODOInput) => Promise<TODOResponse>;
        readBookableEvents: (TODOInput: TODOInput) => Promise<TODOResponse>;
        upsertRegistrationBookableEvent: (TODOInput: TODOInput) => Promise<TODOResponse>;
        deleteRegistrationBookableEvent: (TODOInput: TODOInput) => Promise<TODOResponse>;
    }

    // Inputs
    export type TODOInput = any; // TODO: Define the remaining input types for the Cronofy client methods, and then delete this type.
    export type FactoryOptions = {
        data_center: DataCenter;
        client_id: string;
        client_secret: string;
        access_token: string;
        refresh_token: string;
    };
    export type RequestAccessTokenOptions = {
        client_id: string;
        client_secret: string;
        grant_type: 'authorization_code';
        code: string;
        redirect_uri: string;
    };
    export type ReadEventsOptions = {
        from?: string;
        to?: string;
        tzid: Timezone;
        include_deleted?: boolean;
        include_moved?: boolean;
        last_modified?: string;
        include_managed?: boolean;
        only_managed?: boolean;
        calendar_ids?: string[];
        localized_times?: boolean;
        include_geo?: boolean;
        include_userinfo?: boolean;

        // For pagination
        next_page?: string;
    };
    export type DeleteEventOptions = {
        calendar_id: string;
        event_id: string;
        include_userinfo?: boolean;
    };
    export type CreateEventOptions = {
        calendar_id: string;
        event_id: string;
        summary: string;
        description?: string;
        start: string | EventTimeInZone;
        end: string | EventTimeInZone;
        tzid?: string;
        location?: {
            description?: string;
            lat?: string;
            long?: string;
        };
        url?: string;
        transparency?: 'opaque' | 'transparent';
        extended_transparency?: 'opaque' | 'transparent' | 'working_elsewhere' | 'tentative' | 'out_of_office';
        color?: string;
        reminders?: { minutes: number }[];
        reminders_create_only?: boolean;
        attendees?: {
            invite?: Attendee[];
            remove?: Attendee[];
        };
        event_private?: boolean;
        locale?: string;
        include_userinfo?: boolean;
        tags?: Tags;
        conferencing?: ConferencingInformation;
        subscriptions?: Subscription[];
        recurrence?: {
            rules: RecurrenceRule[];
            exceptions?: {
                add: { date: string }[]; // Array of dates to be excluded from the recurrence pattern
            };
        };
    };

    // Outputs
    export type TODOResponse = any; // TODO: Define the remaining response types for the Cronofy client methods, and then delete this type.
    export type RequestAccessTokenResponse = {
        token_type: 'bearer';
        access_token: string;
        expires_in: number;
        refresh_token: string;
        scope: string;
        sub: string;
    };
    export type RefreshAccessTokenResponse = {
        token_type: 'bearer';
        access_token: string;
        expires_in: number;
        refresh_token: string;
        scope: string;
    };
    export type ListCalendarsResponse = {
        sub: string;
        calendars: Calendar[];
    };
    type _ReadEventsResponse = {
        pages: {
            current: number;
            total: number;
            next_page?: string;
        };
        events: Event[];
    };
    export type ReadEventsResponse = _ReadEventsResponse | WithUserInfo<_ReadEventsResponse>;
    export type DeleteEventResponse = void | WithUserInfo<{}>;
    export type CreateEventResponse = Event;

    // Atoms
    export type Calendar = {
        provider_name: ProviderName;
        profile_id: string;
        profile_name: string;
        calendar_id: string;
        calendar_name: string;
        calendar_readonly: boolean;
        calendar_deleted: boolean;
        calendar_primary: boolean;
        calendar_integrated_conferencing_available: boolean;
        calendar_attachments_available: boolean;
        permission_level: PermissionLevel;
    };
    export type Profile = {
        provider_name: ProviderName;
        provider_service: ProviderService;
        profile_id: string;
        profile_name: string;
        profile_connected: boolean;
        profile_initial_sync_required: boolean;
        profile_relink_url?: string; // Optional as it may not be present if the profile is connected
    };
    export type UserInfo = {
        sub: string;
        email?: string;
        name?: string;
        zoneinfo?: Timezone;
        'cronofy.type': string;
        'cronofy.data': {
            authorization: {
                scope: string;
                status: 'active' | 'hibernated';
                delegated_scope?: string; // Optional, for service accounts
            };
            profiles?: (Profile & {
                profile_calendars: Pick<
                    Calendar,
                    | 'calendar_id'
                    | 'calendar_name'
                    | 'calendar_readonly'
                    | 'calendar_deleted'
                    | 'calendar_primary'
                    | 'calendar_integrated_conferencing_available'
                    | 'calendar_attachments_available'
                    | 'permission_level'
                >[];
            })[];
            application_calendar?: {
                application_calendar_id: string;
            };
            service_account?: {
                provider_name: string;
                domain?: string;
            };
        };
    };
    export type EventTimeInZone = {
        time: string;
        tzid: string;
    };
    export type Attendee = {
        email: string;
        display_name?: string;
    };
    export type Transparency = 'opaque' | 'transparent' | 'unknown';
    export type ExtendedTransparency = Transparency | 'working_elsewhere' | 'tentative' | 'out_of_office';
    export type Event = {
        calendar_id: string;
        event_uid: string;
        summary: string;
        description: string;
        start: string | EventTimeInZone;
        end: string | EventTimeInZone;
        url?: string;
        deleted: boolean;
        created: string;
        updated: string;
        location?: {
            description?: string;
            lat?: string;
            long?: string;
        };
        event_id?: string;
        participation_status: ParticipationStatus;
        attendees?: (Attendee & { partipation_status: ParticipationStatus })[];
        organizer?: {
            email?: string;
            display_name?: string;
        };
        transparency: Transparency;
        extended_transparency: ExtendedTransparency;
        status: 'tentative' | 'confirmed' | 'cancelled' | 'unknown';
        conferencing?: Pick<ConferencingInformation, 'provider_description' | 'join_url'>;
        meeting_url?: string;
        categories: string[];
        tags: Tags;
        attachments?: string[];
        recurring: boolean;
        series_identifier?: string;
        event_private: boolean;
        options: {
            delete: boolean;
            update: boolean;
            change_participation_status: boolean;
        };
    };
    export type Tags = { [context: string]: { value: string }[] };
    type BeforeTransition = {
        before: 'event_start' | 'event_end';
        offset: Duration;
    };
    type AfterTransition = {
        after: 'event_start' | 'event_end';
        offset: Duration;
    };
    export type Transition = BeforeTransition | AfterTransition;
    export type Duration = {
        minutes?: number;
        hours?: number;
    };
    export type Subscription = {
        type: 'webhook';
        uri: string;
        transitions: Transition[];
    };
    export type RecurrenceRule = {
        frequency: 'daily' | 'weekly' | 'monthly' | 'yearly';
        interval?: number;
        by_day?: { day: WeekDay }[]; // Used only with `weekly` frequency
        count?: number;
        until?: string; // Date string
    };
    export type ConferencingInformation = {
        profile_id: 'default' | 'explicit' | 'integrated' | 'none' | string; // string for custom profile IDs
        provider_description?: string; // Required if profile_id is 'explicit'
        join_url?: string; // Required if profile_id is 'explicit'
    };

    // Generics
    type WithUserInfo<T extends {}> = T & { userinfo: UserInfo };

    // Primitives
    type Timezone = string; // e.g. 'Europe/London' TODO - use a library for this
    type WeekDay = 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday';
    export type PermissionLevel = 'sandbox' | 'unrestricted';
    export type ProviderName = 'apple' | 'cronofy' | 'exchange' | 'google' | 'live_connect';
    export type ProviderService = 'cronofy' | 'exchange' | 'google' | 'gsuite' | 'icloud' | 'office365' | 'outlook_com';
    export type ParticipationStatus = 'needs_action' | 'accepted' | 'declined' | 'tentative' | 'unknown';
    export type DataCenter = 'au' | 'ca' | 'de' | 'sg' | 'uk' | 'us';
}