Added JSDoc types for API controllers

- this adds a simple set of types to the @tryghost/api-framework
  package that should describe all of the keys available on a
  controller, and then rolls it out to all API controllers
- unfortunately, due to https://github.com/microsoft/TypeScript/issues/47107, we have
  to split apart `module.exports` into a variable assignment in order for type-checking
  to be done
- the main benefit of this is that `frame` is now typed, and editors understand what keys
  are available, so intellisense works properly
This commit is contained in:
Daniel Lockyer 2024-05-07 08:36:44 +02:00 committed by Daniel Lockyer
parent 3246a8d2c9
commit c298db912c
63 changed files with 280 additions and 65 deletions

View File

@ -1 +1,27 @@
/** @typedef {object} PermissionsObject */
/** @typedef {boolean} PermissionsBoolean */
/** @typedef {number} StatusCodeNumber */
/** @typedef {(result: any) => number} StatusCodeFunction */
/** @typedef {object} ValidationObject */
/**
* @typedef {object} ControllerMethod
* @property {object} headers
* @property {PermissionsBoolean | PermissionsObject} permissions
* @property {string[]} [options]
* @property {ValidationObject} [validation]
* @property {string[]} [data]
* @property {StatusCodeFunction | StatusCodeNumber} [statusCode]
* @property {object} [response]
* @property {function} [cache]
* @property {(frame: import('./lib/Frame')) => object} [generateCacheKeyData]
* @property {(frame: import('./lib/Frame')) => any} query
*/
/**
* @typedef {Record<string, ControllerMethod | string> & Record<'docName', string>} Controller
*/
module.exports = require('./lib/api-framework');

View File

