mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 15:13:21 +00:00
Merge pull request #19943 from strapi/v5/core
chore: internal core refactorings
This commit is contained in:
commit
c9159be3ec
@ -531,14 +531,6 @@ TODO
|
||||
TODO
|
||||
:::
|
||||
|
||||
### `strapi.startWebhooks()`
|
||||
|
||||
- Returns: Promise
|
||||
|
||||
:::info
|
||||
TODO
|
||||
:::
|
||||
|
||||
### `strapi.reload()`
|
||||
|
||||
:::info
|
||||
|
||||
@ -82,7 +82,7 @@ module.exports = async () => {
|
||||
subCategory: 'options',
|
||||
},
|
||||
];
|
||||
await strapi.admin.services.permission.actionProvider.registerMany(actions);
|
||||
await strapi.service('admin::permission').actionProvider.registerMany(actions);
|
||||
};
|
||||
```
|
||||
|
||||
@ -136,7 +136,7 @@ module.exports = async () => {
|
||||
handler: (user) => ({ 'createdBy.id': user.id }),
|
||||
},
|
||||
];
|
||||
await strapi.admin.services.permission.conditionProvider.registerMany(conditions);
|
||||
await strapi.service('admin::permission').conditionProvider.registerMany(conditions);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@ -104,7 +104,7 @@ describe('Stages', () => {
|
||||
});
|
||||
|
||||
test('cannot transition', async () => {
|
||||
global.strapi.admin.services['stage-permissions'].can.mockReturnValueOnce(false);
|
||||
global.strapi.service('admin::stage-permissions').can.mockReturnValueOnce(false);
|
||||
|
||||
const ctx: any = {
|
||||
...baseCtx,
|
||||
@ -145,7 +145,7 @@ describe('Stages', () => {
|
||||
});
|
||||
|
||||
test('cannot transition', async () => {
|
||||
global.strapi.admin.services['stage-permissions'].can.mockReturnValueOnce(false);
|
||||
global.strapi.service('admin::stage-permissions').can.mockReturnValueOnce(false);
|
||||
|
||||
const ctx: any = {
|
||||
...baseCtx,
|
||||
|
||||
@ -18,7 +18,7 @@ const providerAuthenticationFlow = compose([
|
||||
|
||||
export default {
|
||||
async getProviders(ctx: Context) {
|
||||
const { providerRegistry } = strapi.admin.services.passport;
|
||||
const { providerRegistry } = strapi.service('admin::passport');
|
||||
|
||||
ctx.body = providerRegistry.getAll().map(toProviderDTO);
|
||||
},
|
||||
@ -56,7 +56,7 @@ export default {
|
||||
params: { provider: providerName },
|
||||
} = ctx;
|
||||
|
||||
const { providerRegistry } = strapi.admin.services.passport;
|
||||
const { providerRegistry } = strapi.service('admin::passport');
|
||||
|
||||
if (!providerRegistry.has(providerName)) {
|
||||
throw new ValidationError(`Invalid provider supplied: ${providerName}`);
|
||||
|
||||
@ -12,7 +12,7 @@ import createAuditLogsService from './services/audit-logs';
|
||||
import reviewWorkflowsMiddlewares from './middlewares/review-workflows';
|
||||
import { getService } from './utils';
|
||||
|
||||
export default async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default async ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const auditLogsIsEnabled = strapi.config.get('admin.auditLogs.enabled', true);
|
||||
|
||||
if (auditLogsIsEnabled) {
|
||||
|
||||
@ -130,7 +130,7 @@ describe('Audit logs service', () => {
|
||||
const mockFindMany = jest.fn();
|
||||
const mockDeleteExpiredEvents = jest.fn();
|
||||
|
||||
let strapi = {} as Core.LoadedStrapi;
|
||||
let strapi = {} as Core.Strapi;
|
||||
|
||||
beforeAll(() => {
|
||||
// @ts-expect-error - register is a mock
|
||||
@ -178,7 +178,7 @@ describe('Audit logs service', () => {
|
||||
return cb(opt);
|
||||
},
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@ -29,7 +29,7 @@ const strapiMock = {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
|
||||
let validationService: any;
|
||||
|
||||
|
||||
@ -60,6 +60,10 @@ const containerMock = {
|
||||
switch (container) {
|
||||
case 'content-types':
|
||||
return contentTypesContainer;
|
||||
case 'webhookStore':
|
||||
return {
|
||||
addAllowedEvent: jest.fn(),
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -91,10 +95,7 @@ const strapiMock = {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
webhookStore: {
|
||||
addAllowedEvent: jest.fn(),
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
|
||||
const reviewWorkflowsService = reviewWorkflowsServiceFactory({ strapi: strapiMock });
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ const strapiMock = {
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
|
||||
const stagesService = stageFactory({ strapi: strapiMock });
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ const strapiMock = {
|
||||
};
|
||||
}
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
|
||||
const ctMap: Record<string, any> = {
|
||||
[WORKFLOW_MODEL_UID]: workflowCT.schema,
|
||||
|
||||
@ -61,7 +61,7 @@ const getEventMap = (defaultEvents: any) => {
|
||||
}, {} as any);
|
||||
};
|
||||
|
||||
const getRetentionDays = (strapi: Core.LoadedStrapi) => {
|
||||
const getRetentionDays = (strapi: Core.Strapi) => {
|
||||
const licenseRetentionDays = strapi.ee.features.get('audit-logs')?.options.retentionDays;
|
||||
const userRetentionDays = strapi.config.get('admin.auditLogs.retentionDays');
|
||||
|
||||
@ -79,7 +79,7 @@ const getRetentionDays = (strapi: Core.LoadedStrapi) => {
|
||||
return licenseRetentionDays;
|
||||
};
|
||||
|
||||
const createAuditLogsService = (strapi: Core.LoadedStrapi) => {
|
||||
const createAuditLogsService = (strapi: Core.Strapi) => {
|
||||
// Manage internal service state privately
|
||||
const state = {} as any;
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { Core } from '@strapi/types';
|
||||
import { getService } from '../utils';
|
||||
|
||||
const getSSOProvidersList = async () => {
|
||||
const { providerRegistry } = strapi.admin.services.passport;
|
||||
const { providerRegistry } = strapi.service('admin::passport');
|
||||
|
||||
return providerRegistry.getAll().map(({ uid }: { uid: string }) => uid);
|
||||
};
|
||||
|
||||
@ -8,7 +8,7 @@ const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
|
||||
const getWeeklyCronScheduleAt = (date: Date) =>
|
||||
`${date.getSeconds()} ${date.getMinutes()} ${date.getHours()} * * ${date.getDay()}`;
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const metrics = getService('review-workflows-metrics', { strapi });
|
||||
const workflowsService = getService('workflows', { strapi });
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ const setReviewWorkflowAttributes = (contentType: any) => {
|
||||
setAssigneeAttribute(contentType);
|
||||
};
|
||||
|
||||
function extendReviewWorkflowContentTypes({ strapi }: { strapi: Core.LoadedStrapi }) {
|
||||
function extendReviewWorkflowContentTypes({ strapi }: { strapi: Core.Strapi }) {
|
||||
const extendContentType = (contentTypeUID: any) => {
|
||||
strapi.get('content-types').extend(contentTypeUID, setReviewWorkflowAttributes);
|
||||
};
|
||||
@ -74,7 +74,7 @@ function extendReviewWorkflowContentTypes({ strapi }: { strapi: Core.LoadedStrap
|
||||
])(strapi.contentTypes);
|
||||
}
|
||||
|
||||
function persistStagesJoinTables({ strapi }: { strapi: Core.LoadedStrapi }) {
|
||||
function persistStagesJoinTables({ strapi }: { strapi: Core.Strapi }) {
|
||||
return async ({ contentTypes }: any) => {
|
||||
const getStageTableToPersist = (contentTypeUID: any) => {
|
||||
// Persist the stage join table
|
||||
@ -98,12 +98,12 @@ function persistStagesJoinTables({ strapi }: { strapi: Core.LoadedStrapi }) {
|
||||
};
|
||||
}
|
||||
|
||||
const registerWebhookEvents = async ({ strapi }: { strapi: Core.LoadedStrapi }) =>
|
||||
const registerWebhookEvents = async ({ strapi }: { strapi: Core.Strapi }) =>
|
||||
Object.entries(webhookEvents).forEach(([eventKey, event]) =>
|
||||
strapi.webhookStore.addAllowedEvent(eventKey, event)
|
||||
strapi.get('webhookStore').addAllowedEvent(eventKey, event)
|
||||
);
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const workflowsService = getService('workflows', { strapi });
|
||||
const stagesService = getService('stages', { strapi });
|
||||
const workflowsValidationService = getService('review-workflows-validation', { strapi });
|
||||
|
||||
@ -7,7 +7,7 @@ import { STAGE_TRANSITION_UID } from '../../constants/workflows';
|
||||
const { ApplicationError } = errors;
|
||||
const validActions = [STAGE_TRANSITION_UID];
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const roleService = getService('role');
|
||||
const permissionService = getService('permission');
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ const { ApplicationError, ValidationError } = errors;
|
||||
const sanitizedStageFields = ['id', 'name', 'workflow', 'color'];
|
||||
const sanitizeStageFields = pick(sanitizedStageFields);
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const metrics = getService('review-workflows-metrics', { strapi });
|
||||
const stagePermissionsService = getService('stage-permissions', { strapi });
|
||||
const workflowsValidationService = getService('review-workflows-validation', { strapi });
|
||||
|
||||
@ -7,7 +7,7 @@ import { clampMaxWorkflows, clampMaxStagesPerWorkflow } from '../../utils/review
|
||||
|
||||
const { ValidationError } = errors;
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
return {
|
||||
limits: {
|
||||
numberOfWorkflows: MAX_WORKFLOWS,
|
||||
|
||||
@ -4,7 +4,7 @@ import { difference, merge } from 'lodash/fp';
|
||||
import { getService } from '../../../utils';
|
||||
import { WORKFLOW_MODEL_UID } from '../../../constants/workflows';
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const contentManagerContentTypeService = strapi
|
||||
.plugin('content-manager')
|
||||
.service('content-types');
|
||||
|
||||
@ -7,7 +7,7 @@ import { getWorkflowContentTypeFilter } from '../../../utils/review-workflows';
|
||||
import workflowsContentTypesFactory from './content-types';
|
||||
|
||||
const { ApplicationError } = errors;
|
||||
const processFilters = ({ strapi }: { strapi: Core.LoadedStrapi }, filters: any = {}) => {
|
||||
const processFilters = ({ strapi }: { strapi: Core.Strapi }, filters: any = {}) => {
|
||||
const processedFilters = { ...filters };
|
||||
|
||||
if (isString(filters.contentTypes)) {
|
||||
@ -27,7 +27,7 @@ const processPopulate = (populate: any) => {
|
||||
return WORKFLOW_POPULATE;
|
||||
};
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const workflowsContentTypes = workflowsContentTypesFactory({ strapi });
|
||||
const workflowsValidationService = getService('review-workflows-validation', { strapi });
|
||||
const metrics = getService('review-workflows-metrics', { strapi });
|
||||
|
||||
@ -23,7 +23,7 @@ const transformTableName = (table: string | PersistedTable) => {
|
||||
* @param {RegExp} regex
|
||||
* @returns {Promise<string[]>}
|
||||
*/
|
||||
export async function findTables({ strapi }: { strapi: Core.LoadedStrapi }, regex: any) {
|
||||
export async function findTables({ strapi }: { strapi: Core.Strapi }, regex: any) {
|
||||
// @ts-expect-error - getTables is not typed into the schema inspector
|
||||
const tables = await strapi.db.dialect.schemaInspector.getTables();
|
||||
return tables.filter((tableName: string) => regex.test(tableName));
|
||||
@ -33,7 +33,7 @@ export async function findTables({ strapi }: { strapi: Core.LoadedStrapi }, rege
|
||||
* Add tables name to the reserved tables in core store
|
||||
*/
|
||||
async function addPersistTables(
|
||||
{ strapi }: { strapi: Core.LoadedStrapi },
|
||||
{ strapi }: { strapi: Core.Strapi },
|
||||
tableNames: Array<string | PersistedTable>
|
||||
) {
|
||||
const persistedTables = await getPersistedTables({ strapi });
|
||||
@ -69,7 +69,7 @@ async function addPersistTables(
|
||||
* @returns {Promise<string[]>}
|
||||
*/
|
||||
|
||||
async function getPersistedTables({ strapi }: { strapi: Core.LoadedStrapi }) {
|
||||
async function getPersistedTables({ strapi }: { strapi: Core.Strapi }) {
|
||||
const persistedTables: any = await strapi.store.get({
|
||||
type: 'core',
|
||||
key: 'persisted_tables',
|
||||
@ -86,7 +86,7 @@ async function getPersistedTables({ strapi }: { strapi: Core.LoadedStrapi }) {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setPersistedTables(
|
||||
{ strapi }: { strapi: Core.LoadedStrapi },
|
||||
{ strapi }: { strapi: Core.Strapi },
|
||||
tableNames: Array<string | PersistedTable>
|
||||
) {
|
||||
await strapi.store.set({
|
||||
|
||||
@ -20,7 +20,7 @@ export const getVisibleContentTypesUID = pipe([
|
||||
export const hasStageAttribute = has(['attributes', ENTITY_STAGE_ATTRIBUTE]);
|
||||
|
||||
export const getWorkflowContentTypeFilter = (
|
||||
{ strapi }: { strapi: Core.LoadedStrapi },
|
||||
{ strapi }: { strapi: Core.Strapi },
|
||||
contentType: any
|
||||
) => {
|
||||
if (strapi.db.dialect.supportsOperator('$jsonSupersetOf')) {
|
||||
|
||||
@ -11,7 +11,7 @@ const providerOptionsUpdateSchema = yup.object().shape({
|
||||
if (roleId === null) {
|
||||
return true;
|
||||
}
|
||||
return strapi.admin.services.role.exists({ id: roleId });
|
||||
return strapi.service('admin::role').exists({ id: roleId });
|
||||
}),
|
||||
ssoLockedRoles: yup
|
||||
.array()
|
||||
@ -23,7 +23,7 @@ const providerOptionsUpdateSchema = yup.object().shape({
|
||||
'is-valid-role',
|
||||
'You must submit a valid role for the SSO Locked roles',
|
||||
(roleId) => {
|
||||
return strapi.admin.services.role.exists({ id: roleId });
|
||||
return strapi.service('admin::role').exists({ id: roleId });
|
||||
}
|
||||
)
|
||||
),
|
||||
|
||||
@ -21,10 +21,10 @@ const rolesDeleteSchema = yup
|
||||
'Roles deletion checks have failed',
|
||||
async function rolesDeletionChecks(ids) {
|
||||
try {
|
||||
await strapi.admin.services.role.checkRolesIdForDeletion(ids);
|
||||
await strapi.service('admin::role').checkRolesIdForDeletion(ids);
|
||||
|
||||
if (strapi.ee.features.isEnabled('sso')) {
|
||||
await strapi.admin.services.role.ssoCheckRolesIdForDeletion(ids);
|
||||
await strapi.service('admin::role').ssoCheckRolesIdForDeletion(ids);
|
||||
}
|
||||
} catch (e: any) {
|
||||
return this.createError({ path: 'ids', message: e.message });
|
||||
@ -44,10 +44,10 @@ const roleDeleteSchema = yup
|
||||
'Role deletion checks have failed',
|
||||
async function noAdminSingleDelete(id) {
|
||||
try {
|
||||
await strapi.admin.services.role.checkRolesIdForDeletion([id]);
|
||||
await strapi.service('admin::role').checkRolesIdForDeletion([id]);
|
||||
|
||||
if (strapi.ee.features.isEnabled('sso')) {
|
||||
await strapi.admin.services.role.ssoCheckRolesIdForDeletion([id]);
|
||||
await strapi.service('admin::role').ssoCheckRolesIdForDeletion([id]);
|
||||
}
|
||||
} catch (e: any) {
|
||||
return this.createError({ path: 'id', message: e.message });
|
||||
|
||||
@ -38,7 +38,7 @@ describe('Admin Controller', () => {
|
||||
'packageJsonStrapi.telemetryDisabled',
|
||||
null
|
||||
);
|
||||
expect(global.strapi.admin.services.user.exists).toHaveBeenCalled();
|
||||
expect(global.strapi.service('admin::user').exists).toHaveBeenCalled();
|
||||
expect(result.data).toBeDefined();
|
||||
expect(result.data).toStrictEqual({
|
||||
uuid: 'foo',
|
||||
|
||||
@ -195,7 +195,7 @@ describe('Permission Controller', () => {
|
||||
await permissionController.check(ctx);
|
||||
|
||||
expect(localTestData.ability.can).toHaveBeenCalled();
|
||||
expect(strapi.admin.services.permission.engine.checkMany).toHaveBeenCalled();
|
||||
expect(strapi.service('admin::permission').engine.checkMany).toHaveBeenCalled();
|
||||
expect(ctx.body.data).toHaveLength(localTestData.permissions.valid.length);
|
||||
});
|
||||
});
|
||||
|
||||
@ -58,7 +58,7 @@ export default {
|
||||
async find(ctx: Context) {
|
||||
const userService = getService('user');
|
||||
|
||||
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
||||
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: 'admin::user',
|
||||
});
|
||||
|
||||
@ -46,13 +46,13 @@ const updateWebhookValidator = webhookValidator.shape({
|
||||
|
||||
export default {
|
||||
async listWebhooks(ctx: Context) {
|
||||
const webhooks = await strapi.webhookStore.findWebhooks();
|
||||
const webhooks = await strapi.get('webhookStore').findWebhooks();
|
||||
ctx.send({ data: webhooks } satisfies GetWebhooks.Response);
|
||||
},
|
||||
|
||||
async getWebhook(ctx: Context) {
|
||||
const { id } = ctx.params;
|
||||
const webhook = await strapi.webhookStore.findWebhook(id);
|
||||
const webhook = await strapi.get('webhookStore').findWebhook(id);
|
||||
|
||||
if (!webhook) {
|
||||
return ctx.notFound('webhook.notFound');
|
||||
@ -66,9 +66,9 @@ export default {
|
||||
|
||||
await validateYupSchema(webhookValidator)(body);
|
||||
|
||||
const webhook = await strapi.webhookStore.createWebhook(body);
|
||||
const webhook = await strapi.get('webhookStore').createWebhook(body);
|
||||
|
||||
strapi.webhookRunner.add(webhook);
|
||||
strapi.get('webhookRunner').add(webhook);
|
||||
|
||||
ctx.created({ data: webhook } satisfies CreateWebhook.Response);
|
||||
},
|
||||
@ -79,13 +79,13 @@ export default {
|
||||
|
||||
await validateYupSchema(updateWebhookValidator)(body);
|
||||
|
||||
const webhook = await strapi.webhookStore.findWebhook(id);
|
||||
const webhook = await strapi.get('webhookStore').findWebhook(id);
|
||||
|
||||
if (!webhook) {
|
||||
return ctx.notFound('webhook.notFound');
|
||||
}
|
||||
|
||||
const updatedWebhook = await strapi.webhookStore.updateWebhook(id, {
|
||||
const updatedWebhook = await strapi.get('webhookStore').updateWebhook(id, {
|
||||
...webhook,
|
||||
...body,
|
||||
});
|
||||
@ -94,22 +94,22 @@ export default {
|
||||
return ctx.notFound('webhook.notFound');
|
||||
}
|
||||
|
||||
strapi.webhookRunner.update(updatedWebhook);
|
||||
strapi.get('webhookRunner').update(updatedWebhook);
|
||||
|
||||
ctx.send({ data: updatedWebhook } satisfies UpdateWebhook.Response);
|
||||
},
|
||||
|
||||
async deleteWebhook(ctx: Context) {
|
||||
const { id } = ctx.params;
|
||||
const webhook = await strapi.webhookStore.findWebhook(id);
|
||||
const webhook = await strapi.get('webhookStore').findWebhook(id);
|
||||
|
||||
if (!webhook) {
|
||||
return ctx.notFound('webhook.notFound');
|
||||
}
|
||||
|
||||
await strapi.webhookStore.deleteWebhook(id);
|
||||
await strapi.get('webhookStore').deleteWebhook(id);
|
||||
|
||||
strapi.webhookRunner.remove(webhook);
|
||||
strapi.get('webhookRunner').remove(webhook);
|
||||
|
||||
ctx.body = { data: webhook } satisfies DeleteWebhook.Response;
|
||||
},
|
||||
@ -122,11 +122,11 @@ export default {
|
||||
}
|
||||
|
||||
for (const id of ids) {
|
||||
const webhook = await strapi.webhookStore.findWebhook(id);
|
||||
const webhook = await strapi.get('webhookStore').findWebhook(id);
|
||||
|
||||
if (webhook) {
|
||||
await strapi.webhookStore.deleteWebhook(id);
|
||||
strapi.webhookRunner.remove(webhook);
|
||||
await strapi.get('webhookStore').deleteWebhook(id);
|
||||
strapi.get('webhookRunner').remove(webhook);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,13 +136,11 @@ export default {
|
||||
async triggerWebhook(ctx: Context) {
|
||||
const { id } = ctx.params;
|
||||
|
||||
const webhook = await strapi.webhookStore.findWebhook(id);
|
||||
const webhook = await strapi.get('webhookStore').findWebhook(id);
|
||||
|
||||
const response = await strapi.webhookRunner.run(
|
||||
webhook as Modules.WebhookStore.Webhook,
|
||||
'trigger-test',
|
||||
{}
|
||||
);
|
||||
const response = await strapi
|
||||
.get('webhookRunner')
|
||||
.run(webhook as Modules.WebhookStore.Webhook, 'trigger-test', {});
|
||||
|
||||
ctx.body = { data: response } satisfies TriggerWebhook.Response;
|
||||
},
|
||||
|
||||
@ -4,7 +4,7 @@ import adminAuthStrategy from './strategies/admin';
|
||||
import apiTokenAuthStrategy from './strategies/api-token';
|
||||
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const passportMiddleware = strapi.admin?.services.passport.init();
|
||||
const passportMiddleware = strapi.service('admin::passport').init();
|
||||
|
||||
strapi.server.api('admin').use(passportMiddleware);
|
||||
strapi.get('auth').register('admin', adminAuthStrategy);
|
||||
|
||||
@ -11,7 +11,7 @@ const authEventsMapper = {
|
||||
|
||||
const valueIsFunctionType = ([, value]: [any, any]) => isFunction(value);
|
||||
const keyIsValidEventName = ([key]: any) => {
|
||||
return Object.keys(strapi.admin.services.passport.authEventsMapper).includes(key);
|
||||
return Object.keys(strapi.service('admin::passport').authEventsMapper).includes(key);
|
||||
};
|
||||
|
||||
const getPassportStrategies = () => [createLocalStrategy(strapi)] as Strategy[];
|
||||
@ -19,7 +19,7 @@ const getPassportStrategies = () => [createLocalStrategy(strapi)] as Strategy[];
|
||||
const registerAuthEvents = () => {
|
||||
// @ts-expect-error - TODO: migrate auth service to TS
|
||||
const { events = {} } = strapi.config.get('admin.auth', {});
|
||||
const { authEventsMapper } = strapi.admin.services.passport;
|
||||
const { authEventsMapper } = strapi.service('admin::passport');
|
||||
|
||||
const eventList = Object.entries(events).filter(keyIsValidEventName).filter(valueIsFunctionType);
|
||||
|
||||
@ -30,7 +30,8 @@ const registerAuthEvents = () => {
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
strapi.admin.services.passport
|
||||
strapi
|
||||
.service('admin::passport')
|
||||
.getPassportStrategies()
|
||||
.forEach((strategy: Strategy) => passport.use(strategy));
|
||||
|
||||
|
||||
@ -341,7 +341,7 @@ const flattenTokenPermissions = (token: DatabaseTransferToken): TransferToken =>
|
||||
* Assert that a token's permissions are valid
|
||||
*/
|
||||
const assertTokenPermissionsValidity = (attributes: TokenUpdatePayload) => {
|
||||
const permissionService = strapi.admin.services.transfer.permission;
|
||||
const permissionService = strapi.service('admin::transfer').permission;
|
||||
const validPermissions = permissionService.providers.action.keys();
|
||||
const invalidPermissions = difference(attributes.permissions, validPermissions);
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ export const arrayOfConditionNames = yup
|
||||
.array()
|
||||
.of(yup.string())
|
||||
.test('is-an-array-of-conditions', 'is not a plugin name', function (value) {
|
||||
const ids = strapi.admin.services.permission.conditionProvider.keys();
|
||||
const ids = strapi.service('admin::permission').conditionProvider.keys();
|
||||
return _.isUndefined(value) || _.difference(value, ids).length === 0
|
||||
? true
|
||||
: this.createError({ path: this.path, message: `contains conditions that don't exist` });
|
||||
|
||||
@ -18,7 +18,7 @@ const rolesDeleteSchema = yup
|
||||
.required()
|
||||
.test('roles-deletion-checks', 'Roles deletion checks have failed', async function (ids) {
|
||||
try {
|
||||
await strapi.admin.services.role.checkRolesIdForDeletion(ids);
|
||||
await strapi.service('admin::role').checkRolesIdForDeletion(ids);
|
||||
} catch (e) {
|
||||
// @ts-expect-error yup types
|
||||
return this.createError({ path: 'ids', message: e.message });
|
||||
@ -34,7 +34,7 @@ const roleDeleteSchema = yup
|
||||
.required()
|
||||
.test('no-admin-single-delete', 'Role deletion checks have failed', async function (id) {
|
||||
try {
|
||||
await strapi.admin.services.role.checkRolesIdForDeletion([id]);
|
||||
await strapi.service('admin::role').checkRolesIdForDeletion([id]);
|
||||
} catch (e) {
|
||||
// @ts-expect-error yup types
|
||||
return this.createError({ path: 'id', message: e.message });
|
||||
|
||||
@ -4,7 +4,7 @@ import history from './history';
|
||||
|
||||
export default async () => {
|
||||
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
||||
strapi.webhookStore.addAllowedEvent(key, value);
|
||||
strapi.get('webhookStore').addAllowedEvent(key, value);
|
||||
});
|
||||
|
||||
getService('field-sizes').setCustomFieldInputSizes();
|
||||
|
||||
@ -9,7 +9,7 @@ import { getSchemaAttributesDiff } from './utils';
|
||||
|
||||
const DEFAULT_RETENTION_DAYS = 90;
|
||||
|
||||
const createHistoryService = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const state: {
|
||||
deleteExpiredJob: ReturnType<typeof scheduleJob> | null;
|
||||
isInitialized: boolean;
|
||||
@ -20,9 +20,12 @@ const createHistoryService = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
|
||||
const query = strapi.db.query(HISTORY_VERSION_UID);
|
||||
|
||||
const getRetentionDays = (strapi: Core.LoadedStrapi) => {
|
||||
const getRetentionDays = (strapi: Core.Strapi) => {
|
||||
const featureConfig = strapi.ee.features.get('cms-content-history');
|
||||
|
||||
const licenseRetentionDays =
|
||||
strapi.ee.features.get('cms-content-history')?.options.retentionDays;
|
||||
typeof featureConfig === 'object' && featureConfig?.options.retentionDays;
|
||||
|
||||
const userRetentionDays: number = strapi.config.get('admin.history.retentionDays');
|
||||
|
||||
// Allow users to override the license retention days, but not to increase it
|
||||
|
||||
@ -15,11 +15,11 @@ export default async (ctx: Context, next: Next) => {
|
||||
return ctx.send({ error: 'contentType.notFound' }, 404);
|
||||
}
|
||||
|
||||
let target;
|
||||
let controllers;
|
||||
if (!ct.plugin || ct.plugin === 'admin') {
|
||||
target = strapi.admin;
|
||||
controllers = strapi.admin.controllers;
|
||||
} else {
|
||||
target = strapi.plugin(ct.plugin);
|
||||
controllers = strapi.plugin(ct.plugin).controllers;
|
||||
}
|
||||
|
||||
const { route }: { route: Core.Route } = ctx.state;
|
||||
@ -41,7 +41,7 @@ export default async (ctx: Context, next: Next) => {
|
||||
const [controller, action] = actionConfig.split('.');
|
||||
|
||||
if (controller && action) {
|
||||
return target.controllers[controller.toLowerCase()][action](ctx, next);
|
||||
return controllers[controller.toLowerCase()][action](ctx, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ const configurationService = createConfigurationService({
|
||||
},
|
||||
});
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
findAllComponents() {
|
||||
const { toContentManagerModel } = getService('data-mapper');
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ const configurationService = createConfigurationService({
|
||||
},
|
||||
});
|
||||
|
||||
const service = ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
const service = ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
findAllContentTypes() {
|
||||
const { toContentManagerModel } = getService('data-mapper');
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ const emitEvent = async (uid: UID.ContentType, event: string, document: Document
|
||||
});
|
||||
};
|
||||
|
||||
const documentManager = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
const documentManager = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
return {
|
||||
async findOne(id: string, uid: UID.CollectionType, opts: DocServiceParams<'findOne'>[1] = {}) {
|
||||
return strapi.documents(uid).findOne(id, opts);
|
||||
|
||||
@ -69,7 +69,7 @@ export interface GetMetadataOptions {
|
||||
availableStatus?: boolean;
|
||||
}
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
/**
|
||||
* Returns available locales of a document for the current status
|
||||
*/
|
||||
|
||||
@ -50,7 +50,7 @@ const fieldSizes: Record<string, FieldSize> = {
|
||||
uid: defaultSize,
|
||||
};
|
||||
|
||||
const createFieldSizesService = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
const createFieldSizesService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const fieldSizesService = {
|
||||
getAllFieldSizes() {
|
||||
return fieldSizes;
|
||||
|
||||
@ -5,7 +5,7 @@ import type { Configuration } from '../../../shared/contracts/content-types';
|
||||
|
||||
const { getRelationalFields } = relations;
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const sendDidConfigureListView = async (
|
||||
contentType: Struct.ContentTypeSchema,
|
||||
configuration: Configuration
|
||||
|
||||
@ -19,9 +19,9 @@ type Query = {
|
||||
};
|
||||
|
||||
const createPermissionChecker =
|
||||
(strapi: Core.LoadedStrapi) =>
|
||||
(strapi: Core.Strapi) =>
|
||||
({ userAbility, model }: { userAbility: any; model: string }) => {
|
||||
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
||||
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
||||
ability: userAbility,
|
||||
model,
|
||||
});
|
||||
@ -113,6 +113,6 @@ const createPermissionChecker =
|
||||
};
|
||||
};
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
create: createPermissionChecker(strapi),
|
||||
});
|
||||
|
||||
@ -4,7 +4,7 @@ import { contentTypes as contentTypesUtils } from '@strapi/utils';
|
||||
import type { Core, Struct } from '@strapi/types';
|
||||
import { getService } from '../utils';
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
canConfigureContentType({
|
||||
userAbility,
|
||||
contentType,
|
||||
@ -91,6 +91,6 @@ export default ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
},
|
||||
];
|
||||
|
||||
await strapi.admin.services.permission.actionProvider.registerMany(actions);
|
||||
await strapi.service('admin::permission').actionProvider.registerMany(actions);
|
||||
},
|
||||
});
|
||||
|
||||
@ -3,7 +3,7 @@ import slugify from '@sindresorhus/slugify';
|
||||
|
||||
import type { Core, Schema, UID } from '@strapi/types';
|
||||
|
||||
export default ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
async generateUIDField({
|
||||
contentTypeUID,
|
||||
field,
|
||||
|
||||
@ -15,6 +15,14 @@ const mockGraphQlShadowCrud = jest.fn(() => ({
|
||||
}));
|
||||
describe('register', () => {
|
||||
const strapi = {
|
||||
service(name: string) {
|
||||
switch (name) {
|
||||
case 'admin::permission':
|
||||
return this.admin.services.permission;
|
||||
default:
|
||||
throw new Error(`Service ${name} not found`);
|
||||
}
|
||||
},
|
||||
ee: {
|
||||
features: {
|
||||
isEnabled: jest.fn(),
|
||||
@ -61,7 +69,7 @@ describe('register', () => {
|
||||
strapi.ee.features.isEnabled.mockReturnValue(true);
|
||||
register({ strapi });
|
||||
|
||||
expect(strapi.admin.services.permission.actionProvider.registerMany).toHaveBeenCalledWith(
|
||||
expect(strapi.service('admin::permission').actionProvider.registerMany).toHaveBeenCalledWith(
|
||||
ACTIONS
|
||||
);
|
||||
});
|
||||
@ -70,7 +78,7 @@ describe('register', () => {
|
||||
strapi.ee.features.isEnabled.mockReturnValue(false);
|
||||
register({ strapi });
|
||||
|
||||
expect(strapi.admin.services.permission.actionProvider.registerMany).not.toHaveBeenCalled();
|
||||
expect(strapi.service('admin::permission').actionProvider.registerMany).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should exclude the release and release action models from the GraphQL schema when the feature is enabled', async () => {
|
||||
|
||||
@ -4,7 +4,7 @@ import type { Core, Data, UID } from '@strapi/types';
|
||||
import { RELEASE_ACTION_MODEL_UID, RELEASE_MODEL_UID, ALLOWED_WEBHOOK_EVENTS } from './constants';
|
||||
import { getEntryValidStatus, getService } from './utils';
|
||||
|
||||
export const bootstrap = async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export const bootstrap = async ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
if (strapi.ee.features.isEnabled('cms-content-releases')) {
|
||||
const contentTypesWithDraftAndPublish = Object.keys(strapi.contentTypes).filter(
|
||||
(uid: any) => strapi.contentTypes[uid]?.options?.draftAndPublish
|
||||
@ -154,7 +154,7 @@ export const bootstrap = async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
});
|
||||
|
||||
Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
||||
strapi.webhookStore.addAllowedEvent(key, value);
|
||||
strapi.get('webhookStore').addAllowedEvent(key, value);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -262,7 +262,7 @@ describe('Release controller', () => {
|
||||
|
||||
// @ts-expect-error partial context
|
||||
await releaseController.findOne(ctx);
|
||||
expect(strapi.admin.services.user.sanitizeUser).toHaveBeenCalled();
|
||||
expect(strapi.service('admin::user').sanitizeUser).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -75,7 +75,7 @@ const releaseActionController = {
|
||||
|
||||
async findMany(ctx: Koa.Context) {
|
||||
const releaseId: GetReleaseActions.Request['params']['releaseId'] = ctx.params.releaseId;
|
||||
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
||||
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: RELEASE_ACTION_MODEL_UID,
|
||||
});
|
||||
@ -97,8 +97,9 @@ const releaseActionController = {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const contentTypePermissionsManager =
|
||||
strapi.admin.services.permission.createPermissionsManager({
|
||||
const contentTypePermissionsManager = strapi
|
||||
.service('admin::permission')
|
||||
.createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: action.contentType,
|
||||
});
|
||||
|
||||
@ -19,7 +19,7 @@ type ReleaseWithPopulatedActions = Release & { actions: { count: number } };
|
||||
|
||||
const releaseController = {
|
||||
async findMany(ctx: Koa.Context) {
|
||||
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
||||
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: RELEASE_MODEL_UID,
|
||||
});
|
||||
@ -89,7 +89,7 @@ const releaseController = {
|
||||
const sanitizedRelease = {
|
||||
...release,
|
||||
createdBy: release.createdBy
|
||||
? strapi.admin.services.user.sanitizeUser(release.createdBy)
|
||||
? strapi.service('admin::user').sanitizeUser(release.createdBy)
|
||||
: null,
|
||||
};
|
||||
|
||||
@ -115,7 +115,7 @@ const releaseController = {
|
||||
const releaseService = getService('release', { strapi });
|
||||
const release = await releaseService.create(releaseArgs, { user });
|
||||
|
||||
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
||||
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: RELEASE_MODEL_UID,
|
||||
});
|
||||
@ -135,7 +135,7 @@ const releaseController = {
|
||||
const releaseService = getService('release', { strapi });
|
||||
const release = await releaseService.update(id, releaseArgs, { user });
|
||||
|
||||
const permissionsManager = strapi.admin.services.permission.createPermissionsManager({
|
||||
const permissionsManager = strapi.service('admin::permission').createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: RELEASE_MODEL_UID,
|
||||
});
|
||||
|
||||
@ -4,7 +4,7 @@ import { Core } from '@strapi/types';
|
||||
import { Release } from '../../shared/contracts/releases';
|
||||
import { getService } from './utils';
|
||||
|
||||
export const destroy = async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export const destroy = async ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const scheduledJobs: Map<Release['id'], Job> = getService('scheduling', {
|
||||
strapi,
|
||||
}).getAll();
|
||||
|
||||
@ -11,9 +11,9 @@ import {
|
||||
enableContentTypeLocalized,
|
||||
} from './migrations';
|
||||
|
||||
export const register = async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export const register = async ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
if (strapi.ee.features.isEnabled('cms-content-releases')) {
|
||||
await strapi.admin.services.permission.actionProvider.registerMany(ACTIONS);
|
||||
await strapi.service('admin::permission').actionProvider.registerMany(ACTIONS);
|
||||
|
||||
strapi
|
||||
.hook('strapi::content-types.beforeSync')
|
||||
|
||||
@ -48,7 +48,7 @@ const getGroupName = (queryValue?: ReleaseActionGroupBy) => {
|
||||
}
|
||||
};
|
||||
|
||||
const createReleaseService = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
const createReleaseService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const dispatchWebhook = (
|
||||
event: string,
|
||||
{ isPublished, release, error }: { isPublished: boolean; release?: any; error?: unknown }
|
||||
|
||||
@ -6,7 +6,7 @@ import { Release } from '../../../shared/contracts/releases';
|
||||
import { getService } from '../utils';
|
||||
import { RELEASE_MODEL_UID } from '../constants';
|
||||
|
||||
const createSchedulingService = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
const createSchedulingService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const scheduledJobs = new Map<Release['id'], Job>();
|
||||
|
||||
return {
|
||||
@ -21,7 +21,7 @@ const createSchedulingService = ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
|
||||
const job = scheduleJob(scheduleDate, async () => {
|
||||
try {
|
||||
await getService('release').publish(releaseId);
|
||||
await getService('release', { strapi }).publish(releaseId);
|
||||
// @TODO: Trigger webhook with success message
|
||||
} catch (error) {
|
||||
// @TODO: Trigger webhook with error message
|
||||
|
||||
@ -11,7 +11,7 @@ export class AlreadyOnReleaseError extends errors.ApplicationError<'AlreadyOnRel
|
||||
}
|
||||
}
|
||||
|
||||
const createReleaseValidationService = ({ strapi }: { strapi: Core.LoadedStrapi }) => ({
|
||||
const createReleaseValidationService = ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
async validateUniqueEntry(
|
||||
releaseId: CreateReleaseAction.Request['params']['releaseId'],
|
||||
releaseActionArgs: CreateReleaseAction.Request['body']
|
||||
@ -60,8 +60,10 @@ const createReleaseValidationService = ({ strapi }: { strapi: Core.LoadedStrapi
|
||||
},
|
||||
async validatePendingReleasesLimit() {
|
||||
// Use the maximum releases option if it exists, otherwise default to 3
|
||||
const featureCfg = strapi.ee.features.get('cms-content-releases');
|
||||
|
||||
const maximumPendingReleases =
|
||||
strapi.ee.features.get('cms-content-releases')?.options?.maximumReleases || 3;
|
||||
(typeof featureCfg === 'object' && featureCfg?.options?.maximumReleases) || 3;
|
||||
|
||||
const [, pendingReleasesCount] = await strapi.db.query(RELEASE_MODEL_UID).findWithCount({
|
||||
filters: {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import type { UID, Data } from '@strapi/types';
|
||||
import type { UID, Data, Core } from '@strapi/types';
|
||||
|
||||
export const getService = (
|
||||
name: 'release' | 'release-validation' | 'scheduling' | 'release-action' | 'event-manager',
|
||||
{ strapi } = { strapi: global.strapi }
|
||||
{ strapi }: { strapi: Core.Strapi }
|
||||
) => {
|
||||
return strapi.plugin('content-releases').service(name);
|
||||
};
|
||||
@ -10,7 +10,7 @@ export const getService = (
|
||||
export const getPopulatedEntry = async (
|
||||
contentTypeUid: UID.ContentType,
|
||||
entryId: Data.ID,
|
||||
{ strapi } = { strapi: global.strapi }
|
||||
{ strapi }: { strapi: Core.Strapi }
|
||||
) => {
|
||||
const populateBuilderService = strapi.plugin('content-manager').service('populate-builder');
|
||||
// @ts-expect-error - populateBuilderService should be a function but is returning service
|
||||
@ -27,7 +27,7 @@ export const getPopulatedEntry = async (
|
||||
export const getEntryValidStatus = async (
|
||||
contentTypeUid: UID.ContentType,
|
||||
entry: { id: Data.ID; [key: string]: any },
|
||||
{ strapi } = { strapi: global.strapi }
|
||||
{ strapi }: { strapi: Core.Strapi }
|
||||
) => {
|
||||
try {
|
||||
// Same function used by entity-manager to validate entries before publishing
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
|
||||
export default async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
export default async ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const actions = [
|
||||
{
|
||||
section: 'plugins',
|
||||
@ -10,5 +10,5 @@ export default async ({ strapi }: { strapi: Core.LoadedStrapi }) => {
|
||||
},
|
||||
];
|
||||
|
||||
await strapi.admin.services.permission.actionProvider.registerMany(actions);
|
||||
await strapi.service('admin::permission').actionProvider.registerMany(actions);
|
||||
};
|
||||
|
||||
@ -3,29 +3,25 @@ import _ from 'lodash';
|
||||
import { isFunction } from 'lodash/fp';
|
||||
import { Logger, createLogger } from '@strapi/logger';
|
||||
import { Database } from '@strapi/database';
|
||||
import { hooks } from '@strapi/utils';
|
||||
|
||||
import type { Core, Modules, UID, Schema } from '@strapi/types';
|
||||
|
||||
import loadConfiguration from './configuration';
|
||||
import { loadConfiguration } from './configuration';
|
||||
|
||||
import * as factories from './factories';
|
||||
|
||||
import * as utils from './utils';
|
||||
import * as registries from './registries';
|
||||
import * as loaders from './loaders';
|
||||
import { Container } from './container';
|
||||
import createStrapiFs from './services/fs';
|
||||
import createEventHub from './services/event-hub';
|
||||
import { createServer } from './services/server';
|
||||
import createWebhookRunner, { WebhookRunner } from './services/webhook-runner';
|
||||
import { webhookModel, createWebhookStore } from './services/webhook-store';
|
||||
import { createCoreStore, coreStoreModel } from './services/core-store';
|
||||
import { createReloader } from './services/reloader';
|
||||
|
||||
import { providers } from './providers';
|
||||
import createEntityService from './services/entity-service';
|
||||
import createQueryParamService from './services/query-params';
|
||||
|
||||
import createCronService from './services/cron';
|
||||
import entityValidator from './services/entity-validator';
|
||||
import createTelemetry from './services/metrics';
|
||||
import requestContext from './services/request-context';
|
||||
import createAuth from './services/auth';
|
||||
import createCustomFields from './services/custom-fields';
|
||||
@ -34,208 +30,113 @@ import getNumberOfDynamicZones from './services/utils/dynamic-zones';
|
||||
import { FeaturesService, createFeaturesService } from './services/features';
|
||||
import { createDocumentService } from './services/document-service';
|
||||
|
||||
// TODO: move somewhere else
|
||||
import * as draftAndPublishSync from './migrations/draft-publish';
|
||||
import { coreStoreModel } from './services/core-store';
|
||||
import { createConfigProvider } from './services/config';
|
||||
|
||||
/**
|
||||
* Resolve the working directories based on the instance options.
|
||||
*
|
||||
* Behavior:
|
||||
* - `appDir` is the directory where Strapi will write every file (schemas, generated APIs, controllers or services)
|
||||
* - `distDir` is the directory where Strapi will read configurations, schemas and any compiled code
|
||||
*
|
||||
* Default values:
|
||||
* - If `appDir` is `undefined`, it'll be set to `process.cwd()`
|
||||
* - If `distDir` is `undefined`, it'll be set to `appDir`
|
||||
*/
|
||||
const resolveWorkingDirectories = (opts: { appDir?: string; distDir?: string }) => {
|
||||
const cwd = process.cwd();
|
||||
class Strapi extends Container implements Core.Strapi {
|
||||
app: any;
|
||||
|
||||
const appDir = opts.appDir ? path.resolve(cwd, opts.appDir) : cwd;
|
||||
const distDir = opts.distDir ? path.resolve(cwd, opts.distDir) : appDir;
|
||||
isLoaded: boolean = false;
|
||||
|
||||
return { app: appDir, dist: distDir };
|
||||
};
|
||||
internal_config: Record<string, unknown> = {};
|
||||
|
||||
const reloader = (strapi: Strapi) => {
|
||||
const state = {
|
||||
shouldReload: 0,
|
||||
isWatching: true,
|
||||
};
|
||||
constructor(opts: StrapiOptions) {
|
||||
super();
|
||||
|
||||
function reload() {
|
||||
if (state.shouldReload > 0) {
|
||||
// Reset the reloading state
|
||||
state.shouldReload -= 1;
|
||||
reload.isReloading = false;
|
||||
return;
|
||||
}
|
||||
this.internal_config = loadConfiguration(opts);
|
||||
|
||||
if (strapi.config.get('autoReload')) {
|
||||
process.send?.('reload');
|
||||
this.registerInternalServices();
|
||||
|
||||
for (const provider of providers) {
|
||||
provider.init?.(this);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(reload, 'isWatching', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
set(value) {
|
||||
// Special state when the reloader is disabled temporarly (see GraphQL plugin example).
|
||||
if (state.isWatching === false && value === true) {
|
||||
state.shouldReload += 1;
|
||||
}
|
||||
state.isWatching = value;
|
||||
},
|
||||
get() {
|
||||
return state.isWatching;
|
||||
},
|
||||
});
|
||||
get admin(): Core.Module {
|
||||
return this.get('admin');
|
||||
}
|
||||
|
||||
reload.isReloading = false;
|
||||
reload.isWatching = true;
|
||||
get EE(): boolean {
|
||||
return utils.ee.isEE;
|
||||
}
|
||||
|
||||
return reload;
|
||||
};
|
||||
get ee(): Core.Strapi['ee'] {
|
||||
return utils.ee;
|
||||
}
|
||||
|
||||
export type LoadedStrapi = Required<Strapi>;
|
||||
get dirs(): Core.StrapiDirectories {
|
||||
return this.config.get('dirs');
|
||||
}
|
||||
|
||||
class Strapi extends Container implements Core.Strapi {
|
||||
server: Modules.Server.Server;
|
||||
get reload(): Core.Reloader {
|
||||
return this.get('reload');
|
||||
}
|
||||
|
||||
log: Logger;
|
||||
get db(): Database {
|
||||
return this.get('db');
|
||||
}
|
||||
|
||||
fs: Core.StrapiFS;
|
||||
get requestContext(): Modules.RequestContext.RequestContext {
|
||||
return this.get('requestContext');
|
||||
}
|
||||
|
||||
eventHub: Modules.EventHub.EventHub;
|
||||
get customFields(): Modules.CustomFields.CustomFields {
|
||||
return this.get('customFields');
|
||||
}
|
||||
|
||||
startupLogger: Core.StartupLogger;
|
||||
|
||||
cron: Modules.Cron.CronService;
|
||||
|
||||
webhookRunner?: WebhookRunner;
|
||||
|
||||
webhookStore?: Modules.WebhookStore.WebhookStore;
|
||||
|
||||
store?: Modules.CoreStore.CoreStore;
|
||||
|
||||
entityValidator?: Modules.EntityValidator.EntityValidator;
|
||||
get entityValidator(): Modules.EntityValidator.EntityValidator {
|
||||
return this.get('entityValidator');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated `strapi.entityService` will be removed in the next major version
|
||||
*/
|
||||
entityService?: Modules.EntityService.EntityService;
|
||||
get entityService(): Modules.EntityService.EntityService {
|
||||
return this.get('entityService');
|
||||
}
|
||||
|
||||
documents?: Modules.Documents.Service;
|
||||
get documents(): Modules.Documents.Service {
|
||||
return this.get('documents');
|
||||
}
|
||||
|
||||
telemetry: Modules.Metrics.TelemetryService;
|
||||
get features(): FeaturesService {
|
||||
return this.get('features');
|
||||
}
|
||||
|
||||
requestContext: Modules.RequestContext.RequestContext;
|
||||
get fetch(): Modules.Fetch.Fetch {
|
||||
return this.get('fetch');
|
||||
}
|
||||
|
||||
customFields: Modules.CustomFields.CustomFields;
|
||||
get cron(): Modules.Cron.CronService {
|
||||
return this.get('cron');
|
||||
}
|
||||
|
||||
fetch: Modules.Fetch.Fetch;
|
||||
get log(): Logger {
|
||||
return this.get('logger');
|
||||
}
|
||||
|
||||
dirs: Core.StrapiDirectories;
|
||||
get startupLogger(): Core.StartupLogger {
|
||||
return this.get('startupLogger');
|
||||
}
|
||||
|
||||
admin?: Core.Module;
|
||||
get eventHub(): Modules.EventHub.EventHub {
|
||||
return this.get('eventHub');
|
||||
}
|
||||
|
||||
isLoaded: boolean;
|
||||
get fs(): Core.StrapiFS {
|
||||
return this.get('fs');
|
||||
}
|
||||
|
||||
db: Database;
|
||||
get server(): Modules.Server.Server {
|
||||
return this.get('server');
|
||||
}
|
||||
|
||||
app: any;
|
||||
get telemetry(): Modules.Metrics.TelemetryService {
|
||||
return this.get('telemetry');
|
||||
}
|
||||
|
||||
EE?: boolean;
|
||||
|
||||
reload: Core.Reloader;
|
||||
|
||||
features: FeaturesService;
|
||||
|
||||
// @ts-expect-error - Assigned in constructor
|
||||
ee: Core.Strapi['ee'];
|
||||
|
||||
constructor(opts: StrapiOptions = {}) {
|
||||
super();
|
||||
|
||||
utils.destroyOnSignal(this);
|
||||
|
||||
const rootDirs = resolveWorkingDirectories(opts);
|
||||
|
||||
// Load the app configuration from the dist directory
|
||||
const appConfig = loadConfiguration(rootDirs, opts);
|
||||
|
||||
// Instantiate the Strapi container
|
||||
this.add('config', registries.config(appConfig, this))
|
||||
.add('content-types', registries.contentTypes())
|
||||
.add('components', registries.components())
|
||||
.add('services', registries.services(this))
|
||||
.add('policies', registries.policies())
|
||||
.add('middlewares', registries.middlewares())
|
||||
.add('hooks', registries.hooks())
|
||||
.add('controllers', registries.controllers(this))
|
||||
.add('modules', registries.modules(this))
|
||||
.add('plugins', registries.plugins(this))
|
||||
.add('custom-fields', registries.customFields(this))
|
||||
.add('apis', registries.apis(this))
|
||||
.add('sanitizers', registries.sanitizers())
|
||||
.add('validators', registries.validators())
|
||||
.add('query-params', createQueryParamService(this))
|
||||
.add('content-api', createContentAPI(this))
|
||||
.add('auth', createAuth())
|
||||
.add('models', registries.models());
|
||||
|
||||
// Create a mapping of every useful directory (for the app, dist and static directories)
|
||||
this.dirs = utils.getDirs(rootDirs, { strapi: this });
|
||||
|
||||
// Strapi state management variables
|
||||
this.isLoaded = false;
|
||||
this.reload = reloader(this);
|
||||
|
||||
// Instantiate the Koa app & the HTTP server
|
||||
this.server = createServer(this);
|
||||
|
||||
// Strapi utils instantiation
|
||||
this.fs = createStrapiFs(this);
|
||||
this.eventHub = createEventHub();
|
||||
this.startupLogger = utils.createStartupLogger(this);
|
||||
|
||||
const logConfig = {
|
||||
level: 'http', // Strapi defaults to level 'http'
|
||||
...this.config.get('logger'), // DEPRECATED
|
||||
...this.config.get('server.logger.config'),
|
||||
};
|
||||
|
||||
this.log = createLogger(logConfig);
|
||||
this.cron = createCronService();
|
||||
this.telemetry = createTelemetry(this);
|
||||
this.requestContext = requestContext;
|
||||
this.customFields = createCustomFields(this);
|
||||
this.fetch = utils.createStrapiFetch(this);
|
||||
this.features = createFeaturesService(this);
|
||||
this.db = new Database(
|
||||
_.merge(this.config.get('database'), {
|
||||
settings: {
|
||||
migrations: {
|
||||
dir: path.join(this.dirs.app.root, 'database/migrations'),
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
utils.createUpdateNotifier(this).notify();
|
||||
|
||||
Object.defineProperty<Strapi>(this, 'EE', {
|
||||
get: () => {
|
||||
utils.ee.init(this.dirs.app.root, this.log);
|
||||
return utils.ee.isEE;
|
||||
},
|
||||
configurable: false,
|
||||
});
|
||||
|
||||
Object.defineProperty<Strapi>(this, 'ee', {
|
||||
get: () => utils.ee,
|
||||
configurable: false,
|
||||
});
|
||||
get store(): Modules.CoreStore.CoreStore {
|
||||
return this.get('coreStore');
|
||||
}
|
||||
|
||||
get config() {
|
||||
@ -340,24 +241,45 @@ class Strapi extends Container implements Core.Strapi {
|
||||
}
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
this.log.info('Shutting down Strapi');
|
||||
await this.server.destroy();
|
||||
await this.runLifecyclesFunctions(utils.LIFECYCLES.DESTROY);
|
||||
|
||||
this.eventHub.destroy();
|
||||
|
||||
await this.db?.destroy();
|
||||
|
||||
this.telemetry.destroy();
|
||||
this.cron.destroy();
|
||||
|
||||
process.removeAllListeners();
|
||||
|
||||
// @ts-expect-error: Allow clean delete of global.strapi to allow re-instanciation
|
||||
delete global.strapi;
|
||||
|
||||
this.log.info('Strapi has been shut down');
|
||||
// TODO: split into more providers
|
||||
registerInternalServices() {
|
||||
// Instantiate the Strapi container
|
||||
this.add('config', () => createConfigProvider(this.internal_config, this))
|
||||
.add('query-params', createQueryParamService(this))
|
||||
.add('content-api', createContentAPI(this))
|
||||
.add('auth', createAuth())
|
||||
.add('server', () => createServer(this))
|
||||
.add('fs', () => createStrapiFs(this))
|
||||
.add('eventHub', () => createEventHub())
|
||||
.add('startupLogger', () => utils.createStartupLogger(this))
|
||||
.add('logger', () => {
|
||||
return createLogger({
|
||||
level: 'http', // Strapi defaults to level 'http'
|
||||
...this.config.get('logger'), // DEPRECATED
|
||||
...this.config.get('server.logger.config'),
|
||||
});
|
||||
})
|
||||
.add('fetch', () => utils.createStrapiFetch(this))
|
||||
.add('features', () => createFeaturesService(this))
|
||||
.add('requestContext', requestContext)
|
||||
.add('customFields', createCustomFields(this))
|
||||
.add('entityValidator', entityValidator)
|
||||
.add('entityService', () => createEntityService({ strapi: this, db: this.db }))
|
||||
.add('documents', () => createDocumentService(this))
|
||||
.add(
|
||||
'db',
|
||||
() =>
|
||||
new Database(
|
||||
_.merge(this.config.get('database'), {
|
||||
settings: {
|
||||
migrations: {
|
||||
dir: path.join(this.dirs.app.root, 'database/migrations'),
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
)
|
||||
.add('reload', () => createReloader(this));
|
||||
}
|
||||
|
||||
sendStartupTelemetry() {
|
||||
@ -457,32 +379,25 @@ class Strapi extends Container implements Core.Strapi {
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
registerInternalHooks() {
|
||||
this.get('hooks').set('strapi::content-types.beforeSync', hooks.createAsyncParallelHook());
|
||||
this.get('hooks').set('strapi::content-types.afterSync', hooks.createAsyncParallelHook());
|
||||
async load() {
|
||||
await this.register();
|
||||
await this.bootstrap();
|
||||
|
||||
this.hook('strapi::content-types.beforeSync').register(draftAndPublishSync.disable);
|
||||
this.hook('strapi::content-types.afterSync').register(draftAndPublishSync.enable);
|
||||
this.isLoaded = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async register() {
|
||||
await loaders.loadApplicationContext(this);
|
||||
// @ts-expect-error: init is internal
|
||||
this.ee.init(this.dirs.app.root, this.log);
|
||||
|
||||
this.get('models').add(coreStoreModel).add(webhookModel);
|
||||
|
||||
// init webhook runner
|
||||
this.webhookRunner = createWebhookRunner({
|
||||
eventHub: this.eventHub,
|
||||
logger: this.log,
|
||||
configuration: this.config.get('server.webhooks', {}),
|
||||
fetch: this.fetch,
|
||||
});
|
||||
|
||||
this.registerInternalHooks();
|
||||
|
||||
this.telemetry.register();
|
||||
for (const provider of providers) {
|
||||
await provider.register?.(this);
|
||||
}
|
||||
|
||||
await this.runLifecyclesFunctions(utils.LIFECYCLES.REGISTER);
|
||||
|
||||
// NOTE: Swap type customField for underlying data type
|
||||
utils.convertCustomFieldType(this);
|
||||
|
||||
@ -500,24 +415,6 @@ class Strapi extends Container implements Core.Strapi {
|
||||
|
||||
await this.db.init({ models });
|
||||
|
||||
this.store = createCoreStore({ db: this.db });
|
||||
this.webhookStore = createWebhookStore({ db: this.db });
|
||||
|
||||
this.entityValidator = entityValidator;
|
||||
this.entityService = createEntityService({
|
||||
strapi: this,
|
||||
db: this.db,
|
||||
});
|
||||
|
||||
this.documents = createDocumentService(this);
|
||||
|
||||
if (this.config.get('server.cron.enabled', true)) {
|
||||
const cronTasks = this.config.get('server.cron.tasks', {});
|
||||
this.cron.add(cronTasks);
|
||||
}
|
||||
|
||||
this.telemetry.bootstrap();
|
||||
|
||||
let oldContentTypes;
|
||||
if (await this.db.getSchemaConnection().hasTable(coreStoreModel.tableName)) {
|
||||
oldContentTypes = await this.store.get({
|
||||
@ -550,8 +447,6 @@ class Strapi extends Container implements Core.Strapi {
|
||||
value: this.contentTypes,
|
||||
});
|
||||
|
||||
await this.startWebhooks();
|
||||
|
||||
await this.server.initMiddlewares();
|
||||
this.server.initRouting();
|
||||
|
||||
@ -559,41 +454,39 @@ class Strapi extends Container implements Core.Strapi {
|
||||
|
||||
await this.runLifecyclesFunctions(utils.LIFECYCLES.BOOTSTRAP);
|
||||
|
||||
this.cron.start();
|
||||
for (const provider of providers) {
|
||||
await provider.bootstrap?.(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async load() {
|
||||
await this.register();
|
||||
await this.bootstrap();
|
||||
async destroy() {
|
||||
this.log.info('Shutting down Strapi');
|
||||
await this.runLifecyclesFunctions(utils.LIFECYCLES.DESTROY);
|
||||
|
||||
this.isLoaded = true;
|
||||
|
||||
return this as this & Required<Core.Strapi>;
|
||||
}
|
||||
|
||||
async startWebhooks() {
|
||||
const webhooks = await this.webhookStore?.findWebhooks();
|
||||
if (!webhooks) {
|
||||
return;
|
||||
for (const provider of providers) {
|
||||
await provider.destroy?.(this);
|
||||
}
|
||||
|
||||
for (const webhook of webhooks) {
|
||||
this.webhookRunner?.add(webhook);
|
||||
}
|
||||
await this.server.destroy();
|
||||
|
||||
this.eventHub.destroy();
|
||||
|
||||
await this.db?.destroy();
|
||||
|
||||
process.removeAllListeners();
|
||||
|
||||
// @ts-expect-error: Allow clean delete of global.strapi to allow re-instanciation
|
||||
delete global.strapi;
|
||||
|
||||
this.log.info('Strapi has been shut down');
|
||||
}
|
||||
|
||||
async runLifecyclesFunctions(lifecycleName: 'register' | 'bootstrap' | 'destroy') {
|
||||
// plugins
|
||||
await this.get('modules')[lifecycleName]();
|
||||
|
||||
// admin
|
||||
const adminLifecycleFunction = this.admin && this.admin[lifecycleName];
|
||||
if (isFunction(adminLifecycleFunction)) {
|
||||
await adminLifecycleFunction({ strapi: this });
|
||||
}
|
||||
|
||||
// user
|
||||
const userLifecycleFunction = this.app && this.app[lifecycleName];
|
||||
if (isFunction(userLifecycleFunction)) {
|
||||
@ -622,8 +515,8 @@ class Strapi extends Container implements Core.Strapi {
|
||||
}
|
||||
|
||||
export interface StrapiOptions {
|
||||
appDir?: string;
|
||||
distDir?: string;
|
||||
appDir: string;
|
||||
distDir: string;
|
||||
autoReload?: boolean;
|
||||
serveAdminPanel?: boolean;
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ const RESTRICTED_FILENAMES = [
|
||||
'packageJsonStrapi',
|
||||
'info',
|
||||
'autoReload',
|
||||
'dirs',
|
||||
|
||||
// probably mistaken/typo filenames
|
||||
...Object.keys(MISTAKEN_FILENAMES),
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import { join, resolve } from 'path';
|
||||
import { get } from 'lodash/fp';
|
||||
|
||||
import type { Core } from '@strapi/types';
|
||||
import type { StrapiOptions } from '../Strapi';
|
||||
|
||||
export type Options = {
|
||||
app: string;
|
||||
@ -7,8 +10,8 @@ export type Options = {
|
||||
};
|
||||
|
||||
export const getDirs = (
|
||||
{ app: appDir, dist: distDir }: Options,
|
||||
{ strapi }: { strapi: Core.Strapi }
|
||||
{ appDir, distDir }: StrapiOptions,
|
||||
config: { server: Partial<Core.Config.Server> }
|
||||
): Core.StrapiDirectories => ({
|
||||
dist: {
|
||||
root: distDir,
|
||||
@ -31,6 +34,6 @@ export const getDirs = (
|
||||
config: join(appDir, 'config'),
|
||||
},
|
||||
static: {
|
||||
public: resolve(appDir, strapi.config.get('server.dirs.public')),
|
||||
public: resolve(appDir, get('server.dirs.public', config)),
|
||||
},
|
||||
});
|
||||
@ -5,9 +5,12 @@ import _ from 'lodash';
|
||||
import { omit } from 'lodash/fp';
|
||||
import dotenv from 'dotenv';
|
||||
import type { Core } from '@strapi/types';
|
||||
import { getConfigUrls, getAbsoluteAdminUrl, getAbsoluteServerUrl } from './urls';
|
||||
|
||||
import { getConfigUrls, getAbsoluteAdminUrl, getAbsoluteServerUrl } from './urls';
|
||||
import loadConfigDir from './config-loader';
|
||||
import { getDirs } from './get-dirs';
|
||||
|
||||
import type { StrapiOptions } from '../Strapi';
|
||||
|
||||
dotenv.config({ path: process.env.ENV_PATH });
|
||||
|
||||
@ -45,9 +48,8 @@ const defaultConfig = {
|
||||
} satisfies Partial<Core.Config.Api>,
|
||||
};
|
||||
|
||||
export default (dirs: { app: string; dist: string }, initialConfig: any = {}) => {
|
||||
const { app: appDir, dist: distDir } = dirs;
|
||||
const { autoReload = false, serveAdminPanel = true } = initialConfig;
|
||||
export const loadConfiguration = (opts: StrapiOptions) => {
|
||||
const { appDir, distDir, autoReload = false, serveAdminPanel = true } = opts;
|
||||
|
||||
const pkgJSON = require(path.resolve(appDir, 'package.json'));
|
||||
|
||||
@ -83,6 +85,7 @@ export default (dirs: { app: string; dist: string }, initialConfig: any = {}) =>
|
||||
_.set(config, 'admin.url', adminUrl);
|
||||
_.set(config, 'admin.path', adminPath);
|
||||
_.set(config, 'admin.absoluteUrl', getAbsoluteAdminUrl(config));
|
||||
_.set(config, 'dirs', getDirs(opts, config));
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
@ -11,7 +11,7 @@ interface EE {
|
||||
enabled: boolean;
|
||||
licenseInfo: {
|
||||
licenseKey?: string;
|
||||
features?: Array<{ name: string } | string>;
|
||||
features?: Array<{ name: string; [key: string]: any } | string>;
|
||||
expireAt?: string;
|
||||
seats?: number;
|
||||
type?: string;
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
|
||||
import Strapi, { type StrapiOptions } from './Strapi';
|
||||
import { destroyOnSignal, resolveWorkingDirectories, createUpdateNotifier } from './utils';
|
||||
|
||||
export { default as compileStrapi } from './compile';
|
||||
export * as factories from './factories';
|
||||
|
||||
export const createStrapi = (options: StrapiOptions = {}): Core.Strapi => {
|
||||
const strapi = new Strapi(options);
|
||||
export const createStrapi = (options: Partial<StrapiOptions> = {}): Core.Strapi => {
|
||||
const strapi = new Strapi({
|
||||
...options,
|
||||
...resolveWorkingDirectories(options),
|
||||
});
|
||||
|
||||
destroyOnSignal(strapi);
|
||||
createUpdateNotifier(strapi);
|
||||
|
||||
// TODO: deprecate and remove in next major
|
||||
global.strapi = strapi as Core.LoadedStrapi;
|
||||
global.strapi = strapi;
|
||||
|
||||
return strapi;
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ import type { Core, Struct } from '@strapi/types';
|
||||
import { getGlobalId } from '../domain/content-type';
|
||||
|
||||
export default async function loadAdmin(strapi: Core.Strapi) {
|
||||
strapi.admin = require('@strapi/admin/strapi-server');
|
||||
// strapi.admin = require('@strapi/admin/strapi-server');
|
||||
|
||||
strapi.get('services').add(`admin::`, strapi.admin?.services);
|
||||
strapi.get('controllers').add(`admin::`, strapi.admin?.controllers);
|
||||
|
||||
@ -6,7 +6,6 @@ import loadMiddlewares from './middlewares';
|
||||
import loadComponents from './components';
|
||||
import loadPolicies from './policies';
|
||||
import loadPlugins from './plugins';
|
||||
import loadAdmin from './admin';
|
||||
import loadSanitizers from './sanitizers';
|
||||
import loadValidators from './validators';
|
||||
|
||||
@ -16,7 +15,6 @@ export async function loadApplicationContext(strapi: Core.Strapi) {
|
||||
loadSanitizers(strapi),
|
||||
loadValidators(strapi),
|
||||
loadPlugins(strapi),
|
||||
loadAdmin(strapi),
|
||||
loadAPIs(strapi),
|
||||
loadComponents(strapi),
|
||||
loadMiddlewares(strapi),
|
||||
|
||||
22
packages/core/core/src/providers/admin.ts
Normal file
22
packages/core/core/src/providers/admin.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { defineProvider } from './provider';
|
||||
import loadAdmin from '../loaders/admin';
|
||||
|
||||
export default defineProvider({
|
||||
init(strapi) {
|
||||
strapi.add('admin', () => require('@strapi/admin/strapi-server'));
|
||||
},
|
||||
|
||||
async register(strapi) {
|
||||
await loadAdmin(strapi);
|
||||
|
||||
await strapi.get('admin')?.register({ strapi });
|
||||
},
|
||||
|
||||
async bootstrap(strapi) {
|
||||
await strapi.get('admin')?.bootstrap({ strapi });
|
||||
},
|
||||
|
||||
async destroy(strapi) {
|
||||
await strapi.get('admin')?.destroy({ strapi });
|
||||
},
|
||||
});
|
||||
9
packages/core/core/src/providers/coreStore.ts
Normal file
9
packages/core/core/src/providers/coreStore.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { defineProvider } from './provider';
|
||||
import { createCoreStore, coreStoreModel } from '../services/core-store';
|
||||
|
||||
export default defineProvider({
|
||||
init(strapi) {
|
||||
strapi.get('models').add(coreStoreModel);
|
||||
strapi.add('coreStore', () => createCoreStore({ db: strapi.db }));
|
||||
},
|
||||
});
|
||||
19
packages/core/core/src/providers/cron.ts
Normal file
19
packages/core/core/src/providers/cron.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { defineProvider } from './provider';
|
||||
import createCronService from '../services/cron';
|
||||
|
||||
export default defineProvider({
|
||||
init(strapi) {
|
||||
strapi.add('cron', () => createCronService());
|
||||
},
|
||||
async bootstrap(strapi) {
|
||||
if (strapi.config.get('server.cron.enabled', true)) {
|
||||
const cronTasks = strapi.config.get('server.cron.tasks', {});
|
||||
strapi.get('cron').add(cronTasks);
|
||||
}
|
||||
|
||||
strapi.get('cron').start();
|
||||
},
|
||||
async destroy(strapi) {
|
||||
strapi.get('cron').destroy();
|
||||
},
|
||||
});
|
||||
10
packages/core/core/src/providers/index.ts
Normal file
10
packages/core/core/src/providers/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import admin from './admin';
|
||||
import coreStore from './coreStore';
|
||||
import cron from './cron';
|
||||
import registries from './registries';
|
||||
import telemetry from './telemetry';
|
||||
import webhooks from './webhooks';
|
||||
|
||||
import type { Provider } from './provider';
|
||||
|
||||
export const providers: Provider[] = [registries, admin, coreStore, webhooks, telemetry, cron];
|
||||
10
packages/core/core/src/providers/provider.ts
Normal file
10
packages/core/core/src/providers/provider.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
|
||||
export type Provider = {
|
||||
init?: (strapi: Core.Strapi) => void;
|
||||
register?: (strapi: Core.Strapi) => Promise<void>;
|
||||
bootstrap?: (strapi: Core.Strapi) => Promise<void>;
|
||||
destroy?: (strapi: Core.Strapi) => Promise<void>;
|
||||
};
|
||||
|
||||
export const defineProvider = (provider: Provider) => provider;
|
||||
35
packages/core/core/src/providers/registries.ts
Normal file
35
packages/core/core/src/providers/registries.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { hooks } from '@strapi/utils';
|
||||
|
||||
import { defineProvider } from './provider';
|
||||
import * as registries from '../registries';
|
||||
import { loadApplicationContext } from '../loaders';
|
||||
import * as draftAndPublishSync from '../migrations/draft-publish';
|
||||
|
||||
export default defineProvider({
|
||||
init(strapi) {
|
||||
strapi
|
||||
.add('content-types', () => registries.contentTypes())
|
||||
.add('components', () => registries.components())
|
||||
.add('services', () => registries.services(strapi))
|
||||
.add('policies', () => registries.policies())
|
||||
.add('middlewares', () => registries.middlewares())
|
||||
.add('hooks', () => registries.hooks())
|
||||
.add('controllers', () => registries.controllers(strapi))
|
||||
.add('modules', () => registries.modules(strapi))
|
||||
.add('plugins', () => registries.plugins(strapi))
|
||||
.add('custom-fields', () => registries.customFields(strapi))
|
||||
.add('apis', () => registries.apis(strapi))
|
||||
.add('models', () => registries.models())
|
||||
.add('sanitizers', registries.sanitizers())
|
||||
.add('validators', registries.validators());
|
||||
},
|
||||
async register(strapi) {
|
||||
await loadApplicationContext(strapi);
|
||||
|
||||
strapi.get('hooks').set('strapi::content-types.beforeSync', hooks.createAsyncParallelHook());
|
||||
strapi.get('hooks').set('strapi::content-types.afterSync', hooks.createAsyncParallelHook());
|
||||
|
||||
strapi.hook('strapi::content-types.beforeSync').register(draftAndPublishSync.disable);
|
||||
strapi.hook('strapi::content-types.afterSync').register(draftAndPublishSync.enable);
|
||||
},
|
||||
});
|
||||
17
packages/core/core/src/providers/telemetry.ts
Normal file
17
packages/core/core/src/providers/telemetry.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { defineProvider } from './provider';
|
||||
import createTelemetry from '../services/metrics';
|
||||
|
||||
export default defineProvider({
|
||||
init(strapi) {
|
||||
strapi.add('telemetry', () => createTelemetry(strapi));
|
||||
},
|
||||
async register(strapi) {
|
||||
strapi.get('telemetry').register();
|
||||
},
|
||||
async bootstrap(strapi) {
|
||||
strapi.get('telemetry').bootstrap();
|
||||
},
|
||||
async destroy(strapi) {
|
||||
strapi.get('telemetry').destroy();
|
||||
},
|
||||
});
|
||||
29
packages/core/core/src/providers/webhooks.ts
Normal file
29
packages/core/core/src/providers/webhooks.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { defineProvider } from './provider';
|
||||
import { createWebhookStore, webhookModel } from '../services/webhook-store';
|
||||
import createWebhookRunner from '../services/webhook-runner';
|
||||
|
||||
export default defineProvider({
|
||||
init(strapi) {
|
||||
strapi.get('models').add(webhookModel);
|
||||
|
||||
strapi.add('webhookStore', () => createWebhookStore({ db: strapi.db }));
|
||||
strapi.add('webhookRunner', () =>
|
||||
createWebhookRunner({
|
||||
eventHub: strapi.eventHub,
|
||||
logger: strapi.log,
|
||||
configuration: strapi.config.get('server.webhooks', {}),
|
||||
fetch: strapi.fetch,
|
||||
})
|
||||
);
|
||||
},
|
||||
async bootstrap(strapi) {
|
||||
const webhooks = await strapi.get('webhookStore').findWebhooks();
|
||||
if (!webhooks) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const webhook of webhooks) {
|
||||
strapi.get('webhookRunner').add(webhook);
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -1,31 +1,31 @@
|
||||
import configProvider from '../config';
|
||||
import { createConfigProvider } from '../../services/config';
|
||||
|
||||
const logLevel = 'warn';
|
||||
|
||||
describe('config', () => {
|
||||
test('returns objects for partial paths', () => {
|
||||
const config = configProvider({ default: { child: 'val' } });
|
||||
const config = createConfigProvider({ default: { child: 'val' } });
|
||||
expect(config.get('default')).toEqual({ child: 'val' });
|
||||
});
|
||||
|
||||
test('supports full string paths', () => {
|
||||
const config = configProvider({ default: { child: 'val' } });
|
||||
const config = createConfigProvider({ default: { child: 'val' } });
|
||||
expect(config.get('default.child')).toEqual('val');
|
||||
});
|
||||
|
||||
test('supports array paths', () => {
|
||||
const config = configProvider({ default: { child: 'val' } });
|
||||
const config = createConfigProvider({ default: { child: 'val' } });
|
||||
expect(config.get(['default', 'child'])).toEqual('val');
|
||||
});
|
||||
|
||||
test('accepts initial values', () => {
|
||||
const config = configProvider({ default: 'val', foo: 'bar' });
|
||||
const config = createConfigProvider({ default: 'val', foo: 'bar' });
|
||||
expect(config.get('default')).toEqual('val');
|
||||
expect(config.get('foo')).toEqual('bar');
|
||||
});
|
||||
|
||||
test('accepts uid in paths', () => {
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'api::myapi': { foo: 'val' },
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
@ -39,7 +39,7 @@ describe('config', () => {
|
||||
test('`get` supports `plugin::` prefix', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -51,7 +51,7 @@ describe('config', () => {
|
||||
test('`get` supports `plugin::model` in array path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -64,7 +64,7 @@ describe('config', () => {
|
||||
test('`get` supports `plugin.` prefix in string path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -76,7 +76,7 @@ describe('config', () => {
|
||||
test('`get` supports `plugin.model` prefix in array path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -88,7 +88,7 @@ describe('config', () => {
|
||||
test('`get` supports `plugin` + `model` in array path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -99,7 +99,7 @@ describe('config', () => {
|
||||
test('`set` supports `plugin.` prefix in string path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
config.set('plugin.myplugin.thing', 'val');
|
||||
@ -112,7 +112,7 @@ describe('config', () => {
|
||||
test('`set` supports `plugin.` prefix in array path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
config.set(['plugin.myplugin', 'thing'], 'val');
|
||||
@ -125,7 +125,7 @@ describe('config', () => {
|
||||
test('`has` supports `plugin.` prefix in string path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -138,7 +138,7 @@ describe('config', () => {
|
||||
test('`has` supports `plugin.` prefix in array path', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -152,7 +152,7 @@ describe('config', () => {
|
||||
const consoleSpy = jest.spyOn(console, logLevel).mockImplementation(() => {});
|
||||
|
||||
const logSpy = jest.fn();
|
||||
const config = configProvider(
|
||||
const config = createConfigProvider(
|
||||
{
|
||||
'plugin::myplugin': { foo: 'bar' },
|
||||
},
|
||||
@ -166,7 +166,7 @@ describe('config', () => {
|
||||
});
|
||||
|
||||
test('get does NOT support deprecation for other prefixes', () => {
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'api::myapi': { foo: 'bar' },
|
||||
});
|
||||
|
||||
@ -174,7 +174,7 @@ describe('config', () => {
|
||||
});
|
||||
|
||||
test('set does NOT support deprecation for other prefixes', () => {
|
||||
const config = configProvider({
|
||||
const config = createConfigProvider({
|
||||
'api::myapi': { foo: 'bar' },
|
||||
});
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@ export { default as controllers } from './controllers';
|
||||
export { default as modules } from './modules';
|
||||
export { default as plugins } from './plugins';
|
||||
export { default as customFields } from './custom-fields';
|
||||
export { default as config } from './config';
|
||||
export { default as apis } from './apis';
|
||||
export { default as sanitizers } from './sanitizers';
|
||||
export { default as validators } from './validators';
|
||||
|
||||
@ -1,13 +1,19 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
import { get, set, has, isString, isNumber, isArray, type PropertyPath } from 'lodash';
|
||||
|
||||
type State = {
|
||||
config: Config;
|
||||
};
|
||||
|
||||
type Config = Record<string, unknown>;
|
||||
|
||||
export default (
|
||||
initialConfig = {},
|
||||
strapi?: Core.Strapi | Core.LoadedStrapi
|
||||
export const createConfigProvider = (
|
||||
initialConfig: Record<string, unknown> = {},
|
||||
strapi?: Core.Strapi
|
||||
): Core.ConfigProvider => {
|
||||
const _config: Config = { ...initialConfig }; // not deep clone because it would break some config
|
||||
const state: State = {
|
||||
config: { ...initialConfig }, // not deep clone because it would break some config
|
||||
};
|
||||
|
||||
// Accessing model configs with dot (.) was deprecated between v4->v5, but to avoid a major breaking change
|
||||
// we will still support certain namespaces, currently only 'plugin.'
|
||||
@ -42,16 +48,16 @@ export default (
|
||||
};
|
||||
|
||||
return {
|
||||
..._config, // TODO: to remove
|
||||
...state.config, // TODO: to remove
|
||||
get(path: PropertyPath, defaultValue?: unknown) {
|
||||
return get(_config, transformDeprecatedPaths(path), defaultValue);
|
||||
return get(state.config, transformDeprecatedPaths(path), defaultValue);
|
||||
},
|
||||
set(path: PropertyPath, val: unknown) {
|
||||
set(_config, transformDeprecatedPaths(path), val);
|
||||
set(state.config, transformDeprecatedPaths(path), val);
|
||||
return this;
|
||||
},
|
||||
has(path: PropertyPath) {
|
||||
return has(_config, transformDeprecatedPaths(path));
|
||||
return has(state.config, transformDeprecatedPaths(path));
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -27,7 +27,7 @@ describe('Extract document ids from relation data', () => {
|
||||
db: {
|
||||
query: jest.fn((uid) => ({ findMany: findManyQueries[uid] })),
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
});
|
||||
|
||||
it('Load single document id', async () => {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
|
||||
import { PRODUCT_UID, CATEGORY_UID, models } from './utils';
|
||||
import { transformParamsDocumentId } from '../id-transform';
|
||||
|
||||
@ -39,7 +37,7 @@ describe('Transform relational data', () => {
|
||||
db: {
|
||||
query: jest.fn((uid) => ({ findMany: findManyQueries[uid] })),
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
findCategories.mockReturnValue([
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
|
||||
import { PRODUCT_UID, SHOP_UID, models } from './utils';
|
||||
import { transformParamsDocumentId } from '../id-transform';
|
||||
|
||||
@ -33,7 +31,7 @@ describe('Transform relational data', () => {
|
||||
db: {
|
||||
query: jest.fn((uid) => ({ findMany: findManyQueries[uid] })),
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
findShops.mockReturnValue([
|
||||
|
||||
@ -33,7 +33,7 @@ describe('Transform relational data', () => {
|
||||
db: {
|
||||
query: jest.fn((uid) => ({ findMany: findManyQueries[uid] })),
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as unknown as Core.Strapi;
|
||||
|
||||
beforeEach(() => {
|
||||
findCategories.mockReturnValue([
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Core } from '@strapi/types';
|
||||
import { PRODUCT_UID, CATEGORY_UID, models } from './utils';
|
||||
|
||||
import { transformPopulate } from '../populate';
|
||||
@ -23,7 +22,7 @@ describe('transformPopulate', () => {
|
||||
})),
|
||||
},
|
||||
},
|
||||
} as unknown as Core.LoadedStrapi;
|
||||
} as any;
|
||||
});
|
||||
|
||||
// TODO: Are these all realistic formats for populate?
|
||||
|
||||
41
packages/core/core/src/services/reloader.ts
Normal file
41
packages/core/core/src/services/reloader.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import type { Core } from '@strapi/types';
|
||||
|
||||
export const createReloader = (strapi: Core.Strapi) => {
|
||||
const state = {
|
||||
shouldReload: 0,
|
||||
isWatching: true,
|
||||
};
|
||||
|
||||
function reload() {
|
||||
if (state.shouldReload > 0) {
|
||||
// Reset the reloading state
|
||||
state.shouldReload -= 1;
|
||||
reload.isReloading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strapi.config.get('autoReload')) {
|
||||
process.send?.('reload');
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(reload, 'isWatching', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
set(value) {
|
||||
// Special state when the reloader is disabled temporarly (see GraphQL plugin example).
|
||||
if (state.isWatching === false && value === true) {
|
||||
state.shouldReload += 1;
|
||||
}
|
||||
state.isWatching = value;
|
||||
},
|
||||
get() {
|
||||
return state.isWatching;
|
||||
},
|
||||
});
|
||||
|
||||
reload.isReloading = false;
|
||||
reload.isWatching = true;
|
||||
|
||||
return reload;
|
||||
};
|
||||
@ -31,7 +31,7 @@ export default (strapi: Core.Strapi) => {
|
||||
const registerAdminRoutes = (strapi: Core.Strapi) => {
|
||||
const generateRouteScope = createRouteScopeGenerator(`admin::`);
|
||||
|
||||
_.forEach(strapi.admin?.routes, (router) => {
|
||||
_.forEach(strapi.admin.routes, (router) => {
|
||||
router.type = router.type || 'admin';
|
||||
router.prefix = router.prefix || `/admin`;
|
||||
router.routes.forEach((route) => {
|
||||
|
||||
@ -106,8 +106,6 @@ export interface WebhookStore {
|
||||
}
|
||||
|
||||
const createWebhookStore = ({ db }: { db: Database }): WebhookStore => {
|
||||
const webhookQueries = db.query('strapi::webhook');
|
||||
|
||||
return {
|
||||
allowedEvents: new Map([]),
|
||||
addAllowedEvent(key, value) {
|
||||
@ -123,18 +121,19 @@ const createWebhookStore = ({ db }: { db: Database }): WebhookStore => {
|
||||
return this.allowedEvents.get(key);
|
||||
},
|
||||
async findWebhooks() {
|
||||
const results = await webhookQueries.findMany();
|
||||
const results = await db.query('strapi::webhook').findMany();
|
||||
|
||||
return results.map(fromDBObject);
|
||||
},
|
||||
async findWebhook(id) {
|
||||
const result = await webhookQueries.findOne({ where: { id } });
|
||||
const result = await db.query('strapi::webhook').findOne({ where: { id } });
|
||||
return result ? fromDBObject(result) : null;
|
||||
},
|
||||
async createWebhook(data) {
|
||||
await webhookEventValidator(this.allowedEvents, data.events);
|
||||
|
||||
return webhookQueries
|
||||
return db
|
||||
.query('strapi::webhook')
|
||||
.create({
|
||||
data: toDBObject({ ...data, isEnabled: true }),
|
||||
})
|
||||
@ -143,7 +142,7 @@ const createWebhookStore = ({ db }: { db: Database }): WebhookStore => {
|
||||
async updateWebhook(id, data) {
|
||||
await webhookEventValidator(this.allowedEvents, data.events);
|
||||
|
||||
const webhook = await webhookQueries.update({
|
||||
const webhook = await db.query('strapi::webhook').update({
|
||||
where: { id },
|
||||
data: toDBObject(data),
|
||||
});
|
||||
@ -151,7 +150,7 @@ const createWebhookStore = ({ db }: { db: Database }): WebhookStore => {
|
||||
return webhook ? fromDBObject(webhook) : null;
|
||||
},
|
||||
async deleteWebhook(id) {
|
||||
const webhook = await webhookQueries.delete({ where: { id } });
|
||||
const webhook = await db.query('strapi::webhook').delete({ where: { id } });
|
||||
return webhook ? fromDBObject(webhook) : null;
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export { openBrowser } from './open-browser';
|
||||
export { isInitialized } from './is-initialized';
|
||||
export { getDirs } from './get-dirs';
|
||||
export { getDirs } from '../configuration/get-dirs';
|
||||
export { ee } from './ee';
|
||||
export { createUpdateNotifier } from './update-notifier';
|
||||
export { createStrapiFetch, Fetch } from './fetch';
|
||||
@ -9,3 +9,4 @@ export { createStartupLogger } from './startup-logger';
|
||||
export { transformContentTypesToModels } from './transform-content-types-to-models';
|
||||
export { destroyOnSignal } from './signals';
|
||||
export { LIFECYCLES } from './lifecycles';
|
||||
export { resolveWorkingDirectories } from './resolve-working-dirs';
|
||||
|
||||
21
packages/core/core/src/utils/resolve-working-dirs.ts
Normal file
21
packages/core/core/src/utils/resolve-working-dirs.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import path from 'node:path';
|
||||
|
||||
/**
|
||||
* Resolve the working directories based on the instance options.
|
||||
*
|
||||
* Behavior:
|
||||
* - `appDir` is the directory where Strapi will write every file (schemas, generated APIs, controllers or services)
|
||||
* - `distDir` is the directory where Strapi will read configurations, schemas and any compiled code
|
||||
*
|
||||
* Default values:
|
||||
* - If `appDir` is `undefined`, it'll be set to `process.cwd()`
|
||||
* - If `distDir` is `undefined`, it'll be set to `appDir`
|
||||
*/
|
||||
export const resolveWorkingDirectories = (opts: { appDir?: string; distDir?: string }) => {
|
||||
const cwd = process.cwd();
|
||||
|
||||
const appDir = opts.appDir ? path.resolve(cwd, opts.appDir) : cwd;
|
||||
const distDir = opts.distDir ? path.resolve(cwd, opts.distDir) : appDir;
|
||||
|
||||
return { appDir, distDir };
|
||||
};
|
||||
@ -43,6 +43,7 @@ export const createUpdateNotifier = (strapi: Core.Strapi) => {
|
||||
} catch {
|
||||
// we don't have write access to the file system
|
||||
// we silence the error
|
||||
return;
|
||||
}
|
||||
|
||||
const checkUpdate = async (checkInterval: number) => {
|
||||
@ -83,21 +84,17 @@ export const createUpdateNotifier = (strapi: Core.Strapi) => {
|
||||
console.log(message);
|
||||
};
|
||||
|
||||
return {
|
||||
notify({ checkInterval = CHECK_INTERVAL, notifInterval = NOTIF_INTERVAL } = {}) {
|
||||
// TODO v6: Remove this warning
|
||||
if (env.bool('STRAPI_DISABLE_UPDATE_NOTIFICATION', false)) {
|
||||
strapi.log.warn(
|
||||
'STRAPI_DISABLE_UPDATE_NOTIFICATION is no longer supported. Instead, set logger.updates.enabled to false in your server configuration.'
|
||||
);
|
||||
}
|
||||
// TODO v6: Remove this warning
|
||||
if (env.bool('STRAPI_DISABLE_UPDATE_NOTIFICATION', false)) {
|
||||
strapi.log.warn(
|
||||
'STRAPI_DISABLE_UPDATE_NOTIFICATION is no longer supported. Instead, set logger.updates.enabled to false in your server configuration.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!strapi.config.get('server.logger.updates.enabled') || !config) {
|
||||
return;
|
||||
}
|
||||
if (!strapi.config.get('server.logger.updates.enabled') || !config) {
|
||||
return;
|
||||
}
|
||||
|
||||
display(notifInterval);
|
||||
checkUpdate(checkInterval); // doesn't need to await
|
||||
},
|
||||
};
|
||||
display(NOTIF_INTERVAL);
|
||||
checkUpdate(CHECK_INTERVAL); // doesn't need to await
|
||||
};
|
||||
|
||||
@ -25,13 +25,13 @@ export const collect = <T = unknown>(stream: Readable): Promise<T[]> => {
|
||||
export const getStrapiFactory =
|
||||
<
|
||||
T extends {
|
||||
[key in keyof Partial<Core.LoadedStrapi>]: unknown;
|
||||
[key in keyof Partial<Core.Strapi>]: unknown;
|
||||
},
|
||||
>(
|
||||
properties?: T
|
||||
) =>
|
||||
(additionalProperties?: Partial<T>) => {
|
||||
return { ...properties, ...additionalProperties } as Core.LoadedStrapi;
|
||||
return { ...properties, ...additionalProperties } as Core.Strapi;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -113,7 +113,7 @@ export const destinationStages = [
|
||||
/**
|
||||
* Update the global store with the given strapi value
|
||||
*/
|
||||
export const setGlobalStrapi = (strapi: Core.LoadedStrapi): void => {
|
||||
export const setGlobalStrapi = (strapi: Core.Strapi): void => {
|
||||
(global as unknown as Global).strapi = strapi;
|
||||
};
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ export const VALID_CONFLICT_STRATEGIES = ['restore'];
|
||||
export const DEFAULT_CONFLICT_STRATEGY = 'restore';
|
||||
|
||||
export interface ILocalStrapiDestinationProviderOptions {
|
||||
getStrapi(): Core.LoadedStrapi | Promise<Core.LoadedStrapi>; // return an initialized instance of Strapi
|
||||
getStrapi(): Core.Strapi | Promise<Core.Strapi>; // return an initialized instance of Strapi
|
||||
|
||||
autoDestroy?: boolean; // shut down the instance returned by getStrapi() at the end of the transfer
|
||||
restore?: restore.IRestoreOptions; // erase data in strapi database before transfer; required if strategy is 'restore'
|
||||
@ -39,7 +39,7 @@ class LocalStrapiDestinationProvider implements IDestinationProvider {
|
||||
|
||||
options: ILocalStrapiDestinationProviderOptions;
|
||||
|
||||
strapi?: Core.LoadedStrapi;
|
||||
strapi?: Core.Strapi;
|
||||
|
||||
transaction?: Transaction;
|
||||
|
||||
|
||||
@ -7,10 +7,7 @@ import { IConfiguration, Transaction } from '../../../../../../types';
|
||||
|
||||
const omitInvalidCreationAttributes = omit(['id']);
|
||||
|
||||
const restoreCoreStore = async <T extends { value: unknown }>(
|
||||
strapi: Core.LoadedStrapi,
|
||||
values: T
|
||||
) => {
|
||||
const restoreCoreStore = async <T extends { value: unknown }>(strapi: Core.Strapi, values: T) => {
|
||||
const data = omitInvalidCreationAttributes(values);
|
||||
return strapi.db.query('strapi::core-store').create({
|
||||
data: {
|
||||
@ -20,15 +17,12 @@ const restoreCoreStore = async <T extends { value: unknown }>(
|
||||
});
|
||||
};
|
||||
|
||||
const restoreWebhooks = async <T extends { value: unknown }>(
|
||||
strapi: Core.LoadedStrapi,
|
||||
values: T
|
||||
) => {
|
||||
const restoreWebhooks = async <T extends { value: unknown }>(strapi: Core.Strapi, values: T) => {
|
||||
const data = omitInvalidCreationAttributes(values);
|
||||
return strapi.db.query('strapi::webhook').create({ data });
|
||||
};
|
||||
|
||||
export const restoreConfigs = async (strapi: Core.LoadedStrapi, config: IConfiguration) => {
|
||||
export const restoreConfigs = async (strapi: Core.Strapi, config: IConfiguration) => {
|
||||
if (config.type === 'core-store') {
|
||||
return restoreCoreStore(strapi, config.value as { value: unknown });
|
||||
}
|
||||
@ -39,7 +33,7 @@ export const restoreConfigs = async (strapi: Core.LoadedStrapi, config: IConfigu
|
||||
};
|
||||
|
||||
export const createConfigurationWriteStream = async (
|
||||
strapi: Core.LoadedStrapi,
|
||||
strapi: Core.Strapi,
|
||||
transaction?: Transaction
|
||||
) => {
|
||||
return new Writable({
|
||||
|
||||
@ -10,7 +10,7 @@ import * as queries from '../../../../queries';
|
||||
import { resolveComponentUID } from '../../../../../utils/components';
|
||||
|
||||
interface IEntitiesRestoreStreamOptions {
|
||||
strapi: Core.LoadedStrapi;
|
||||
strapi: Core.Strapi;
|
||||
updateMappingTable<TSchemaUID extends UID.Schema>(
|
||||
type: TSchemaUID,
|
||||
oldID: number,
|
||||
|
||||
@ -22,7 +22,7 @@ interface IDeleteResults {
|
||||
aggregate: { [uid: string]: { count: number } };
|
||||
}
|
||||
|
||||
export const deleteRecords = async (strapi: Core.LoadedStrapi, options: IRestoreOptions) => {
|
||||
export const deleteRecords = async (strapi: Core.Strapi, options: IRestoreOptions) => {
|
||||
const entities = await deleteEntitiesRecords(strapi, options);
|
||||
const configuration = await deleteConfigurationRecords(strapi, options);
|
||||
|
||||
@ -34,7 +34,7 @@ export const deleteRecords = async (strapi: Core.LoadedStrapi, options: IRestore
|
||||
};
|
||||
|
||||
const deleteEntitiesRecords = async (
|
||||
strapi: Core.LoadedStrapi,
|
||||
strapi: Core.Strapi,
|
||||
options: IRestoreOptions = {}
|
||||
): Promise<IDeleteResults> => {
|
||||
const { entities } = options;
|
||||
@ -112,7 +112,7 @@ const deleteEntitiesRecords = async (
|
||||
};
|
||||
|
||||
const deleteConfigurationRecords = async (
|
||||
strapi: Core.LoadedStrapi,
|
||||
strapi: Core.Strapi,
|
||||
options: IRestoreOptions = {}
|
||||
): Promise<IDeleteResults> => {
|
||||
const { coreStore = true, webhook = true } = options?.configuration ?? {};
|
||||
|
||||
@ -26,7 +26,7 @@ const isForeignKeyConstraintError = (e: Error) => {
|
||||
|
||||
export const createLinksWriteStream = (
|
||||
mapID: (uid: string, id: number) => number | undefined,
|
||||
strapi: Core.LoadedStrapi,
|
||||
strapi: Core.Strapi,
|
||||
transaction?: Transaction,
|
||||
onWarning?: (message: string) => void
|
||||
) => {
|
||||
|
||||
@ -8,7 +8,7 @@ import type { IAsset, IFile } from '../../../../types';
|
||||
|
||||
function getFileStream(
|
||||
filepath: string,
|
||||
strapi: Core.LoadedStrapi,
|
||||
strapi: Core.Strapi,
|
||||
isLocal = false
|
||||
): PassThrough | ReadStream {
|
||||
if (isLocal) {
|
||||
@ -43,7 +43,7 @@ function getFileStream(
|
||||
|
||||
function getFileStats(
|
||||
filepath: string,
|
||||
strapi: Core.LoadedStrapi,
|
||||
strapi: Core.Strapi,
|
||||
isLocal = false
|
||||
): Promise<{ size: number }> {
|
||||
if (isLocal) {
|
||||
@ -95,7 +95,7 @@ async function signFile(file: IFile) {
|
||||
/**
|
||||
* Generate and consume assets streams in order to stream each file individually
|
||||
*/
|
||||
export const createAssetsStream = (strapi: Core.LoadedStrapi): Duplex => {
|
||||
export const createAssetsStream = (strapi: Core.Strapi): Duplex => {
|
||||
const generator: () => AsyncGenerator<IAsset, void> = async function* () {
|
||||
const stream: Readable = strapi.db
|
||||
.queryBuilder('plugin::upload.file')
|
||||
|
||||
@ -8,7 +8,7 @@ import type { IConfiguration } from '../../../../types';
|
||||
/**
|
||||
* Create a readable stream that export the Strapi app configuration
|
||||
*/
|
||||
export const createConfigurationStream = (strapi: Core.LoadedStrapi): Readable => {
|
||||
export const createConfigurationStream = (strapi: Core.Strapi): Readable => {
|
||||
return Readable.from(
|
||||
(async function* configurationGenerator(): AsyncGenerator<IConfiguration> {
|
||||
// Core Store
|
||||
|
||||
@ -7,7 +7,7 @@ import { IEntity } from '../../../../types';
|
||||
/**
|
||||
* Generate and consume content-types streams in order to stream each entity individually
|
||||
*/
|
||||
export const createEntitiesStream = (strapi: Core.LoadedStrapi): Readable => {
|
||||
export const createEntitiesStream = (strapi: Core.Strapi): Readable => {
|
||||
const contentTypes: Struct.ContentTypeSchema[] = Object.values(strapi.contentTypes);
|
||||
|
||||
async function* contentTypeStreamGenerator() {
|
||||
|
||||
@ -11,7 +11,7 @@ import * as utils from '../../../utils';
|
||||
import { assertValidStrapi } from '../../../utils/providers';
|
||||
|
||||
export interface ILocalStrapiSourceProviderOptions {
|
||||
getStrapi(): Core.LoadedStrapi | Promise<Core.LoadedStrapi>; // return an initialized instance of Strapi
|
||||
getStrapi(): Core.Strapi | Promise<Core.Strapi>; // return an initialized instance of Strapi
|
||||
|
||||
autoDestroy?: boolean; // shut down the instance returned by getStrapi() at the end of the transfer
|
||||
}
|
||||
@ -27,7 +27,7 @@ class LocalStrapiSourceProvider implements ISourceProvider {
|
||||
|
||||
options: ILocalStrapiSourceProviderOptions;
|
||||
|
||||
strapi?: Core.LoadedStrapi;
|
||||
strapi?: Core.Strapi;
|
||||
|
||||
constructor(options: ILocalStrapiSourceProviderOptions) {
|
||||
this.options = options;
|
||||
|
||||
@ -7,7 +7,7 @@ import { createLinkQuery } from '../../queries/link';
|
||||
/**
|
||||
* Create a Readable which will stream all the links from a Strapi instance
|
||||
*/
|
||||
export const createLinksStream = (strapi: Core.LoadedStrapi): Readable => {
|
||||
export const createLinksStream = (strapi: Core.Strapi): Readable => {
|
||||
const uids = [...Object.keys(strapi.contentTypes), ...Object.keys(strapi.components)] as string[];
|
||||
|
||||
// Async generator stream that returns every link from a Strapi instance
|
||||
|
||||
@ -18,7 +18,7 @@ const sanitizeComponentLikeAttributes = <T extends Struct.Schema>(
|
||||
|
||||
const omitInvalidCreationAttributes = omit(['id']);
|
||||
|
||||
const createEntityQuery = (strapi: Core.LoadedStrapi): any => {
|
||||
const createEntityQuery = (strapi: Core.Strapi): any => {
|
||||
const components = {
|
||||
async assignToEntity(uid: UID.Schema, data: any) {
|
||||
const model = strapi.getModel(uid);
|
||||
|
||||
@ -6,7 +6,7 @@ import { ILink } from '../../../types';
|
||||
|
||||
// TODO: Remove any types when we'll have types for DB metadata
|
||||
|
||||
export const createLinkQuery = (strapi: Core.LoadedStrapi, trx?: Knex.Transaction) => {
|
||||
export const createLinkQuery = (strapi: Core.Strapi, trx?: Knex.Transaction) => {
|
||||
const query = () => {
|
||||
const { connection } = strapi.db;
|
||||
|
||||
|
||||
@ -304,7 +304,7 @@ export const createPullController = handlerControllerFactory<Partial<PullHandler
|
||||
|
||||
this.provider = createLocalStrapiSourceProvider({
|
||||
autoDestroy: false,
|
||||
getStrapi: () => strapi as Core.LoadedStrapi,
|
||||
getStrapi: () => strapi as Core.Strapi,
|
||||
});
|
||||
|
||||
return { transferID: this.transferID };
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user