@stackbit/types
Advanced tools
Comparing version 0.3.1-develop.1 to 0.4.0-staging.0
import type { FieldType } from './model-fields'; | ||
export declare const InterfaceVersion: "0.2.0"; | ||
/** | ||
@@ -3,0 +4,0 @@ * Front-end frameworks supported by Stackbit without any additional |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.RICH_TEXT_HINT_MAX_LENGTH = exports.RICH_TEXT_MARK_TYPES = exports.RICH_TEXT_NODE_TYPES = exports.STYLE_PROPS_VALUES = exports.STYLE_PROPS = exports.FIELD_TYPES = exports.FIELD_TYPE = exports.CMS_NAMES = exports.SSG_NAMES = void 0; | ||
exports.RICH_TEXT_HINT_MAX_LENGTH = exports.RICH_TEXT_MARK_TYPES = exports.RICH_TEXT_NODE_TYPES = exports.STYLE_PROPS_VALUES = exports.STYLE_PROPS = exports.FIELD_TYPES = exports.FIELD_TYPE = exports.CMS_NAMES = exports.SSG_NAMES = exports.InterfaceVersion = void 0; | ||
exports.InterfaceVersion = '0.2.0'; | ||
/** | ||
@@ -5,0 +6,0 @@ * Front-end frameworks supported by Stackbit without any additional |
@@ -8,21 +8,152 @@ /// <reference types="node" /> | ||
import type { UpdateOperation, UpdateOperationField } from './content-source-operation'; | ||
export interface ContentSourceInterface<UserContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
import { InterfaceVersion } from './consts'; | ||
/** | ||
* A class implementing the `ContentSourceInterface` allows Stackbit to | ||
* communicate with the underlying content source. | ||
* | ||
* The instantiation of the content source is done inside the stackbit.config.ts | ||
* file. The content source may define arbitrary construction options needed to | ||
* connect and communicate with the underlying content source. For example, | ||
* construction options may include project ID, API keys, etc. | ||
* | ||
* The Content Source Interface has four generic types: | ||
* - `SchemaContext`: A generic type the content source instance may use to | ||
* store custom data in the {@link Schema.context} property. Stackbit will | ||
* cache the custom data with the rest of the {@link Schema} data. The cached | ||
* {@link Schema} can be acquired using the {@link InitOptions.cache.getSchema} | ||
* method provided to the {@link init} method. | ||
* - `UserContext`: A generic type defining user-specific context properties | ||
* like a username, an email address and an OAuth accessToken. To use the | ||
* `UserContext`, it is required to create an OAuth integration between | ||
* Stackbit and the underlying content. Please contact Stackbit support for | ||
* more info. | ||
* - `DocumentContext`: A generic type the content source instance may use to | ||
* store custom data in the {@link Document.context} property. Stackbit will | ||
* cache the custom data with the rest of the {@link Document} data. The cached | ||
* {@link Document} can be acquired using the {@link InitOptions.cache.getDocuments} | ||
* and {@link InitOptions.cache.getDocumentById} methods provided to the | ||
* {@link init} method. | ||
* - `AssetContext`: A generic type the content source instance may use to store | ||
* custom data in the {@link Asset.context} property. Stackbit will cache this | ||
* data with the rest of the {@link Asset}. Stackbit will cache the custom | ||
* data with the rest of the {@link Asset} data. The cached {@link Asset} can | ||
* be acquired using the {@link InitOptions.cache.getAssets} and | ||
* {@link InitOptions.cache.getAssetById} methods provided to the {@link init} | ||
* method. | ||
*/ | ||
export interface ContentSourceInterface<UserContext = unknown, SchemaContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
/** | ||
* This function should return the type of the content source. | ||
* The type must be unique among other content sources within the same project. | ||
* The `getVersion` method should return the {@link Version} specifying | ||
* the ContentSourceInterface version the content source module implements, | ||
* and the version of the content source module, possibly matching the | ||
* version in the `package.json`. | ||
* | ||
* You can use the {@link import('./utils').getVersion} utility method to | ||
* read the content source module version from the package.json and get | ||
* the current content source interface version: | ||
* @example | ||
* async getVersion(): Promise<Version> { | ||
* return getVersion({ | ||
* packageJsonPath: path.join(__dirname, '../package.json') | ||
* }); | ||
* } | ||
*/ | ||
getVersion(): Promise<Version>; | ||
/** | ||
* The `getContentSourceType` method should return the type of the content | ||
* source. The content source type must be unique among other content | ||
* sources used by the same project. | ||
*/ | ||
getContentSourceType(): string; | ||
/** | ||
* This function should return the project ID of the content source. | ||
* The ID must be unique among other content sources of the same type. | ||
* The `getProjectId` method should return the unique identifier of the | ||
* content source instance. This identified must be unique among other | ||
* content sources instances of the same content source type. | ||
*/ | ||
getProjectId(): string; | ||
/** | ||
* @deprecated | ||
* | ||
* The `getProjectEnvironment` method should return a string representing | ||
* additional segmentation of a particular content source instance. This | ||
* might be useful when a content source supports projects with multiple | ||
* environments. | ||
*/ | ||
getProjectEnvironment(): string; | ||
/** | ||
* The `getProjectManageUrl` method should return the URL address of the | ||
* underlying content source's web application. Stackbit uses this URL to | ||
* show links to the content source web application. | ||
*/ | ||
getProjectManageUrl(): string; | ||
/** | ||
* This function should initialize the content source by fetching the schema | ||
* and everything else needed to produce the StackbitSchema | ||
* The `init` method should initialize the content source instance. | ||
* | ||
* This is a good place to create and initialize API clients using the | ||
* options passed to the constructor, fetch and cache meta-data that does | ||
* not frequently change, such as users, locales, and other configuration. | ||
* | ||
* This method should start watching for content and schema changes using | ||
* any available synchronization technique. For example, the content source | ||
* may start polling the underlying API, set up server-to-server listeners | ||
* or webhooks. When the content source module detects a change in the | ||
* content or the schema, it should call the {@link InitOptions.cache.updateContent} | ||
* or the {@link InitOptions.cache.invalidateSchema} callbacks. | ||
* | ||
* The content source instance should remain stateless and should not store | ||
* models, documents, or assets. After initializing the content source, | ||
* Stackbit will fetch and cache the needed data using the methods like | ||
* {@link getSchema}, {@link getDocuments}, and {@link getAssets}. When | ||
* the content source instance needs to access the cached data, it may call | ||
* functions with matching names passed to this method inside the | ||
* `options.cache` property. This paradigm ensures that Stackbit and the | ||
* content source instance work on the same data. | ||
* | ||
* @param {InitOptions} options | ||
*/ | ||
init(options: InitOptions): Promise<void>; | ||
init(options: InitOptions<SchemaContext, DocumentContext, AssetContext>): Promise<void>; | ||
/** | ||
* The `reset` method should reset the internal state, clean up any instance | ||
* variables, and cached meta-data fetched in the `init` method and | ||
* re-fetch it again. | ||
*/ | ||
reset(): Promise<void>; | ||
/** | ||
* This function should destroy the content source instance by clearing any | ||
* listeners and observers that might keep the instance from being garbage | ||
* collected. | ||
* | ||
* This function is called when Stackbit reloads the stackbit.config.ts file. | ||
* For example, when the config file is changed. Once the config file is | ||
* reloaded, new instances of content sources are created and initialized. | ||
* And the old instances are destroyed. | ||
*/ | ||
destroy(): Promise<void>; | ||
/** | ||
* Stackbit calls the `onWebhook` method when the underlying content | ||
* source calls a previously configured webhook. | ||
* | ||
* The content source module may set up webhooks between the underlying | ||
* content source and Stackbit using the {@link InitOptions.webhookUrl} | ||
* passed to the {@link init} method. When the underlying content source | ||
* calls the webhook, Stackbit passes the webhook request to this method | ||
* with its data and request headers. Webhooks can be used to trigger the | ||
* {@link InitOptions.cache.updateContent}, and the | ||
* {@link InitOptions.cache.invalidateSchema} callbacks passed to the | ||
* {@link init} method. | ||
* | ||
* This method is not called in local development (when | ||
* {@link InitOptions.localDev} is `true`). | ||
* To debug webhooks locally, you need to create a public URL that | ||
* forwards external webhooks to stackbit dev's internal port: `localhost:8090`. | ||
* You can use a tool like 'ngrok' and run `ngrok http 8090` to create a | ||
* public URL that forwards webhooks to stackbit dev. Ngrok will print the | ||
* public URL it created (e.g., https://xyz.ngrok.io). Then use this URL | ||
* when running stackbit dev: | ||
* `stackbit dev --log-level=debug --csi-webhook-url=https://xyz.ngrok.io/_stackbit/onWebhook` | ||
* | ||
* @param data | ||
* @param {any} data.data | ||
* @param {Record<string, string>} data.headers | ||
*/ | ||
onWebhook?(data: { | ||
@@ -32,34 +163,124 @@ data: unknown; | ||
}): void; | ||
/** | ||
* Stackbit calls the `onFilesChange` method when it detects changes in | ||
* the project files. This method is optional and should be used when the | ||
* content source stores its schema or content in files within the project | ||
* repository. Therefore, if your content source relies on files within | ||
* the project repository, you don't need to set up any file-watching | ||
* processes. Stackbit will watch the files for you and call this method | ||
* when the files are changed. | ||
* | ||
* When this method is called, the content source module should check if the | ||
* changed files represent a document or a model and return a matching result. | ||
* | ||
* @param options | ||
* @param {string[]} options.updatedFiles | ||
* A list of updated files. The file paths are relative to the project | ||
* root folder. | ||
*/ | ||
onFilesChange?({ updatedFiles }: { | ||
updatedFiles: string[]; | ||
}): Promise<{ | ||
schemaChanged?: boolean; | ||
contentChangeEvent?: ContentChangeEvent<DocumentContext, AssetContext>; | ||
invalidateSchema?: boolean; | ||
contentChanges?: ContentChanges<DocumentContext, AssetContext>; | ||
}>; | ||
startWatchingContentUpdates(options: { | ||
getModelMap: () => ModelMap; | ||
getDocument: ({ documentId }: { | ||
documentId: string; | ||
}) => Document<DocumentContext> | undefined; | ||
getAsset: ({ assetId }: { | ||
assetId: string; | ||
}) => Asset<AssetContext> | undefined; | ||
onContentChange: (contentChangeEvent: ContentChangeEvent<DocumentContext, AssetContext>) => Promise<void>; | ||
onSchemaChange: () => void; | ||
}): void; | ||
stopWatchingContentUpdates(): void; | ||
/** | ||
* This function is responsible to fetch and convert content models | ||
* to Stackbit models. | ||
* Stackbit calls the `startWatchingContentUpdates` method after it has | ||
* initialized the content source instance and loaded its schema, documents | ||
* and assets, and is ready to receive the content and the schema updates. | ||
* | ||
* This method may also be called after calling the | ||
* {@link stopWatchingContentUpdates} and as soon as Stackbit app becomes | ||
* active again. | ||
* | ||
* This method should start watching for content and schema updates using | ||
* any available content synchronization mechanism. For example, polling the | ||
* content source's synchronization API or setting up a server-to-server | ||
* listeners. | ||
* | ||
* When the content source instance detects a change in the content or the | ||
* schema, it should call the `updateContent` or the `invalidateSchema` | ||
* callbacks provided inside the `cache` object to the {@link init} method. | ||
* | ||
* Note: if you use webhooks as your content synchronization mechanism, you | ||
* don't need to implement this method. | ||
* | ||
* Note: The content source module should remain stateless in respect to the | ||
* fetched content and schema. It should not store models, documents, or | ||
* assets. If you need to access models, documents, or assets previously | ||
* returned from `getSchema`, `getDocuments`, or `getAssets` methods, use | ||
* the matching functions provided to the {@link init} method inside the | ||
* `options.cache` property. | ||
* | ||
* @param {object} options | ||
* The 'options' parameter is deprecated, use methods passed to the | ||
* {@link init} method. | ||
*/ | ||
getModels(): Promise<Model[]>; | ||
getLocales(): Promise<Locale[]>; | ||
startWatchingContentUpdates?(): void; | ||
/** | ||
* This function should fetch the documents and convert them into Stackbit's | ||
* Document type | ||
* Stackbit calls the `stopWatchingContentUpdates` method after Stackbit app | ||
* has not been used for a while. | ||
* | ||
* You can use this method to stop watching for content and schema updates, | ||
* and stop calling the `updateContent` and the `invalidateSchema` callbacks | ||
* provided to the {@link init} method until the | ||
* {@link startWatchingContentUpdates} method is called again. | ||
* | ||
* This method may be useful when the content synchronization mechanism uses | ||
* rapid polling requests that may consume the monthly API request limit of | ||
* a headless CMS. | ||
* | ||
* Note: if you use webhooks as your content synchronization mechanism, you | ||
* don't need to implement this method. | ||
*/ | ||
getDocuments(options: { | ||
modelMap: ModelMap; | ||
}): Promise<Document<DocumentContext>[]>; | ||
stopWatchingContentUpdates?(): void; | ||
/** | ||
* The `getSchema` method should fetch all the content models from the | ||
* underlying content source and convert them to an array of Stackbit | ||
* [Models]{@link Model}. | ||
* | ||
* Optionally, if the underlying content source supports locales, this | ||
* method may fetch the available locales and convert them to an array of | ||
* Stackbit [Locales]{@link Locale}. | ||
* | ||
* The returned object should be of type {@link Schema} having the | ||
* following interface: | ||
* ```typescript | ||
* interface Schema { | ||
* models: Model[], | ||
* locales?: Locale[] | ||
* } | ||
* ``` | ||
*/ | ||
getSchema(): Promise<Schema<SchemaContext>>; | ||
/** | ||
* The `getDocuments` method should fetch all the documents from the | ||
* underlying content source and convert them to an array of Stackbit | ||
* [Documents]{@link Document}. You can define the `DocumentContext` generic | ||
* type to set the {@link Document.context} to a custom data that your | ||
* content source may need. Stackbit will cache the documents with the | ||
* context data. | ||
*/ | ||
getDocuments(): Promise<Document<DocumentContext>[]>; | ||
/** | ||
* The `getAssets` method should fetch all the assets from the underlying | ||
* content source and convert them to an array Stackbit [Assets]{@link Asset}. | ||
* You can define the `AssetContext` generic type to set the | ||
* {@link Asset.context} to a custom data that your content source may need. | ||
* Stackbit will cache the assets with the context data. | ||
*/ | ||
getAssets(): Promise<Asset<AssetContext>[]>; | ||
/** | ||
* The `hasAccess` method should check if the current user has read/write | ||
* access to the content source. | ||
* | ||
* @param {Object} options | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. Please contact Stackbit support if you want to | ||
* integrate your content source's OAuth flow with Stackbit. | ||
*/ | ||
hasAccess(options: { | ||
@@ -71,16 +292,64 @@ userContext?: UserContext; | ||
}>; | ||
/** | ||
* The `createDocument` method should create a document in the underlying | ||
* content source and return the created document as a Stackbit Document. | ||
* | ||
* @param {Object} options | ||
* @param {Record<string, UpdateOperationField>} options.updateOperationFields | ||
* A map of update operation fields by field names. | ||
* @param {Model} options.model | ||
* A model representing the document to be created. | ||
* @param {string} [options.locale] | ||
* A locale id for the document to be created. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
createDocument(options: { | ||
updateOperationFields: Record<string, UpdateOperationField>; | ||
model: Model; | ||
modelMap: ModelMap; | ||
locale?: string; | ||
defaultLocaleDocumentId?: string; | ||
userContext?: UserContext; | ||
}): Promise<Document<DocumentContext>>; | ||
}): Promise<{ | ||
documentId: string; | ||
}>; | ||
/** | ||
* The `updateDocument()` method should update a document in the underlying | ||
* content source and return the updated document as a Stackbit Document. | ||
* | ||
* @param {Object} options | ||
* @param {Document} options.document | ||
* A document to be updated. | ||
* @param {UpdateOperation[]} options.operations | ||
* An array of update operations. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
updateDocument(options: { | ||
document: Document<DocumentContext>; | ||
operations: UpdateOperation[]; | ||
modelMap: ModelMap; | ||
userContext?: UserContext; | ||
}): Promise<Document<DocumentContext>>; | ||
}): Promise<void>; | ||
/** | ||
* The `deleteDocument` method should delete a document from the underlying | ||
* content source. | ||
* | ||
* @param {Object} options | ||
* @param {Document} options.document | ||
* A document to be deleted. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
deleteDocument(options: { | ||
@@ -90,2 +359,20 @@ document: Document<DocumentContext>; | ||
}): Promise<void>; | ||
/** | ||
* The `uploadAsset` method should upload an asset to the underlying | ||
* content source and return the upload asset as a Stackbit Asset. | ||
* | ||
* @param {Object} options | ||
* @param {string} options.fileName | ||
* The fileName of the asset. | ||
* @param {string} options.mimeType | ||
* The mimeType of the asset. | ||
* @param {string} [options.locale] | ||
* The locale id for the asset. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
uploadAsset(options: { | ||
@@ -99,2 +386,7 @@ url?: string; | ||
}): Promise<Asset<AssetContext>>; | ||
/** | ||
* The `validateDocuments` method should validate documents according to | ||
* the underlying content source validation rules and return an array of | ||
* {@link ValidationError} if the documents do not pass validation. | ||
*/ | ||
validateDocuments(options: { | ||
@@ -108,2 +400,18 @@ documents: Document<DocumentContext>[]; | ||
}>; | ||
/** | ||
* The `publishDocuments` method should publish documents in the | ||
* underlying content source. | ||
* | ||
* @param {Object} options | ||
* @param {Document[]} options.documents | ||
* The array of documents to be published. | ||
* @param {Asset[]} options.assets | ||
* The array of assets to be published. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
publishDocuments(options: { | ||
@@ -115,2 +423,74 @@ documents: Document<DocumentContext>[]; | ||
} | ||
export interface Version { | ||
/** | ||
* The ContentSourceInterface version the content source module implements. | ||
* Use the `getInterfaceVersion()` utility method to get the current version. | ||
*/ | ||
interfaceVersion: typeof InterfaceVersion; | ||
/** | ||
* The current version of the Content Source module. This should be the | ||
* version stored in the package.json of the content source. | ||
*/ | ||
contentSourceVersion: string; | ||
} | ||
export interface InitOptions<SchemaContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
/** | ||
* @type Logger | ||
* A logger object used to log messages to the terminal console. Messages | ||
* logged with this logger will be shown in the console when running | ||
* `stackbit dev`. Use the `--log-level` argument to configure the log | ||
* levels printed by `stackbit dev`. | ||
* | ||
* Use this logger to debug the content source when working locally with | ||
* `stackbit dev` | ||
* | ||
* @example: | ||
* stackbit dev --log-level debug | ||
**/ | ||
logger: Logger; | ||
/** | ||
* @type Logger | ||
* A logger object used to log messages to the "log" panel in the Stackbit | ||
* client application. | ||
* | ||
* Use this logger to print important messages to the user using the | ||
* Stackbit UI. | ||
*/ | ||
userLogger: Logger; | ||
/** | ||
* @type boolean | ||
* A boolean flag indicating if the content source is running in local | ||
* development mode using the `stackbit dev` command (true), or if it is | ||
* running in Stackbit cloud project (false). | ||
*/ | ||
localDev: boolean; | ||
userCommandSpawner?: UserCommandSpawner; | ||
/** | ||
* @type string | ||
* A string representing a Stackbit webhook URL that the content source | ||
* module may use to create webhooks between the content source and Stackbit. | ||
* | ||
* Webhooks need to be set once. Use predefined webhook names to check if | ||
* the webhook was already created. This parameter is empty when `localDev` | ||
* is `true`. | ||
*/ | ||
webhookUrl?: string; | ||
devAppRestartNeeded?: () => void; | ||
/** | ||
* @type Cache | ||
* A Stackbit managed cache for documents, assets and models returned by the | ||
* content source. Use cache methods to get, update, delete and invalidate | ||
* data stored in the cache. | ||
*/ | ||
cache: Cache<SchemaContext, DocumentContext, AssetContext>; | ||
git: GitServiceInterface; | ||
runCommand: CommandRunner; | ||
} | ||
export declare type UserCommandSpawner = (options: SpawnUserCommandOptions) => ChildProcessWithoutNullStreams; | ||
export interface SpawnUserCommandOptions { | ||
command: string; | ||
args?: string[]; | ||
cwd?: string; | ||
env?: NodeJS.ProcessEnv; | ||
} | ||
export declare type RunResult = { | ||
@@ -153,24 +533,61 @@ stdout: string; | ||
} | ||
export interface InitOptions { | ||
logger: Logger; | ||
userLogger: Logger; | ||
userCommandSpawner?: UserCommandSpawner; | ||
localDev: boolean; | ||
webhookUrl?: string; | ||
devAppRestartNeeded?: () => void; | ||
git: GitServiceInterface; | ||
runCommand: CommandRunner; | ||
/** | ||
* A Stackbit managed cache for documents, assets and models returned by the | ||
* content source module. Use cache methods to get, update, delete and invalidate | ||
* data stored in the cache. | ||
*/ | ||
export interface Cache<SchemaContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
/** | ||
* Returns the documents that were originally returned from the content | ||
* source's [getDocuments]{@link ContentSourceInterface#getDocuments} method. | ||
* @return Document[] | ||
*/ | ||
getDocuments: () => Document<DocumentContext>[]; | ||
/** | ||
* Returns the assets that were originally returned from the content | ||
* source's [getAssets]{@link ContentSourceInterface#getAssets} method. | ||
* @return Asset[] | ||
*/ | ||
getAssets: () => Asset<AssetContext>[]; | ||
/** | ||
* Returns the schema that were originally returned from the content | ||
* source's [getSchema]{@link ContentSourceInterface#getSchema} method. | ||
* | ||
* @return Schema | ||
*/ | ||
getSchema: () => Schema<SchemaContext>; | ||
/** | ||
* Returns a document by [Document.id]{@link Document.id}. | ||
* @param options | ||
* @param {string} options.documentId | ||
* @return Document | undefined | ||
*/ | ||
getDocumentById: (documentId: string) => Document<DocumentContext> | undefined; | ||
/** | ||
* Returns an asset by [Asset.id]{@link Asset.id}. | ||
* @param options | ||
* @param {string} options.assetId | ||
* @return Asset | undefined | ||
*/ | ||
getAssetById: (assetId: string) => Asset<AssetContext> | undefined; | ||
/** | ||
* Returns a model by [Model.name]{@link Model.name}. | ||
* @param {string} modelName | ||
* @return Model | undefined | ||
*/ | ||
getModelByName: (modelName: string) => Model | undefined; | ||
updateContent: (contentChanges: ContentChanges<DocumentContext, AssetContext>) => Promise<void>; | ||
invalidateSchema: () => void; | ||
} | ||
export declare type UserCommandSpawner = (options: SpawnUserCommandOptions) => ChildProcessWithoutNullStreams; | ||
export interface SpawnUserCommandOptions { | ||
command: string; | ||
args?: string[]; | ||
cwd?: string; | ||
env?: NodeJS.ProcessEnv; | ||
export interface ContentChanges<DocumentContext = unknown, AssetContext = unknown> { | ||
documents?: Document<DocumentContext>[]; | ||
assets?: Asset<AssetContext>[]; | ||
deletedDocumentIds?: string[]; | ||
deletedAssetIds?: string[]; | ||
} | ||
export interface ContentChangeEvent<DocumentContext = unknown, AssetContext = unknown> { | ||
documents: Document<DocumentContext>[]; | ||
assets: Asset<AssetContext>[]; | ||
deletedDocumentIds: string[]; | ||
deletedAssetIds: string[]; | ||
export declare type ContentChangeEvent<DocumentContext = unknown, AssetContext = unknown> = Required<ContentChanges<DocumentContext, AssetContext>>; | ||
export interface Schema<SchemaContext = unknown> { | ||
models: Model[]; | ||
locales?: Locale[]; | ||
context: SchemaContext; | ||
} | ||
@@ -177,0 +594,0 @@ export declare type ModelMap = Record<string, Model>; |
@@ -12,2 +12,3 @@ export * from './config'; | ||
export * from './sidebar-button'; | ||
export * from './config-delegate'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -28,2 +28,3 @@ "use strict"; | ||
__exportStar(require("./sidebar-button"), exports); | ||
__exportStar(require("./config-delegate"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -5,3 +5,6 @@ /** | ||
import { STYLE_PROPS } from './consts'; | ||
export declare type Field = FieldBasic | FieldEnum | FieldImage | FieldNumber | FieldObject | FieldModel | FieldReference | FieldCrossReference | FieldStyle | FieldList; | ||
import type { DocumentWithSource } from './content-source-document'; | ||
import type { DocumentModelField, DocumentObjectField } from './content-source-document-fields'; | ||
import type { ConfigDelegate } from './config-delegate'; | ||
export declare type Field = FieldString | FieldUrl | FieldSlug | FieldText | FieldMarkdown | FieldHtml | FieldNumber | FieldBoolean | FieldDate | FieldDatetime | FieldColor | FieldJson | FieldRichText | FieldFile | FieldEnum | FieldImage | FieldObject | FieldModel | FieldReference | FieldCrossReference | FieldStyle | FieldList; | ||
export declare type DistributeFieldsExtension<Type extends Field> = Type extends { | ||
@@ -33,3 +36,3 @@ type: 'object'; | ||
export declare type FieldType = Field['type']; | ||
export declare type FieldSpecificProps = FieldBasicProps | FieldEnumProps | FieldImageProps | FieldNumberProps | FieldObjectProps | FieldModelProps | FieldReferenceProps | FieldCrossReferenceProps | FieldStyleProps | FieldListProps; | ||
export declare type FieldSpecificProps = FieldStringProps | FieldUrlProps | FieldSlugProps | FieldTextProps | FieldMarkdownProps | FieldHtmlProps | FieldNumberProps | FieldBooleanProps | FieldDateProps | FieldDatetimeProps | FieldColorProps | FieldJsonProps | FieldRichTextProps | FieldFileProps | FieldEnumProps | FieldImageProps | FieldObjectProps | FieldModelProps | FieldReferenceProps | FieldCrossReferenceProps | FieldStyleProps | FieldListProps; | ||
declare type ExtractByType<Union extends { | ||
@@ -43,6 +46,18 @@ type: FieldType; | ||
export declare type FieldSpecificPropsForField<Type extends Field> = ExtractByType<FieldSpecificProps, Type['type']>; | ||
export declare type FieldBasic = FieldCommonProps & FieldBasicProps; | ||
export declare type FieldString = FieldCommonProps & FieldStringProps; | ||
export declare type FieldUrl = FieldCommonProps & FieldUrlProps; | ||
export declare type FieldSlug = FieldCommonProps & FieldSlugProps; | ||
export declare type FieldText = FieldCommonProps & FieldTextProps; | ||
export declare type FieldMarkdown = FieldCommonProps & FieldMarkdownProps; | ||
export declare type FieldHtml = FieldCommonProps & FieldHtmlProps; | ||
export declare type FieldNumber = FieldCommonProps & FieldNumberProps; | ||
export declare type FieldBoolean = FieldCommonProps & FieldBooleanProps; | ||
export declare type FieldDate = FieldCommonProps & FieldDateProps; | ||
export declare type FieldDatetime = FieldCommonProps & FieldDatetimeProps; | ||
export declare type FieldColor = FieldCommonProps & FieldColorProps; | ||
export declare type FieldJson = FieldCommonProps & FieldJsonProps; | ||
export declare type FieldRichText = FieldCommonProps & FieldRichTextProps; | ||
export declare type FieldFile = FieldCommonProps & FieldFileProps; | ||
export declare type FieldEnum = FieldCommonProps & FieldEnumProps; | ||
export declare type FieldImage = FieldCommonProps & FieldImageProps; | ||
export declare type FieldNumber = FieldCommonProps & FieldNumberProps; | ||
export declare type FieldObject = FieldCommonProps & FieldObjectProps; | ||
@@ -70,5 +85,42 @@ export declare type FieldModel = FieldCommonProps & FieldModelProps; | ||
} | ||
export interface FieldBasicProps { | ||
type: 'string' | 'url' | 'slug' | 'text' | 'markdown' | 'html' | 'boolean' | 'date' | 'datetime' | 'color' | 'file' | 'json' | 'richText'; | ||
export declare type FieldBasicProps = FieldStringProps | FieldUrlProps | FieldSlugProps | FieldTextProps | FieldMarkdownProps | FieldHtmlProps | FieldBooleanProps | FieldDateProps | FieldDatetimeProps | FieldColorProps | FieldJsonProps | FieldRichTextProps | FieldFileProps; | ||
export interface FieldStringProps { | ||
type: 'string'; | ||
} | ||
export interface FieldUrlProps { | ||
type: 'url'; | ||
} | ||
export interface FieldSlugProps { | ||
type: 'slug'; | ||
} | ||
export interface FieldTextProps { | ||
type: 'text'; | ||
} | ||
export interface FieldMarkdownProps { | ||
type: 'markdown'; | ||
} | ||
export interface FieldHtmlProps { | ||
type: 'html'; | ||
} | ||
export interface FieldBooleanProps { | ||
type: 'boolean'; | ||
} | ||
export interface FieldDateProps { | ||
type: 'date'; | ||
} | ||
export interface FieldDatetimeProps { | ||
type: 'datetime'; | ||
} | ||
export interface FieldColorProps { | ||
type: 'color'; | ||
} | ||
export interface FieldJsonProps { | ||
type: 'json'; | ||
} | ||
export interface FieldRichTextProps { | ||
type: 'richText'; | ||
} | ||
export interface FieldFileProps { | ||
type: 'file'; | ||
} | ||
export declare type FieldEnumProps = FieldEnumDropdownProps | FieldEnumThumbnailsProps | FieldEnumPaletteProps | FieldEnumPaletteColorsProps; | ||
@@ -127,2 +179,3 @@ export interface FieldEnumDropdownProps { | ||
labelField?: string; | ||
preview?: DocumentFieldPreview; | ||
thumbnail?: string; | ||
@@ -192,3 +245,27 @@ variantField?: string; | ||
} | ||
export declare type DocumentPreview = DocumentPreviewFunction | PreviewFields; | ||
export declare type DocumentFieldPreview = ObjectPreviewFunction | PreviewFields; | ||
export declare type DocumentPreviewFunction = (options: { | ||
document: DocumentWithSource; | ||
currentLocale?: string; | ||
} & ConfigDelegate) => { | ||
title?: string; | ||
subtitle?: string; | ||
image?: string; | ||
}; | ||
export declare type ObjectPreviewFunction = (options: { | ||
parentDocument: DocumentWithSource; | ||
documentField: DocumentModelField | DocumentObjectField; | ||
currentLocale?: string; | ||
} & ConfigDelegate) => { | ||
title?: string; | ||
subtitle?: string; | ||
image?: string; | ||
}; | ||
export interface PreviewFields { | ||
title?: string; | ||
subtitle?: string; | ||
image?: string; | ||
} | ||
export {}; | ||
//# sourceMappingURL=model-fields.d.ts.map |
/** | ||
* Stackbit Model Types | ||
*/ | ||
import type { Field, FieldExtension, FieldGroupItem } from './model-fields'; | ||
import type { Field, FieldExtension, FieldGroupItem, DocumentPreview, DocumentFieldPreview } from './model-fields'; | ||
import { Document } from './content-source-document'; | ||
export declare type Model = ObjectModel | DataModel | PageModel | ConfigModel; | ||
@@ -29,3 +30,2 @@ export declare type ModelWithSource = Model & { | ||
readOnly?: boolean; | ||
localized?: boolean; | ||
labelField?: string; | ||
@@ -47,9 +47,10 @@ /** @deprecated */ | ||
type: 'object'; | ||
preview?: DocumentFieldPreview; | ||
} | ||
/** @deprecated */ | ||
export interface ConfigModel extends ModelCommonFields { | ||
export interface ConfigModel extends ModelCommonFields, ModelLocalized { | ||
type: 'config'; | ||
file?: string; | ||
} | ||
export interface PageModel extends ModelCommonFields, ModelMatchFields { | ||
export interface PageModel extends ModelCommonFields, ModelMatchFields, ModelLocalized { | ||
type: 'page'; | ||
@@ -60,7 +61,27 @@ layout?: string; | ||
hideContent?: boolean; | ||
preview?: DocumentPreview; | ||
} | ||
export interface DataModel extends ModelCommonFields, ModelMatchFields { | ||
export interface DataModel extends ModelCommonFields, ModelMatchFields, ModelLocalized { | ||
type: 'data'; | ||
filePath?: string; | ||
preview?: DocumentPreview; | ||
} | ||
export interface ModelLocalized { | ||
/** | ||
* Boolean flag indicating if documents belonging to this model are localized. | ||
* If localized is set to true, provide the `locale` function to set the | ||
* document `locale` | ||
*/ | ||
localized?: boolean; | ||
/** | ||
* The `locale` function should return the locale for the passed `document`. | ||
*/ | ||
locale?: (options: { | ||
document: Document; | ||
/** | ||
* The model of the passed `document`. | ||
*/ | ||
model: DataModel | PageModel; | ||
}) => string; | ||
} | ||
//# sourceMappingURL=models.d.ts.map |
@@ -0,1 +1,2 @@ | ||
import type { Version } from './content-source'; | ||
import type { FieldType, Field, FieldForType } from './model-fields'; | ||
@@ -8,8 +9,13 @@ import type { StackbitConfig } from './config'; | ||
}; | ||
export declare function getInterfaceVersion(): "0.2.0"; | ||
export declare function getVersion(options?: { | ||
packageJsonPath?: string; | ||
contentSourceVersion?: string; | ||
}): Promise<Version>; | ||
export declare function isLocalizedField(field: DocumentField | AssetFileField): field is DocumentFieldLocalized | AssetFileFieldLocalized; | ||
/** | ||
* Returns non-localized version of a DocumentField for the provided `locale`. | ||
* If the `field` is localized, and the provided locale is not present, returns | ||
* null. If the `field` is not localized returns the `field` as-is ignoring the | ||
* `locale`. | ||
* If the `field` is localized, and the provided locale is not present, this | ||
* function returns `undefined`. If the `field` is not localized, this function | ||
* returns the `field` as-is ignoring the `locale`. | ||
* | ||
@@ -46,3 +52,3 @@ * @example Passing localized field | ||
*/ | ||
export declare function getLocalizedFieldForLocale<Type extends FieldType>(field: DocumentFieldForType<Type>, locale?: string): DocumentFieldNonLocalizedForType<Type> | null; | ||
export declare function getLocalizedFieldForLocale<Type extends FieldType>(field?: DocumentFieldForType<Type>, locale?: string): DocumentFieldNonLocalizedForType<Type> | undefined; | ||
export declare function isOneOfFieldTypes<T extends FieldType>(fieldType: FieldType, fieldTypes: ReadonlyArray<T>): fieldType is T; | ||
@@ -49,0 +55,0 @@ export declare function isModelFieldOneOfFieldTypes<T extends FieldType>(modelField: Field, fieldTypes: ReadonlyArray<T>): modelField is FieldForType<T>; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defineStackbitConfig = exports.isDocumentFieldOneOfFieldTypes = exports.isModelFieldOneOfFieldTypes = exports.isOneOfFieldTypes = exports.getLocalizedFieldForLocale = exports.isLocalizedField = void 0; | ||
exports.defineStackbitConfig = exports.isDocumentFieldOneOfFieldTypes = exports.isModelFieldOneOfFieldTypes = exports.isOneOfFieldTypes = exports.getLocalizedFieldForLocale = exports.isLocalizedField = exports.getVersion = exports.getInterfaceVersion = void 0; | ||
const consts_1 = require("./consts"); | ||
function getInterfaceVersion() { | ||
return consts_1.InterfaceVersion; | ||
} | ||
exports.getInterfaceVersion = getInterfaceVersion; | ||
async function getVersion(options = {}) { | ||
if (options.contentSourceVersion) { | ||
return { | ||
interfaceVersion: consts_1.InterfaceVersion, | ||
contentSourceVersion: options.contentSourceVersion | ||
}; | ||
} | ||
else if (options.packageJsonPath) { | ||
const packageJson = await Promise.resolve().then(() => __importStar(require(options.packageJsonPath))); | ||
return { | ||
interfaceVersion: consts_1.InterfaceVersion, | ||
contentSourceVersion: packageJson.version | ||
}; | ||
} | ||
else { | ||
return { | ||
interfaceVersion: consts_1.InterfaceVersion, | ||
contentSourceVersion: '' | ||
}; | ||
} | ||
} | ||
exports.getVersion = getVersion; | ||
function isLocalizedField(field) { | ||
@@ -10,5 +60,5 @@ return !!field.localized; | ||
* Returns non-localized version of a DocumentField for the provided `locale`. | ||
* If the `field` is localized, and the provided locale is not present, returns | ||
* null. If the `field` is not localized returns the `field` as-is ignoring the | ||
* `locale`. | ||
* If the `field` is localized, and the provided locale is not present, this | ||
* function returns `undefined`. If the `field` is not localized, this function | ||
* returns the `field` as-is ignoring the `locale`. | ||
* | ||
@@ -46,10 +96,10 @@ * @example Passing localized field | ||
function getLocalizedFieldForLocale(field, locale) { | ||
if (field.localized) { | ||
if (field && field.localized) { | ||
if (!locale) { | ||
return null; | ||
return undefined; | ||
} | ||
const { localized, locales, ...base } = field; | ||
const localizedField = locales[locale]; | ||
const localizedField = locales === null || locales === void 0 ? void 0 : locales[locale]; | ||
if (!localizedField) { | ||
return null; | ||
return undefined; | ||
} | ||
@@ -61,5 +111,3 @@ return { | ||
} | ||
else { | ||
return field; | ||
} | ||
return field; | ||
} | ||
@@ -66,0 +114,0 @@ exports.getLocalizedFieldForLocale = getLocalizedFieldForLocale; |
{ | ||
"name": "@stackbit/types", | ||
"version": "0.3.1-develop.1", | ||
"version": "0.4.0-staging.0", | ||
"description": "Types for Stackbit config and Content Source Interface", | ||
@@ -42,3 +42,3 @@ "main": "dist/index.js", | ||
}, | ||
"gitHead": "6a2c36684d06f4b141ab9214b0447c690277fe4d" | ||
"gitHead": "f4d3d35b36a78b28cb41f26279f7e3afd47d9691" | ||
} |
import type { FieldType } from './model-fields'; | ||
export const InterfaceVersion = '0.2.0' as const; | ||
/** | ||
@@ -4,0 +6,0 @@ * Front-end frameworks supported by Stackbit without any additional |
@@ -6,30 +6,185 @@ import type { ChildProcessWithoutNullStreams } from 'child_process'; | ||
import type { UpdateOperation, UpdateOperationField } from './content-source-operation'; | ||
import { InterfaceVersion } from './consts'; | ||
export interface ContentSourceInterface<UserContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
/** | ||
* A class implementing the `ContentSourceInterface` allows Stackbit to | ||
* communicate with the underlying content source. | ||
* | ||
* The instantiation of the content source is done inside the stackbit.config.ts | ||
* file. The content source may define arbitrary construction options needed to | ||
* connect and communicate with the underlying content source. For example, | ||
* construction options may include project ID, API keys, etc. | ||
* | ||
* The Content Source Interface has four generic types: | ||
* - `SchemaContext`: A generic type the content source instance may use to | ||
* store custom data in the {@link Schema.context} property. Stackbit will | ||
* cache the custom data with the rest of the {@link Schema} data. The cached | ||
* {@link Schema} can be acquired using the {@link InitOptions.cache.getSchema} | ||
* method provided to the {@link init} method. | ||
* - `UserContext`: A generic type defining user-specific context properties | ||
* like a username, an email address and an OAuth accessToken. To use the | ||
* `UserContext`, it is required to create an OAuth integration between | ||
* Stackbit and the underlying content. Please contact Stackbit support for | ||
* more info. | ||
* - `DocumentContext`: A generic type the content source instance may use to | ||
* store custom data in the {@link Document.context} property. Stackbit will | ||
* cache the custom data with the rest of the {@link Document} data. The cached | ||
* {@link Document} can be acquired using the {@link InitOptions.cache.getDocuments} | ||
* and {@link InitOptions.cache.getDocumentById} methods provided to the | ||
* {@link init} method. | ||
* - `AssetContext`: A generic type the content source instance may use to store | ||
* custom data in the {@link Asset.context} property. Stackbit will cache this | ||
* data with the rest of the {@link Asset}. Stackbit will cache the custom | ||
* data with the rest of the {@link Asset} data. The cached {@link Asset} can | ||
* be acquired using the {@link InitOptions.cache.getAssets} and | ||
* {@link InitOptions.cache.getAssetById} methods provided to the {@link init} | ||
* method. | ||
*/ | ||
export interface ContentSourceInterface< | ||
UserContext = unknown, | ||
SchemaContext = unknown, | ||
DocumentContext = unknown, | ||
AssetContext = unknown | ||
> { | ||
/** | ||
* This function should return the type of the content source. | ||
* The type must be unique among other content sources within the same project. | ||
* The `getVersion` method should return the {@link Version} specifying | ||
* the ContentSourceInterface version the content source module implements, | ||
* and the version of the content source module, possibly matching the | ||
* version in the `package.json`. | ||
* | ||
* You can use the {@link import('./utils').getVersion} utility method to | ||
* read the content source module version from the package.json and get | ||
* the current content source interface version: | ||
* @example | ||
* async getVersion(): Promise<Version> { | ||
* return getVersion({ | ||
* packageJsonPath: path.join(__dirname, '../package.json') | ||
* }); | ||
* } | ||
*/ | ||
getVersion(): Promise<Version>; | ||
/** | ||
* The `getContentSourceType` method should return the type of the content | ||
* source. The content source type must be unique among other content | ||
* sources used by the same project. | ||
*/ | ||
getContentSourceType(): string; | ||
/** | ||
* This function should return the project ID of the content source. | ||
* The ID must be unique among other content sources of the same type. | ||
* The `getProjectId` method should return the unique identifier of the | ||
* content source instance. This identified must be unique among other | ||
* content sources instances of the same content source type. | ||
*/ | ||
getProjectId(): string; | ||
/** | ||
* @deprecated | ||
* | ||
* The `getProjectEnvironment` method should return a string representing | ||
* additional segmentation of a particular content source instance. This | ||
* might be useful when a content source supports projects with multiple | ||
* environments. | ||
*/ | ||
getProjectEnvironment(): string; | ||
/** | ||
* The `getProjectManageUrl` method should return the URL address of the | ||
* underlying content source's web application. Stackbit uses this URL to | ||
* show links to the content source web application. | ||
*/ | ||
getProjectManageUrl(): string; | ||
/** | ||
* This function should initialize the content source by fetching the schema | ||
* and everything else needed to produce the StackbitSchema | ||
* The `init` method should initialize the content source instance. | ||
* | ||
* This is a good place to create and initialize API clients using the | ||
* options passed to the constructor, fetch and cache meta-data that does | ||
* not frequently change, such as users, locales, and other configuration. | ||
* | ||
* This method should start watching for content and schema changes using | ||
* any available synchronization technique. For example, the content source | ||
* may start polling the underlying API, set up server-to-server listeners | ||
* or webhooks. When the content source module detects a change in the | ||
* content or the schema, it should call the {@link InitOptions.cache.updateContent} | ||
* or the {@link InitOptions.cache.invalidateSchema} callbacks. | ||
* | ||
* The content source instance should remain stateless and should not store | ||
* models, documents, or assets. After initializing the content source, | ||
* Stackbit will fetch and cache the needed data using the methods like | ||
* {@link getSchema}, {@link getDocuments}, and {@link getAssets}. When | ||
* the content source instance needs to access the cached data, it may call | ||
* functions with matching names passed to this method inside the | ||
* `options.cache` property. This paradigm ensures that Stackbit and the | ||
* content source instance work on the same data. | ||
* | ||
* @param {InitOptions} options | ||
*/ | ||
init(options: InitOptions): Promise<void>; | ||
init(options: InitOptions<SchemaContext, DocumentContext, AssetContext>): Promise<void>; | ||
/** | ||
* The `reset` method should reset the internal state, clean up any instance | ||
* variables, and cached meta-data fetched in the `init` method and | ||
* re-fetch it again. | ||
*/ | ||
reset(): Promise<void>; | ||
/** | ||
* This function should destroy the content source instance by clearing any | ||
* listeners and observers that might keep the instance from being garbage | ||
* collected. | ||
* | ||
* This function is called when Stackbit reloads the stackbit.config.ts file. | ||
* For example, when the config file is changed. Once the config file is | ||
* reloaded, new instances of content sources are created and initialized. | ||
* And the old instances are destroyed. | ||
*/ | ||
destroy(): Promise<void>; | ||
/** | ||
* Stackbit calls the `onWebhook` method when the underlying content | ||
* source calls a previously configured webhook. | ||
* | ||
* The content source module may set up webhooks between the underlying | ||
* content source and Stackbit using the {@link InitOptions.webhookUrl} | ||
* passed to the {@link init} method. When the underlying content source | ||
* calls the webhook, Stackbit passes the webhook request to this method | ||
* with its data and request headers. Webhooks can be used to trigger the | ||
* {@link InitOptions.cache.updateContent}, and the | ||
* {@link InitOptions.cache.invalidateSchema} callbacks passed to the | ||
* {@link init} method. | ||
* | ||
* This method is not called in local development (when | ||
* {@link InitOptions.localDev} is `true`). | ||
* To debug webhooks locally, you need to create a public URL that | ||
* forwards external webhooks to stackbit dev's internal port: `localhost:8090`. | ||
* You can use a tool like 'ngrok' and run `ngrok http 8090` to create a | ||
* public URL that forwards webhooks to stackbit dev. Ngrok will print the | ||
* public URL it created (e.g., https://xyz.ngrok.io). Then use this URL | ||
* when running stackbit dev: | ||
* `stackbit dev --log-level=debug --csi-webhook-url=https://xyz.ngrok.io/_stackbit/onWebhook` | ||
* | ||
* @param data | ||
* @param {any} data.data | ||
* @param {Record<string, string>} data.headers | ||
*/ | ||
onWebhook?(data: { data: unknown; headers: Record<string, string> }): void; | ||
/** | ||
* Stackbit calls the `onFilesChange` method when it detects changes in | ||
* the project files. This method is optional and should be used when the | ||
* content source stores its schema or content in files within the project | ||
* repository. Therefore, if your content source relies on files within | ||
* the project repository, you don't need to set up any file-watching | ||
* processes. Stackbit will watch the files for you and call this method | ||
* when the files are changed. | ||
* | ||
* When this method is called, the content source module should check if the | ||
* changed files represent a document or a model and return a matching result. | ||
* | ||
* @param options | ||
* @param {string[]} options.updatedFiles | ||
* A list of updated files. The file paths are relative to the project | ||
* root folder. | ||
*/ | ||
onFilesChange?({ | ||
@@ -39,50 +194,192 @@ updatedFiles | ||
updatedFiles: string[]; | ||
}): Promise<{ schemaChanged?: boolean; contentChangeEvent?: ContentChangeEvent<DocumentContext, AssetContext> }>; | ||
}): Promise<{ invalidateSchema?: boolean; contentChanges?: ContentChanges<DocumentContext, AssetContext> }>; | ||
startWatchingContentUpdates(options: { | ||
getModelMap: () => ModelMap; | ||
getDocument: ({ documentId }: { documentId: string }) => Document<DocumentContext> | undefined; | ||
getAsset: ({ assetId }: { assetId: string }) => Asset<AssetContext> | undefined; | ||
onContentChange: (contentChangeEvent: ContentChangeEvent<DocumentContext, AssetContext>) => Promise<void>; | ||
onSchemaChange: () => void; | ||
}): void; | ||
/** | ||
* Stackbit calls the `startWatchingContentUpdates` method after it has | ||
* initialized the content source instance and loaded its schema, documents | ||
* and assets, and is ready to receive the content and the schema updates. | ||
* | ||
* This method may also be called after calling the | ||
* {@link stopWatchingContentUpdates} and as soon as Stackbit app becomes | ||
* active again. | ||
* | ||
* This method should start watching for content and schema updates using | ||
* any available content synchronization mechanism. For example, polling the | ||
* content source's synchronization API or setting up a server-to-server | ||
* listeners. | ||
* | ||
* When the content source instance detects a change in the content or the | ||
* schema, it should call the `updateContent` or the `invalidateSchema` | ||
* callbacks provided inside the `cache` object to the {@link init} method. | ||
* | ||
* Note: if you use webhooks as your content synchronization mechanism, you | ||
* don't need to implement this method. | ||
* | ||
* Note: The content source module should remain stateless in respect to the | ||
* fetched content and schema. It should not store models, documents, or | ||
* assets. If you need to access models, documents, or assets previously | ||
* returned from `getSchema`, `getDocuments`, or `getAssets` methods, use | ||
* the matching functions provided to the {@link init} method inside the | ||
* `options.cache` property. | ||
* | ||
* @param {object} options | ||
* The 'options' parameter is deprecated, use methods passed to the | ||
* {@link init} method. | ||
*/ | ||
startWatchingContentUpdates?(): void; | ||
stopWatchingContentUpdates(): void; | ||
/** | ||
* Stackbit calls the `stopWatchingContentUpdates` method after Stackbit app | ||
* has not been used for a while. | ||
* | ||
* You can use this method to stop watching for content and schema updates, | ||
* and stop calling the `updateContent` and the `invalidateSchema` callbacks | ||
* provided to the {@link init} method until the | ||
* {@link startWatchingContentUpdates} method is called again. | ||
* | ||
* This method may be useful when the content synchronization mechanism uses | ||
* rapid polling requests that may consume the monthly API request limit of | ||
* a headless CMS. | ||
* | ||
* Note: if you use webhooks as your content synchronization mechanism, you | ||
* don't need to implement this method. | ||
*/ | ||
stopWatchingContentUpdates?(): void; | ||
/** | ||
* This function is responsible to fetch and convert content models | ||
* to Stackbit models. | ||
* The `getSchema` method should fetch all the content models from the | ||
* underlying content source and convert them to an array of Stackbit | ||
* [Models]{@link Model}. | ||
* | ||
* Optionally, if the underlying content source supports locales, this | ||
* method may fetch the available locales and convert them to an array of | ||
* Stackbit [Locales]{@link Locale}. | ||
* | ||
* The returned object should be of type {@link Schema} having the | ||
* following interface: | ||
* ```typescript | ||
* interface Schema { | ||
* models: Model[], | ||
* locales?: Locale[] | ||
* } | ||
* ``` | ||
*/ | ||
getModels(): Promise<Model[]>; | ||
getSchema(): Promise<Schema<SchemaContext>>; | ||
getLocales(): Promise<Locale[]>; | ||
/** | ||
* The `getDocuments` method should fetch all the documents from the | ||
* underlying content source and convert them to an array of Stackbit | ||
* [Documents]{@link Document}. You can define the `DocumentContext` generic | ||
* type to set the {@link Document.context} to a custom data that your | ||
* content source may need. Stackbit will cache the documents with the | ||
* context data. | ||
*/ | ||
getDocuments(): Promise<Document<DocumentContext>[]>; | ||
/** | ||
* This function should fetch the documents and convert them into Stackbit's | ||
* Document type | ||
* The `getAssets` method should fetch all the assets from the underlying | ||
* content source and convert them to an array Stackbit [Assets]{@link Asset}. | ||
* You can define the `AssetContext` generic type to set the | ||
* {@link Asset.context} to a custom data that your content source may need. | ||
* Stackbit will cache the assets with the context data. | ||
*/ | ||
getDocuments(options: { modelMap: ModelMap }): Promise<Document<DocumentContext>[]>; | ||
getAssets(): Promise<Asset<AssetContext>[]>; | ||
/** | ||
* The `hasAccess` method should check if the current user has read/write | ||
* access to the content source. | ||
* | ||
* @param {Object} options | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. Please contact Stackbit support if you want to | ||
* integrate your content source's OAuth flow with Stackbit. | ||
*/ | ||
hasAccess(options: { userContext?: UserContext }): Promise<{ hasConnection: boolean; hasPermissions: boolean }>; | ||
/** | ||
* The `createDocument` method should create a document in the underlying | ||
* content source and return the created document as a Stackbit Document. | ||
* | ||
* @param {Object} options | ||
* @param {Record<string, UpdateOperationField>} options.updateOperationFields | ||
* A map of update operation fields by field names. | ||
* @param {Model} options.model | ||
* A model representing the document to be created. | ||
* @param {string} [options.locale] | ||
* A locale id for the document to be created. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
createDocument(options: { | ||
updateOperationFields: Record<string, UpdateOperationField>; | ||
model: Model; | ||
modelMap: ModelMap; | ||
locale?: string; | ||
defaultLocaleDocumentId?: string; | ||
userContext?: UserContext; | ||
}): Promise<Document<DocumentContext>>; | ||
}): Promise<{ documentId: string }>; | ||
/** | ||
* The `updateDocument()` method should update a document in the underlying | ||
* content source and return the updated document as a Stackbit Document. | ||
* | ||
* @param {Object} options | ||
* @param {Document} options.document | ||
* A document to be updated. | ||
* @param {UpdateOperation[]} options.operations | ||
* An array of update operations. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
updateDocument(options: { | ||
document: Document<DocumentContext>; | ||
operations: UpdateOperation[]; | ||
modelMap: ModelMap; | ||
userContext?: UserContext; | ||
}): Promise<Document<DocumentContext>>; | ||
}): Promise<void>; | ||
/** | ||
* The `deleteDocument` method should delete a document from the underlying | ||
* content source. | ||
* | ||
* @param {Object} options | ||
* @param {Document} options.document | ||
* A document to be deleted. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
deleteDocument(options: { document: Document<DocumentContext>; userContext?: UserContext }): Promise<void>; | ||
/** | ||
* The `uploadAsset` method should upload an asset to the underlying | ||
* content source and return the upload asset as a Stackbit Asset. | ||
* | ||
* @param {Object} options | ||
* @param {string} options.fileName | ||
* The fileName of the asset. | ||
* @param {string} options.mimeType | ||
* The mimeType of the asset. | ||
* @param {string} [options.locale] | ||
* The locale id for the asset. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
uploadAsset(options: { | ||
@@ -97,2 +394,7 @@ url?: string; | ||
/** | ||
* The `validateDocuments` method should validate documents according to | ||
* the underlying content source validation rules and return an array of | ||
* {@link ValidationError} if the documents do not pass validation. | ||
*/ | ||
validateDocuments(options: { | ||
@@ -105,2 +407,18 @@ documents: Document<DocumentContext>[]; | ||
/** | ||
* The `publishDocuments` method should publish documents in the | ||
* underlying content source. | ||
* | ||
* @param {Object} options | ||
* @param {Document[]} options.documents | ||
* The array of documents to be published. | ||
* @param {Asset[]} options.assets | ||
* The array of assets to be published. | ||
* @param {UserContext} [options.userContext] | ||
* User properties provided by the OAuth flow between Stackbit and the | ||
* underlying content source. The type of the `userContext` is defined by | ||
* the `UserContext` generic type. The `userContext` is passed only if | ||
* there is an OAuth integration between Stackbit and the underlying | ||
* content source. | ||
*/ | ||
publishDocuments(options: { | ||
@@ -113,2 +431,78 @@ documents: Document<DocumentContext>[]; | ||
export interface Version { | ||
/** | ||
* The ContentSourceInterface version the content source module implements. | ||
* Use the `getInterfaceVersion()` utility method to get the current version. | ||
*/ | ||
interfaceVersion: typeof InterfaceVersion; | ||
/** | ||
* The current version of the Content Source module. This should be the | ||
* version stored in the package.json of the content source. | ||
*/ | ||
contentSourceVersion: string; | ||
} | ||
export interface InitOptions<SchemaContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
/** | ||
* @type Logger | ||
* A logger object used to log messages to the terminal console. Messages | ||
* logged with this logger will be shown in the console when running | ||
* `stackbit dev`. Use the `--log-level` argument to configure the log | ||
* levels printed by `stackbit dev`. | ||
* | ||
* Use this logger to debug the content source when working locally with | ||
* `stackbit dev` | ||
* | ||
* @example: | ||
* stackbit dev --log-level debug | ||
**/ | ||
logger: Logger; | ||
/** | ||
* @type Logger | ||
* A logger object used to log messages to the "log" panel in the Stackbit | ||
* client application. | ||
* | ||
* Use this logger to print important messages to the user using the | ||
* Stackbit UI. | ||
*/ | ||
userLogger: Logger; | ||
/** | ||
* @type boolean | ||
* A boolean flag indicating if the content source is running in local | ||
* development mode using the `stackbit dev` command (true), or if it is | ||
* running in Stackbit cloud project (false). | ||
*/ | ||
localDev: boolean; | ||
userCommandSpawner?: UserCommandSpawner; | ||
/** | ||
* @type string | ||
* A string representing a Stackbit webhook URL that the content source | ||
* module may use to create webhooks between the content source and Stackbit. | ||
* | ||
* Webhooks need to be set once. Use predefined webhook names to check if | ||
* the webhook was already created. This parameter is empty when `localDev` | ||
* is `true`. | ||
*/ | ||
webhookUrl?: string; | ||
devAppRestartNeeded?: () => void; | ||
/** | ||
* @type Cache | ||
* A Stackbit managed cache for documents, assets and models returned by the | ||
* content source. Use cache methods to get, update, delete and invalidate | ||
* data stored in the cache. | ||
*/ | ||
cache: Cache<SchemaContext, DocumentContext, AssetContext>; | ||
git: GitServiceInterface; | ||
runCommand: CommandRunner; | ||
} | ||
export type UserCommandSpawner = (options: SpawnUserCommandOptions) => ChildProcessWithoutNullStreams; | ||
export interface SpawnUserCommandOptions { | ||
command: string; | ||
args?: string[]; | ||
cwd?: string; | ||
env?: NodeJS.ProcessEnv; | ||
} | ||
export type RunResult = { stdout: string; stderr: string; exitCode?: number; err?: Error }; | ||
@@ -148,27 +542,67 @@ | ||
export interface InitOptions { | ||
logger: Logger; | ||
userLogger: Logger; | ||
userCommandSpawner?: UserCommandSpawner; | ||
localDev: boolean; | ||
webhookUrl?: string; | ||
devAppRestartNeeded?: () => void; | ||
git: GitServiceInterface; | ||
runCommand: CommandRunner; | ||
/** | ||
* A Stackbit managed cache for documents, assets and models returned by the | ||
* content source module. Use cache methods to get, update, delete and invalidate | ||
* data stored in the cache. | ||
*/ | ||
export interface Cache<SchemaContext = unknown, DocumentContext = unknown, AssetContext = unknown> { | ||
/** | ||
* Returns the documents that were originally returned from the content | ||
* source's [getDocuments]{@link ContentSourceInterface#getDocuments} method. | ||
* @return Document[] | ||
*/ | ||
getDocuments: () => Document<DocumentContext>[]; | ||
/** | ||
* Returns the assets that were originally returned from the content | ||
* source's [getAssets]{@link ContentSourceInterface#getAssets} method. | ||
* @return Asset[] | ||
*/ | ||
getAssets: () => Asset<AssetContext>[]; | ||
/** | ||
* Returns the schema that were originally returned from the content | ||
* source's [getSchema]{@link ContentSourceInterface#getSchema} method. | ||
* | ||
* @return Schema | ||
*/ | ||
getSchema: () => Schema<SchemaContext>; | ||
/** | ||
* Returns a document by [Document.id]{@link Document.id}. | ||
* @param options | ||
* @param {string} options.documentId | ||
* @return Document | undefined | ||
*/ | ||
getDocumentById: (documentId: string) => Document<DocumentContext> | undefined; | ||
/** | ||
* Returns an asset by [Asset.id]{@link Asset.id}. | ||
* @param options | ||
* @param {string} options.assetId | ||
* @return Asset | undefined | ||
*/ | ||
getAssetById: (assetId: string) => Asset<AssetContext> | undefined; | ||
/** | ||
* Returns a model by [Model.name]{@link Model.name}. | ||
* @param {string} modelName | ||
* @return Model | undefined | ||
*/ | ||
getModelByName: (modelName: string) => Model | undefined; | ||
updateContent: (contentChanges: ContentChanges<DocumentContext, AssetContext>) => Promise<void>; | ||
invalidateSchema: () => void; | ||
} | ||
export type UserCommandSpawner = (options: SpawnUserCommandOptions) => ChildProcessWithoutNullStreams; | ||
export interface SpawnUserCommandOptions { | ||
command: string; | ||
args?: string[]; | ||
cwd?: string; | ||
env?: NodeJS.ProcessEnv; | ||
export interface ContentChanges<DocumentContext = unknown, AssetContext = unknown> { | ||
documents?: Document<DocumentContext>[]; | ||
assets?: Asset<AssetContext>[]; | ||
deletedDocumentIds?: string[]; | ||
deletedAssetIds?: string[]; | ||
} | ||
export interface ContentChangeEvent<DocumentContext = unknown, AssetContext = unknown> { | ||
documents: Document<DocumentContext>[]; | ||
assets: Asset<AssetContext>[]; | ||
deletedDocumentIds: string[]; | ||
deletedAssetIds: string[]; | ||
// backward compatibility | ||
export type ContentChangeEvent<DocumentContext = unknown, AssetContext = unknown> = Required< | ||
ContentChanges<DocumentContext, AssetContext> | ||
>; | ||
export interface Schema<SchemaContext = unknown> { | ||
models: Model[]; | ||
locales?: Locale[]; | ||
context: SchemaContext; | ||
} | ||
@@ -175,0 +609,0 @@ |
@@ -12,1 +12,2 @@ export * from './config'; | ||
export * from './sidebar-button'; | ||
export * from './config-delegate'; |
@@ -6,8 +6,23 @@ /** | ||
import { STYLE_PROPS } from './consts'; | ||
import type { DocumentWithSource } from './content-source-document'; | ||
import type { DocumentModelField, DocumentObjectField } from './content-source-document-fields'; | ||
import type { ConfigDelegate } from './config-delegate'; | ||
export type Field = | ||
| FieldBasic | ||
| FieldString | ||
| FieldUrl | ||
| FieldSlug | ||
| FieldText | ||
| FieldMarkdown | ||
| FieldHtml | ||
| FieldNumber | ||
| FieldBoolean | ||
| FieldDate | ||
| FieldDatetime | ||
| FieldColor | ||
| FieldJson | ||
| FieldRichText | ||
| FieldFile | ||
| FieldEnum | ||
| FieldImage | ||
| FieldNumber | ||
| FieldObject | ||
@@ -46,6 +61,18 @@ | FieldModel | ||
export type FieldSpecificProps = | ||
| FieldBasicProps | ||
| FieldStringProps | ||
| FieldUrlProps | ||
| FieldSlugProps | ||
| FieldTextProps | ||
| FieldMarkdownProps | ||
| FieldHtmlProps | ||
| FieldNumberProps | ||
| FieldBooleanProps | ||
| FieldDateProps | ||
| FieldDatetimeProps | ||
| FieldColorProps | ||
| FieldJsonProps | ||
| FieldRichTextProps | ||
| FieldFileProps | ||
| FieldEnumProps | ||
| FieldImageProps | ||
| FieldNumberProps | ||
| FieldObjectProps | ||
@@ -65,6 +92,18 @@ | FieldModelProps | ||
export type FieldBasic = FieldCommonProps & FieldBasicProps; | ||
export type FieldString = FieldCommonProps & FieldStringProps; | ||
export type FieldUrl = FieldCommonProps & FieldUrlProps; | ||
export type FieldSlug = FieldCommonProps & FieldSlugProps; | ||
export type FieldText = FieldCommonProps & FieldTextProps; | ||
export type FieldMarkdown = FieldCommonProps & FieldMarkdownProps; | ||
export type FieldHtml = FieldCommonProps & FieldHtmlProps; | ||
export type FieldNumber = FieldCommonProps & FieldNumberProps; | ||
export type FieldBoolean = FieldCommonProps & FieldBooleanProps; | ||
export type FieldDate = FieldCommonProps & FieldDateProps; | ||
export type FieldDatetime = FieldCommonProps & FieldDatetimeProps; | ||
export type FieldColor = FieldCommonProps & FieldColorProps; | ||
export type FieldJson = FieldCommonProps & FieldJsonProps; | ||
export type FieldRichText = FieldCommonProps & FieldRichTextProps; | ||
export type FieldFile = FieldCommonProps & FieldFileProps; | ||
export type FieldEnum = FieldCommonProps & FieldEnumProps; | ||
export type FieldImage = FieldCommonProps & FieldImageProps; | ||
export type FieldNumber = FieldCommonProps & FieldNumberProps; | ||
export type FieldObject = FieldCommonProps & FieldObjectProps; | ||
@@ -95,21 +134,69 @@ export type FieldModel = FieldCommonProps & FieldModelProps; | ||
// export type FieldType = typeof FIELD_TYPES[number]; | ||
export type FieldBasicProps = | ||
| FieldStringProps | ||
| FieldUrlProps | ||
| FieldSlugProps | ||
| FieldTextProps | ||
| FieldMarkdownProps | ||
| FieldHtmlProps | ||
| FieldBooleanProps | ||
| FieldDateProps | ||
| FieldDatetimeProps | ||
| FieldColorProps | ||
| FieldJsonProps | ||
| FieldRichTextProps | ||
| FieldFileProps; | ||
export interface FieldBasicProps { | ||
type: | ||
| 'string' | ||
| 'url' | ||
| 'slug' | ||
| 'text' | ||
| 'markdown' | ||
| 'html' | ||
| 'boolean' | ||
| 'date' | ||
| 'datetime' | ||
| 'color' | ||
| 'file' | ||
| 'json' | ||
| 'richText'; | ||
export interface FieldStringProps { | ||
type: 'string'; | ||
} | ||
export interface FieldUrlProps { | ||
type: 'url'; | ||
} | ||
export interface FieldSlugProps { | ||
type: 'slug'; | ||
} | ||
export interface FieldTextProps { | ||
type: 'text'; | ||
} | ||
export interface FieldMarkdownProps { | ||
type: 'markdown'; | ||
} | ||
export interface FieldHtmlProps { | ||
type: 'html'; | ||
} | ||
export interface FieldBooleanProps { | ||
type: 'boolean'; | ||
} | ||
export interface FieldDateProps { | ||
type: 'date'; | ||
} | ||
export interface FieldDatetimeProps { | ||
type: 'datetime'; | ||
} | ||
export interface FieldColorProps { | ||
type: 'color'; | ||
} | ||
export interface FieldJsonProps { | ||
type: 'json'; | ||
} | ||
export interface FieldRichTextProps { | ||
type: 'richText'; | ||
} | ||
export interface FieldFileProps { | ||
type: 'file'; | ||
} | ||
export type FieldEnumProps = | ||
@@ -184,2 +271,3 @@ | FieldEnumDropdownProps | ||
labelField?: string; | ||
preview?: DocumentFieldPreview; | ||
thumbnail?: string; | ||
@@ -275,1 +363,33 @@ variantField?: string; | ||
} | ||
export type DocumentPreview = DocumentPreviewFunction | PreviewFields; | ||
export type DocumentFieldPreview = ObjectPreviewFunction | PreviewFields; | ||
export type DocumentPreviewFunction = ( | ||
options: { | ||
document: DocumentWithSource; | ||
currentLocale?: string; | ||
} & ConfigDelegate | ||
) => { | ||
title?: string; | ||
subtitle?: string; | ||
image?: string; | ||
}; | ||
export type ObjectPreviewFunction = ( | ||
options: { | ||
parentDocument: DocumentWithSource; | ||
documentField: DocumentModelField | DocumentObjectField; | ||
currentLocale?: string; | ||
} & ConfigDelegate | ||
) => { | ||
title?: string; | ||
subtitle?: string; | ||
image?: string; | ||
}; | ||
export interface PreviewFields { | ||
title?: string; | ||
subtitle?: string; | ||
image?: string; | ||
} |
@@ -5,3 +5,4 @@ /** | ||
import type { Field, FieldExtension, FieldGroupItem } from './model-fields'; | ||
import type { Field, FieldExtension, FieldGroupItem, DocumentPreview, DocumentFieldPreview } from './model-fields'; | ||
import { Document } from './content-source-document'; | ||
@@ -34,3 +35,2 @@ export type Model = ObjectModel | DataModel | PageModel | ConfigModel; | ||
readOnly?: boolean; | ||
localized?: boolean; | ||
labelField?: string; | ||
@@ -54,6 +54,7 @@ /** @deprecated */ | ||
type: 'object'; | ||
preview?: DocumentFieldPreview; | ||
} | ||
/** @deprecated */ | ||
export interface ConfigModel extends ModelCommonFields { | ||
export interface ConfigModel extends ModelCommonFields, ModelLocalized { | ||
type: 'config'; | ||
@@ -63,3 +64,3 @@ file?: string; | ||
export interface PageModel extends ModelCommonFields, ModelMatchFields { | ||
export interface PageModel extends ModelCommonFields, ModelMatchFields, ModelLocalized { | ||
type: 'page'; | ||
@@ -70,7 +71,28 @@ layout?: string; | ||
hideContent?: boolean; | ||
preview?: DocumentPreview; | ||
} | ||
export interface DataModel extends ModelCommonFields, ModelMatchFields { | ||
export interface DataModel extends ModelCommonFields, ModelMatchFields, ModelLocalized { | ||
type: 'data'; | ||
filePath?: string; | ||
preview?: DocumentPreview; | ||
} | ||
export interface ModelLocalized { | ||
/** | ||
* Boolean flag indicating if documents belonging to this model are localized. | ||
* If localized is set to true, provide the `locale` function to set the | ||
* document `locale` | ||
*/ | ||
localized?: boolean; | ||
/** | ||
* The `locale` function should return the locale for the passed `document`. | ||
*/ | ||
locale?: (options: { | ||
document: Document; | ||
/** | ||
* The model of the passed `document`. | ||
*/ | ||
model: DataModel | PageModel; | ||
}) => string; | ||
} |
@@ -0,1 +1,2 @@ | ||
import type { Version } from './content-source'; | ||
import type { FieldType, Field, FieldForType } from './model-fields'; | ||
@@ -10,2 +11,3 @@ import type { StackbitConfig } from './config'; | ||
} from './content-source-document-fields'; | ||
import { InterfaceVersion } from './consts'; | ||
@@ -16,2 +18,26 @@ export type Simplify<T> = { | ||
export function getInterfaceVersion() { | ||
return InterfaceVersion; | ||
} | ||
export async function getVersion(options: { packageJsonPath?: string; contentSourceVersion?: string; } = {}): Promise<Version> { | ||
if (options.contentSourceVersion) { | ||
return { | ||
interfaceVersion: InterfaceVersion, | ||
contentSourceVersion: options.contentSourceVersion | ||
}; | ||
} else if (options.packageJsonPath) { | ||
const packageJson = await import(options.packageJsonPath); | ||
return { | ||
interfaceVersion: InterfaceVersion, | ||
contentSourceVersion: packageJson.version | ||
}; | ||
} else { | ||
return { | ||
interfaceVersion: InterfaceVersion, | ||
contentSourceVersion: '' | ||
}; | ||
} | ||
} | ||
export function isLocalizedField( | ||
@@ -25,5 +51,5 @@ field: DocumentField | AssetFileField | ||
* Returns non-localized version of a DocumentField for the provided `locale`. | ||
* If the `field` is localized, and the provided locale is not present, returns | ||
* null. If the `field` is not localized returns the `field` as-is ignoring the | ||
* `locale`. | ||
* If the `field` is localized, and the provided locale is not present, this | ||
* function returns `undefined`. If the `field` is not localized, this function | ||
* returns the `field` as-is ignoring the `locale`. | ||
* | ||
@@ -61,13 +87,13 @@ * @example Passing localized field | ||
export function getLocalizedFieldForLocale<Type extends FieldType>( | ||
field: DocumentFieldForType<Type>, | ||
field?: DocumentFieldForType<Type>, | ||
locale?: string | ||
): DocumentFieldNonLocalizedForType<Type> | null { | ||
if (field.localized) { | ||
): DocumentFieldNonLocalizedForType<Type> | undefined { | ||
if (field && field.localized) { | ||
if (!locale) { | ||
return null; | ||
return undefined; | ||
} | ||
const { localized, locales, ...base } = field; | ||
const localizedField = locales[locale]; | ||
const localizedField = locales?.[locale]; | ||
if (!localizedField) { | ||
return null; | ||
return undefined; | ||
} | ||
@@ -78,5 +104,4 @@ return { | ||
} as unknown as DocumentFieldNonLocalizedForType<Type>; | ||
} else { | ||
return field; | ||
} | ||
return field; | ||
} | ||
@@ -83,0 +108,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
200321
67
4120
1