@ -1,6 +1,7 @@
const models = require('../../models');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'actions',
browse: {
@ -20,3 +21,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const announcementBarSettings = require('../../services/announcement-bar-service');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'announcement',
browse: {
@ -13,3 +14,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -18,7 +18,8 @@ const messages = {
notTheBlogOwner: 'You are not the site owner.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'authentication',
setup: {
@ -250,3 +251,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -19,7 +19,8 @@ const rejectPrivateFieldsTransformer = input => mapQuery(input, function (value,
};
});
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'authors',
browse: {
@ -92,3 +93,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,7 +6,8 @@ const messages = {
collectionNotFound: 'Collection not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'collections',
readBySlug: {
@ -51,3 +52,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,7 +6,8 @@ const messages = {
collectionNotFound: 'Collection not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'collections',
browse: {
@ -136,3 +137,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -2,7 +2,8 @@ const commentsService = require('../../services/comments');
const ALLOWED_INCLUDES = ['member', 'replies', 'replies.member', 'replies.count.likes', 'replies.liked', 'count.replies', 'count.likes', 'liked', 'post', 'parent'];
const UNSAFE_ATTRS = ['status'];
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'comments',
browse: {
@ -207,3 +208,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const models = require('../../models');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'comments',
edit: {
@ -26,3 +27,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const publicConfig = require('../../services/public-config');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'config',
read: {
@ -13,3 +14,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const customThemeSettingsService = require('../../services/custom-theme-settings');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'custom_theme_settings',
browse: {
@ -23,3 +24,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -8,7 +8,8 @@ const {pool} = require('@tryghost/promise');
const models = require('../../models');
const settingsCache = require('../../../shared/settings-cache');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'db',
backupContent: {
@ -173,3 +174,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -7,7 +7,8 @@ const messages = {
postNotFound: 'Post not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'email_post',
read: {
@ -46,3 +47,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const emailService = require('../../services/email-service');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'email_previews',
read: {
@ -47,3 +48,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -12,7 +12,8 @@ const messages = {
const allowedBatchIncludes = ['count.recipients'];
const allowedFailureIncludes = ['member', 'email_recipient'];
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'emails',
browse: {
@ -180,3 +181,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const exploreService = require('../../services/explore');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'explore',
read: {
@ -13,3 +14,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const feedbackService = require('../../services/audience-feedback');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'feedback',
add: {
@ -24,3 +25,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const storage = require('../../adapters/storage');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'files',
upload: {
statusCode: 201,
@ -20,3 +21,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -23,7 +23,8 @@ const sign = async (claims, options) => {
}, options));
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'identities',
read: {
headers: {
@ -36,3 +37,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,7 +6,8 @@ const imageTransform = require('@tryghost/image-transform');
const storage = require('../../adapters/storage');
const config = require('../../../shared/config');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'images',
upload: {
statusCode: 201,
@ -80,3 +81,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const recommendations = require('../../services/recommendations');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'recommendations',
browse: {
@ -18,3 +19,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -12,7 +12,8 @@ const integrationsService = getIntegrationsServiceInstance({
ApiKeyModel: models.ApiKey
});
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'integrations',
browse: {
headers: {
@ -163,3 +164,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -10,7 +10,8 @@ const messages = {
inviteNotFound: 'Invite not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'invites',
browse: {
@ -127,3 +128,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -9,7 +9,8 @@ const messages = {
const ALLOWED_INCLUDES = ['count.members'];
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'labels',
browse: {
@ -161,3 +162,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,7 +1,8 @@
const linkTrackingService = require('../../services/link-tracking');
const INVALIDATE_ALL_REDIRECTS = '/r/*';
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'links',
browse: {
headers: {
@ -59,3 +60,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const mailEvents = require('../../services/mail-events');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'mail_events',
add: {
headers: {
@ -12,3 +13,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -35,7 +35,8 @@ _private.sendMail = (object) => {
});
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'mail',
send: {
@ -66,3 +67,5 @@ module.exports = {
});
}
};
module.exports = controller;

View File

@ -1,7 +1,8 @@
const path = require('path');
const storage = require('../../adapters/storage');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'media',
upload: {
statusCode: 201,
@ -47,3 +48,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,8 +6,10 @@ const messages = {
memberNotFound: 'Member not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'member_signin_urls',
read: {
headers: {
cacheInvalidate: false
@ -34,3 +36,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const membersService = require('../../services/members');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'members_stripe_connect',
auth: {
headers: {
@ -30,3 +31,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -29,7 +29,8 @@ const messages = {
const allowedIncludes = ['email_recipients', 'products', 'tiers'];
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'members',
browse: {
@ -503,3 +504,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const mentions = require('../../services/mentions');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'mentions',
browse: {
headers: {
@ -37,3 +38,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const models = require('../../models');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'newsletters',
browse: {
@ -20,3 +21,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -2,7 +2,8 @@ const allowedIncludes = ['count.posts', 'count.members', 'count.active_members']
const newslettersService = require('../../services/newsletters');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'newsletters',
browse: {
@ -121,3 +122,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -3,7 +3,8 @@ const settingsService = require('../../services/settings/settings-service');
const settingsBREADService = settingsService.getSettingsBREADServiceInstance();
const internalContext = {context: {internal: true}};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'notifications',
browse: {
@ -101,3 +102,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const oembed = require('../../services/oembed');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'oembed',
read: {
@ -20,3 +21,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,7 +6,8 @@ const messages = {
offerNotFound: 'Offer not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'offers',
read: {
@ -29,3 +30,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,7 +6,8 @@ const messages = {
offerNotFound: 'Offer not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'offers',
browse: {
@ -82,3 +83,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -20,7 +20,8 @@ const rejectPrivateFieldsTransformer = input => mapQuery(input, function (value,
};
});
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'pages',
browse: {
@ -103,3 +104,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -11,7 +11,8 @@ const messages = {
const postsService = getPostServiceInstance();
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'pages',
browse: {
headers: {
@ -282,3 +283,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -23,6 +23,12 @@ const rejectPrivateFieldsTransformer = input => mapQuery(input, function (value,
};
});
/**
*
* @param {import('@tryghost/api-framework').Frame} frame
* @param {object} options
* @returns {object}
*/
function generateOptionsData(frame, options) {
return options.reduce((memo, option) => {
let value = frame.options?.[option];
@ -52,7 +58,9 @@ function generateAuthData(frame) {
};
}
}
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'posts',
browse: {
@ -172,3 +180,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -38,7 +38,8 @@ function getCacheHeaderFromEventString(event, dto) {
}
}
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'posts',
browse: {
headers: {
@ -327,3 +328,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -7,7 +7,8 @@ const messages = {
postNotFound: 'Post not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'previews',
read: {
@ -47,3 +48,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const recommendations = require('../../services/recommendations');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'recommendations',
browse: {
@ -62,3 +63,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const recommendations = require('../../services/recommendations');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'recommendations',
browse: {
@ -107,3 +108,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -2,7 +2,8 @@ const path = require('path');
const customRedirects = require('../../services/custom-redirects');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'redirects',
download: {
@ -44,3 +45,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const models = require('../../models');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'roles',
browse: {
headers: {
@ -20,3 +21,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,8 +1,8 @@
const models = require('../../models');
const postSchedulingService = require('../../services/posts/post-scheduling-service')();
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'schedules',
publish: {
headers: {
@ -85,3 +85,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -8,7 +8,8 @@ const messages = {
accessDenied: 'Access Denied.'
};
const session = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
read(frame) {
/*
* TODO
@ -66,4 +67,4 @@ const session = {
}
};
module.exports = session;
module.exports = controller;

View File

@ -2,7 +2,8 @@ const settingsCache = require('../../../shared/settings-cache');
const urlUtils = require('../../../shared/url-utils');
const ghostVersion = require('@tryghost/version');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'settings',
browse: {
@ -22,3 +23,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -21,7 +21,8 @@ async function getStripeConnectData(frame) {
}
}
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'settings',
browse: {
@ -179,3 +180,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const publicConfig = require('../../services/public-config');
const site = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'site',
read: {
@ -14,4 +15,4 @@ const site = {
}
};
module.exports = site;
module.exports = controller;

View File

@ -1,7 +1,8 @@
// Used to call the slack ping service, iirc this was done to avoid circular deps a long time ago
const events = require('../../lib/common/events');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'slack',
sendTest: {
headers: {
@ -13,3 +14,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -12,7 +12,8 @@ const allowedTypes = {
user: models.User
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'slugs',
generate: {
headers: {
@ -52,3 +53,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -7,7 +7,8 @@ const messages = {
snippetAlreadyExists: 'Snippet already exists.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'snippets',
browse: {
@ -131,3 +132,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const statsService = require('../../services/stats');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'stats',
memberCountHistory: {
headers: {
@ -104,3 +105,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -9,7 +9,8 @@ const messages = {
tagNotFound: 'Tag not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'tags',
browse: {
@ -76,3 +77,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -8,7 +8,8 @@ const messages = {
tagNotFound: 'Tag not found.'
};
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'tags',
browse: {
@ -156,3 +157,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -6,7 +6,8 @@ const models = require('../../models');
const events = require('../../lib/common/events');
const {settingsCache} = require('../../services/settings-helpers');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'themes',
browse: {
@ -180,3 +181,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const tiersService = require('../../services/tiers');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'tiers',
browse: {
@ -23,3 +24,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -1,6 +1,7 @@
const tiersService = require('../../services/tiers');
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'tiers',
browse: {
@ -80,3 +81,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -73,7 +73,8 @@ function shouldInvalidateCacheAfterChange(model) {
return false;
}
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'users',
browse: {
@ -287,3 +288,5 @@ module.exports = {
}
}
};
module.exports = controller;

View File

@ -15,7 +15,8 @@ const webhooksService = getWebhooksServiceInstance({
WebhookModel: models.Webhook
});
module.exports = {
/** @type {import('@tryghost/api-framework').Controller} */
const controller = {
docName: 'webhooks',
add: {
@ -133,3 +134,5 @@ module.exports = {
}
}
};
module.exports = controller;