@stackbit/types
Version:
Types for Stackbit config and Content Source Interface
607 lines • 24.9 kB
TypeScript
import type { ContentSourceInterface, ParametersOfCSIMethod, ReturnTypeOfCSIMethod, User } from './content-source';
import type { DocumentWithSource, AssetWithSource } from './content-source-document';
import type { ModelExtension, ModelMatchFields, ModelWithSource, NamelessModelMap } from './models';
import { SSG_NAMES, CMS_NAMES } from './consts';
import type { SidebarButton } from './sidebar-button';
import type { ConfigDelegate } from './config-delegate';
import type { AssetSource } from './asset-source';
import type { CustomActionBulk, CustomActionGlobal, CustomActionModel } from './custom-actions';
import { DocumentPermissions, ModelPermissions } from './content-permissions';
import { ContentObjectSpecification } from './utility-types';
export interface StackbitConfig {
/**
* The version of the Stackbit configuration.
*/
stackbitVersion: string;
/**
* The name of the front-end framework.
*
* If you specify the `ssgName` property, you can omit the `devCommand`
* property, and Stackbit will use a default value matching your front-end
* framework.
*/
ssgName?: (typeof SSG_NAMES)[number];
/**
* The version of your front-end framework.
* This is particularly useful for Hugo, as it allows for the
* pre-installation of the matching Hugo binary version.
*/
ssgVersion?: string;
/**
* The Node.js version to use for installing dependencies and running the
* front-end framework. You should set it to one of the Node major versions
* such as "18", "16" or "14".
*
* @example
* nodeVersion: "18"
*/
nodeVersion?: string;
/**
* The `useESM` flag indicates if stackbit.config.ts should be compiled to
* CJS or ESM module.
*
* If one of the stackbit.config.ts dependencies is ESM only, you can use
* this flag to support it.
*
* This flag is parsed statically before stackbit.config.ts is
* loaded as a module.
*/
useESM?: boolean;
postGitCloneCommand?: string;
preInstallCommand?: string;
postInstallCommand?: string;
/**
* The command that should be executed to install the project dependencies.
*
* @example
* installCommand: "npm install"
*/
installCommand?: string;
/**
* The command that should be executed to run the development server of your
* front-end framework. When specifying the `devCommand` you must specify
* the arguments for the host and port and set them to `{HOSTNAME}` and
* `{PORT}` tokens respectively. Stackbit will replace these tokens with its
* internal host and port.
*
* @example
* devCommand: "node ./node_modules/.bin/gatsby develop -p {PORT} -H {HOSTNAME}
* devCommand: "node ./node_modules/.bin/next dev --port {PORT} --hostname {HOSTNAME}
* devCommand: "node custom-server.js --port {PORT} --hostname {HOSTNAME}
*/
devCommand?: string;
/** @deprecated This property is deprecated in favor of using `contentSources` */
cmsName?: (typeof CMS_NAMES)[number];
import?: Import;
buildCommand?: string;
publishDir?: string;
/**
* The directory to store the cached content provided by the content-sources.
* If the cacheDir is a relative path, it will be resolved relative to the
* stackbit.config.ts file.
* If not set, defaults to ".stackbit/cache" folder relative to stackbit.config.ts file.
*/
cacheDir?: string;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
staticDir?: string;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
uploadDir?: string;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
assets?: Assets;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
pagesDir?: string | null;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
dataDir?: string | null;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
pageLayoutKey?: string | null;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
objectTypeKey?: string;
/** @deprecated This property is deprecated in favor of using `GitContentSource` */
excludePages?: string | string[];
styleObjectModelName?: string | null;
presetSource?: PresetSource;
sidebarButtons?: SidebarButton[];
/**
* @alias {@link sitemap}
* @deprecated use {@link sitemap}
*/
siteMap?: SiteMapFunction;
/**
* The `sitemap` function should return an array of {@link SiteMapEntry}
* objects. Stackbit uses these objects to show the website's sitemap in its
* UI.
*
* There are two types of sitemap entries: 'static' and 'dynamic'.
*
* Static sitemap entries represent static pages on your website and require
* a [`urlPath`]{@link SiteMapBaseEntry.urlPath}, [`label`]{@link SiteMapBaseEntry.label},
* and [`stableId`]{@link SiteMapBaseEntry.stableId}. The `stableId` must be
* a unique identifier that never changes, even if the entry's `urlPath` is
* modified.
*
* Dynamic sitemap entries represent pages on your website that are
* generated from content source documents. These entries require a
* [`urlPath`]{@link SiteMapBaseEntry.urlPath} and a
* [`document`]{@link SiteMapDocumentEntry.document} object with `id`,
* `modelName`, `srcType`, and `srcProjectId` properties.
*
* To generate dynamic sitemap entries, use the `documents` and `models`
* properties of the `options` parameter.
*
* @param {Object} options
* @param {DocumentWithSource[]} options.documents
* @param {ModelWithSource[]} options.models
*/
sitemap?: SiteMapFunction;
/**
* The `transformSitemap` method is used to transform sitemap entries available for specific user
*/
transformSitemap?: (options: ConfigDelegate & {
sitemap: SiteMapEntry[];
userContext: User;
}) => SiteMapEntry[];
treeViews?: TreeViewsFunction;
/**
* The `transformTreeViews` method is used to transform tree view entries available for specific user
*/
transformTreeViews?: (options: ConfigDelegate & {
treeViews: TreeViewNode[];
userContext: User;
}) => TreeViewNode[];
presetReferenceBehavior?: 'copyReference' | 'duplicateContents';
nonDuplicatableModels?: string[];
duplicatableModels?: string[];
customContentReload?: boolean;
experimental?: Experimental;
contentEngine?: ContentEngineOptions;
contentSources?: ContentSourceInterface<any, any, any, any, any>[];
connectors?: {
integration: any;
config: any;
}[];
assetSources?: AssetSource[];
viewports?: Viewport[];
/**
* The `mapModels` method can be used to modify the models returned by
* content sources.
*
* This method takes an `options` object with the `models` property
* containing an array of `Model` objects. The `mapModels` method should
* return an array of modified objects.
*
* @param options
* @param {ModelWithSource[]} options.models
*/
mapModels?: (options: {
models: ModelWithSource[];
}) => ModelWithSource[];
modelExtensions?: ModelExtension[];
permissionsForModel?: (options: ConfigDelegate & {
model: ModelWithSource;
userContext: User;
}) => ModelPermissions | undefined;
mapDocuments?: (options: {
documents: DocumentWithSource[];
models: ModelWithSource[];
}) => DocumentWithSource[];
permissionsForDocument?: (options: ConfigDelegate & {
document: DocumentWithSource;
userContext: User;
}) => DocumentPermissions | undefined;
/**
* The `filterAsset` method is used to hide or show asset for specific user
*/
filterAsset?: (options: ConfigDelegate & {
asset: AssetWithSource;
userContext: User;
}) => boolean | undefined;
/**
* The `onContentCreate` method can be used to modify the values before
* they are transformed into operations to create new documents.
*
* This method takes a single `options` parameter with an `object` property
* containing the data needed to create one or more documents with links
* between themselves.
*
* This method should modify the `options.object` and return the modified
* object.
*
* For more information about the structure of the `options.object`, refer
* to the [`object`]{@link OnContentCreateOptions.object} property documentation
*
* @example
* // Iterate over 'object' fields, for every field of type "slug" sanitize
* // its value using a custom 'sanitizeSlug' function.
* mapDocuments: (options) {
* const object = options.object;
* for (const fieldName of Object.keys(object)) {
* const modelField = options.model.fields.find((field) => field.name === fieldName);
* if (modelField.type === 'slug') {
* const fieldValue = object[fieldName];
* object[fieldName] = sanitizeSlug(fieldValue);
* }
* }
* return object;
* }
*
* @param {OnContentCreateOptions} options
*/
onContentCreate?: (options: OnContentCreateOptions) => Promise<Record<string, any>>;
onDocumentCreate?: (options: OnDocumentCreateOptions) => ReturnType<ContentSourceInterface['createDocument']>;
onDocumentUpdate?: (options: OnDocumentUpdateOptions) => ReturnType<ContentSourceInterface['updateDocument']>;
onDocumentDelete?: (options: OnDocumentDeleteOptions) => ReturnType<ContentSourceInterface['deleteDocument']>;
onDocumentArchive?: (options: OnDocumentArchiveOptions) => ReturnTypeOfCSIMethod<'archiveDocument'>;
onDocumentUnarchive?: (options: OnDocumentUnarchiveOptions) => ReturnTypeOfCSIMethod<'unarchiveDocument'>;
onDocumentsPublish?: (options: OnDocumentsPublishOptions) => ReturnType<ContentSourceInterface['publishDocuments']>;
onDocumentsUnpublish?: (options: OnDocumentsUnpublishOptions) => ReturnTypeOfCSIMethod<'unpublishDocuments'>;
/**
* Use `actions` to extend the visual editor with custom actions that invoke
* functions specified by the `run` method.
*/
actions?: (CustomActionGlobal | CustomActionBulk | CustomActionModel)[];
/**
* @deprecated This property is deprecated in favor of using `contentSources`
* and mapping content source models using the `mapModels` and `modelExtensions`
* properties.
*/
models?: NamelessModelMap;
/** @deprecated */
contentModels?: ContentModelMap;
/** @deprecated */
modelsSource?: ModelsSource;
/** @deprecated */
logicFields?: string[];
/** @deprecated */
noEncodeFields?: string[];
/** @deprecated */
omitFields?: string[];
/** @deprecated */
encodedFieldTypes?: string[];
}
export type Import = ContentfulImport | SanityImport;
export interface ContentfulImport {
type: 'contentful';
contentFile: string;
uploadAssets?: boolean;
assetsDirectory?: string;
spaceIdEnvVar?: string;
accessTokenEnvVar?: string;
deliveryTokenEnvVar?: string;
previewTokenEnvVar?: string;
}
export interface SanityImport {
type: 'sanity';
contentFile: string;
sanityStudioPath: string;
deployStudio?: boolean;
deployGraphql?: boolean;
projectIdEnvVar?: string;
datasetEnvVar?: string;
tokenEnvVar?: string;
}
export type Assets = StaticAssets | RelativeAssets;
export interface StaticAssets {
referenceType: 'static';
assetsDir?: string;
staticDir: string;
publicPath: string;
uploadDir?: string;
}
export interface RelativeAssets {
referenceType: 'relative';
assetsDir: string;
staticDir?: string;
publicPath?: string;
uploadDir?: string;
}
export type ContentModelMap = Record<string, ContentModel>;
export interface ContentModel extends ModelMatchFields {
isPage?: boolean;
urlPath?: string;
hideContent?: boolean;
newFilePath?: string;
}
export type PresetSource = PresetSourceFiles;
export interface PresetSourceFiles {
type: 'files';
presetDirs: string[];
}
export type ModelsSource = ModelsSourceFiles | ModelsSourceContentful | ModelsSourceSanity;
export interface ModelsSourceFiles {
type: 'files';
modelDirs: string[];
}
export interface ModelsSourceContentful {
type: 'contentful';
module?: string;
[key: string]: any;
}
export interface ModelsSourceSanity {
type: 'sanity';
sanityStudioPath: string;
module?: string;
[key: string]: any;
}
export type SiteMapFunction = (options: SiteMapOptions) => SiteMapEntry[];
export type TreeViewsFunction = (options: ConfigDelegate) => Promise<TreeViewNode[]>;
export interface SiteMapOptions extends ConfigDelegate {
/**
* When the sitemap function is called for the first time, this property
* will include all the documents from all the content sources.
*
* When a new document is created or an existing document is changed, the
* sitemap function will be called again and this property will contain only
* the new and changed documents.
*
* To access other documents, use getDocumentById() and getDocuments()
* functions.
*/
documents: DocumentWithSource[];
/**
* This property includes all the models from all the content sources.
*/
models: ModelWithSource[];
}
export type SiteMapEntry = SiteMapBaseEntry | SiteMapDocumentEntry;
export interface SiteMapBaseEntry {
/** The URL path of a page */
urlPath: string;
/**
* The human-readable string describing a page.
*
* When used with `document`, the `label` can be omitted, in which case it
* will be computed using the document model's `labelField` property.
*/
label: string;
/**
* A stable ID that uniquely and consistently represents a website page.
* If the `urlPath` of a particular page has changed, its stableId must
* remain the same. The `stableId` allows Stackbit to redirect editors to
* a different URL when the `urlPath` of the currently viewed page has been
* changed. For example, one document can represent multiple website pages
* if it has field-level localization. In this case, the srcDocumentId of
* both sitemap entries should be the same, however the stableId must be
* different.
*
* When used with `document`, the `stableId` can be omitted, in which case
* it will be set to document's `id`.
*/
stableId: string;
/** The locale of the page */
locale?: string;
isHomePage?: boolean;
}
export interface TreeViewBaseNode {
label: string;
stableId: string;
children?: TreeViewNode[];
}
export interface TreeViewDocumentNode {
label?: string;
stableId?: string;
document: {
srcType: string;
srcProjectId: string;
id: string;
};
children?: TreeViewNode[];
}
export type TreeViewNode = TreeViewBaseNode | TreeViewDocumentNode;
export interface SiteMapDocumentEntry extends Omit<SiteMapBaseEntry, 'label' | 'stableId'> {
label?: string;
stableId?: string;
document: {
srcType: string;
srcProjectId: string;
modelName: string;
id: string;
};
}
export interface ContentEngineOptions {
port?: number | string;
host?: string;
}
export interface Experimental {
ssg?: {
name?: string;
passthrough?: string[];
directRoutes?: Record<string, string>;
proxyWebsockets?: boolean;
watch?: {
reinstallPackages?: string[];
};
logPatterns?: {
up?: string[];
};
};
}
export interface Viewport {
label: string;
size: {
width?: number;
height?: number;
};
}
export interface OnContentCreateOptions extends ConfigDelegate {
/**
* The `object` contains data for creating one or more new documents.
* It must conform to the {@link ContentObjectSpecification}.
*/
object: ContentObjectSpecification;
/**
* The model representing the new document
*/
model: ModelWithSource;
/**
* The locale for the new document
*/
locale?: string;
}
export interface OnDocumentCreateOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `createDocument`
* method to create a document. You can transform this object and pass the
* result to the `createDocument` parameter to create a different document.
*/
createDocumentOptions: Parameters<ContentSourceInterface['createDocument']>[0];
/**
* This function creates a document. Pass the `createDocumentOptions`
* parameter to this function to create a document. If you call this
* function without passing any options, original options will be used.
*/
createDocument: (options?: Parameters<ContentSourceInterface['createDocument']>[0]) => ReturnType<ContentSourceInterface['createDocument']>;
}
export interface OnDocumentUpdateOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `updateDocument`
* method to update a document. You can transform this object and pass the
* result to the `updateDocument` parameter to update the document in a
* different way.
*/
updateDocumentOptions: Parameters<ContentSourceInterface['updateDocument']>[0];
/**
* This function updates a document. Pass the `updateDocumentOptions`
* parameter to this function to update a document. If you call this
* function without passing any options, original options will be used.
*/
updateDocument: (options?: Parameters<ContentSourceInterface['updateDocument']>[0]) => ReturnType<ContentSourceInterface['updateDocument']>;
}
export interface OnDocumentDeleteOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `deleteDocument`
* method to delete a document.
*/
deleteDocumentOptions: Parameters<ContentSourceInterface['deleteDocument']>[0];
/**
* This function deletes a document. Pass the `deleteDocumentOptions`
* parameter to this function to delete a document. If you call this
* function without passing any options, original options will be used.
*/
deleteDocument: (options?: Parameters<ContentSourceInterface['deleteDocument']>[0]) => ReturnType<ContentSourceInterface['deleteDocument']>;
}
export interface OnDocumentArchiveOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `archiveDocument`
* method to archive a document.
*/
archiveDocumentOptions: Parameters<NonNullable<ContentSourceInterface['archiveDocument']>>[0];
/**
* This function archives a document. Pass the `archiveDocumentOptions`
* parameter to this function to archive a document. If you call this
* function without passing any options, original options will be used.
*/
archiveDocument: (options?: Parameters<NonNullable<ContentSourceInterface['archiveDocument']>>[0]) => ReturnType<NonNullable<ContentSourceInterface['archiveDocument']>>;
}
export interface OnDocumentUnarchiveOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `unarchiveDocument`
* method to unarchive a document.
*/
unarchiveDocumentOptions: ParametersOfCSIMethod<'unarchiveDocument'>[0];
/**
* This function unarchives a document. Pass the `unarchiveDocumentOptions`
* parameter to this function to unarchive a document. If you call this
* function without passing any options, original options will be used.
*/
unarchiveDocument: (options?: ParametersOfCSIMethod<'unarchiveDocument'>[0]) => ReturnTypeOfCSIMethod<'unarchiveDocument'>;
}
export interface OnDocumentsPublishOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `publishDocuments`
* method to publish documents.
*/
publishDocumentsOptions: Parameters<ContentSourceInterface['publishDocuments']>[0];
/**
* This function publishes documents. Pass the `publishDocumentsOptions`
* parameter to this function to publish documents.
*/
publishDocuments: (options?: Parameters<ContentSourceInterface['publishDocuments']>[0]) => ReturnType<ContentSourceInterface['publishDocuments']>;
}
export interface OnDocumentsUnpublishOptions extends DocumentHookBaseOptions {
/**
* The `options` object is passed to the content source `unpublishDocuments`
* method to unpublish documents.
*/
unpublishDocumentsOptions: ParametersOfCSIMethod<'unpublishDocuments'>[0];
/**
* This function publishes documents. Pass the `unpublishDocumentsOptions`
* parameter to this function to unpublish documents.
*/
unpublishDocuments: (options?: ParametersOfCSIMethod<'unpublishDocuments'>[0]) => ReturnTypeOfCSIMethod<'unpublishDocuments'>;
}
export interface DocumentHookBaseOptions extends ConfigDelegate {
/**
* The content source type of the current document
*/
srcType: string;
/**
* The content source project ID of the current document
*/
srcProjectId: string;
/**
* This object contains functions to create, update, delete and publish
* documents in the content source of the current document.
*
* All functions receive an optional `userContext`. If the `userContext`
* is not specified, a default `userContext` for the current user and the
* content source will be used.
*
* Calling these functions will trigger onDocument hooks. Therefore, do not
* use these function to create, update, delete and publish the current
* document, otherwise you will introduce an infinite loop.
*/
contentSourceActions: ContentSourceActions;
/**
* This function returns an object containing functions to create, update,
* delete and publish documents in the content source matching the received
* `srType` and `srcProjectId`.
*
* The `srcProjectId` is optional. However, if there are multiple
* content source instances of the `srcType`, `undefined` will be returned
*
* All functions receive an optional `userContext`. If the `userContext`
* is not specified, a default `userContext` for the current user and the
* content source will be used.
*
* Calling these functions will trigger onDocument hooks. Therefore, do not
* use these function to create, update, delete and publish the current
* document, otherwise you will introduce an infinite loop.
*
* @param options
* @param {string} options.srcType The content source type
* @param {string} [options.srcProjectId] The content source project ID
*/
getContentSourceActionsForSource: (options: {
srcType: string;
srcProjectId?: string;
}) => ContentSourceActions | undefined;
/**
* Returns the `userContext` of the current user for the content source
* specified by `srType`.
*
* The `userContext` can be used to create, update, delete and publish
* documents on behalf of the current user.
*
* Generally you don't need to pass the `userContext` yourself as it will be
* added automatically.
*
* @param {string} srcType The content source type
*/
getUserContextForContentSourceType: (srcType: string) => User | undefined;
}
export interface ContentSourceActions {
createDocument: (...args: Parameters<ContentSourceInterface['createDocument']>) => ReturnType<ContentSourceInterface['createDocument']>;
/**
* Creates a document from the provided `object` and `modelName`.
* The `object` structure must conform to the {@link ContentObjectSpecification}.
*/
createDocumentFromObject: (options: {
object: ContentObjectSpecification;
modelName: string;
locale?: string;
}) => ReturnType<ContentSourceInterface['createDocument']>;
updateDocument: (...args: Parameters<ContentSourceInterface['updateDocument']>) => ReturnType<ContentSourceInterface['updateDocument']>;
deleteDocument: (...args: Parameters<ContentSourceInterface['deleteDocument']>) => ReturnType<ContentSourceInterface['deleteDocument']>;
publishDocuments: (...args: Parameters<ContentSourceInterface['publishDocuments']>) => ReturnType<ContentSourceInterface['publishDocuments']>;
}
//# sourceMappingURL=config.d.ts.map