Skip to content

Modular Station - API

This utility allows you, as an integration author, to expose APIs for other integrations that might be in use alogside yours. Instead of requiring them to call addIntegration instantiating yours, which has multiple limitations, they can use the API from your integration regardless of how it was installed.

Terminal window
npx astro add @inox-tools/modular-station

Assuming you already have an integration, you can just wrap it in the withApi function to give it superpowers:

my-integration.ts
import { withApi } from '@inox-tools/modular-station';
export default (options: Options) => {
export default withApi((options: Options) => {
const sharedState = ...;
return {
hooks: {
// ... using the shared state
},
};
};
});

With this, you can now expose APIs alongside your hooks:

my-integration.ts
import { withApi } from '@inox-tools/modular-station';
export default withApi((options: Options) => {
const sharedState = ...;
return {
hooks: {
// ... using the shared state
},
addSomething(thing: string) {
// add the thing to shared state
},
};
});

By default, accessing your API from any hook besides astro:config:setup will throw an error. This is because that is the only hook where nearly everything can be done in Astro’s lifecycle.

If you have an API that also works when called from other hooks, you can wrap them with onHook to declare which hooks are supported. For example, if you expose a method to register information that is only used on astro:build:start you can allow it to be used on any hook before that:

my-integration.ts
import { withApi, onHook } from '@inox-tools/modular-station';
export default withApi((options: Options) => {
const sharedState = ...;
return {
hooks: {
// ... using the shared state
},
addSomething: onHook([
'astro:config:setup',
'astro:config:done',
'astro:build:setup',
], (thing: string) {
// add the thing to shared state
}),
};
});

On your astro:config:setup or astro:config:done hooks you can get the API from the provided AstroConfig like so:

my-integration.ts
import otherIntegration from 'other-integration';
export default () => {
return {
name: 'my-integration',
hooks: {
'astro:config:setup': ({ config }) => {
const api = otherIntegration.fromConfig(config);
api?.addSomething();
},
},
};
};

The API might be null if the integration is not present. If needed, you can instantiate and add the integration yourself or use the optional API.