@oktis-works/plugin-runtime 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap.d.ts +39 -4
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +158 -38
- package/dist/bootstrap.js.map +1 -1
- package/dist/hook-registry.d.ts +60 -1
- package/dist/hook-registry.d.ts.map +1 -1
- package/dist/hook-registry.js +142 -10
- package/dist/hook-registry.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +7 -14
- package/dist/loader.js.map +1 -1
- package/dist/manifest.d.ts +24 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +76 -0
- package/dist/manifest.js.map +1 -0
- package/dist/plugin-api.d.ts +148 -0
- package/dist/plugin-api.d.ts.map +1 -0
- package/dist/plugin-api.js +174 -0
- package/dist/plugin-api.js.map +1 -0
- package/dist/sandbox.d.ts +23 -3
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +29 -4
- package/dist/sandbox.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// @oktis-works/plugin-runtime - PluginAPI completa (WP7 + WP8)
|
|
2
|
+
//
|
|
3
|
+
// Este módulo expõe uma fábrica `createPluginApi` que o core injeta com os
|
|
4
|
+
// serviços reais (settings, eventBus, db, etc.). O plugin recebe um objeto
|
|
5
|
+
// com métodos tipados; o runtime só conhece a interface (evita ciclo de dep).
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
/**
|
|
8
|
+
* Cria a PluginAPI real a partir das dependências do core.
|
|
9
|
+
* Chamado pelo core no bootstrap (não pelo plugin-runtime diretamente).
|
|
10
|
+
* Retorna { api: PluginAPI, internal: PluginApiInternal } para separar a API pública dos detalhes internos.
|
|
11
|
+
*/
|
|
12
|
+
export function createPluginApi(deps) {
|
|
13
|
+
const { hooks, manifest, settings, eventBus, db, getTenantId, getUserId, getTenantById, getUserById, allowedPermissions } = deps;
|
|
14
|
+
// Valida permissão antes de executar query
|
|
15
|
+
function checkDbPermission() {
|
|
16
|
+
if (!allowedPermissions.includes('db:query')) {
|
|
17
|
+
throw new Error('Plugin permission denied: db:query');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const registeredRoutes = [];
|
|
21
|
+
const registeredFields = [];
|
|
22
|
+
// Build the public API object
|
|
23
|
+
const api = {
|
|
24
|
+
registerHook(type, handler) {
|
|
25
|
+
/**
|
|
26
|
+
* Maps plugin lifecycle hook types to internal action names.
|
|
27
|
+
* These actions are fired by the core at the corresponding lifecycle events.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // In plugin's register function:
|
|
31
|
+
* api.registerHook('onInstall', async (context, payload) => {
|
|
32
|
+
* // Runs when plugin is installed
|
|
33
|
+
* await context.api.query('CREATE TABLE IF NOT EXISTS my_plugin_data (...)');
|
|
34
|
+
* });
|
|
35
|
+
* api.registerHook('onActivate', async (context, payload) => {
|
|
36
|
+
* // Runs when plugin is activated for a tenant
|
|
37
|
+
* });
|
|
38
|
+
* api.registerHook('beforeContentCreate', async (context, payload) => {
|
|
39
|
+
* // Runs before content is created - can modify payload
|
|
40
|
+
* payload.data.custom_field = 'value';
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* Mapping:
|
|
44
|
+
* - onInstall -> plugin.install
|
|
45
|
+
* - onActivate -> plugin.activate
|
|
46
|
+
* - onDeactivate -> plugin.deactivate
|
|
47
|
+
* - onUninstall -> plugin.uninstall
|
|
48
|
+
* - onSettingsPage -> plugin.settings_page
|
|
49
|
+
* - onAdminMenu -> okcms.admin.menu
|
|
50
|
+
* - beforeContentCreate -> okcms.content.before-create
|
|
51
|
+
* - afterContentCreate -> okcms.content.after-create
|
|
52
|
+
* - beforeContentUpdate -> okcms.content.before-update
|
|
53
|
+
* - afterContentUpdate -> okcms.content.after-update
|
|
54
|
+
* - beforeContentDelete -> okcms.content.before-delete
|
|
55
|
+
* - afterContentDelete -> okcms.content.after-delete
|
|
56
|
+
* - onContentPublish -> okcms.content.published
|
|
57
|
+
* - onContentUnpublish -> okcms.content.unpublished
|
|
58
|
+
*/
|
|
59
|
+
const hookMap = {
|
|
60
|
+
'onInstall': 'plugin.install',
|
|
61
|
+
'onActivate': 'plugin.activate',
|
|
62
|
+
'onDeactivate': 'plugin.deactivate',
|
|
63
|
+
'onUninstall': 'plugin.uninstall',
|
|
64
|
+
'onSettingsPage': 'plugin.settings_page',
|
|
65
|
+
'onAdminMenu': 'okcms.admin.menu',
|
|
66
|
+
'beforeContentCreate': 'okcms.content.before-create',
|
|
67
|
+
'afterContentCreate': 'okcms.content.after-create',
|
|
68
|
+
'beforeContentUpdate': 'okcms.content.before-update',
|
|
69
|
+
'afterContentUpdate': 'okcms.content.after-update',
|
|
70
|
+
'beforeContentDelete': 'okcms.content.before-delete',
|
|
71
|
+
'afterContentDelete': 'okcms.content.after-delete',
|
|
72
|
+
'onContentPublish': 'okcms.content.published',
|
|
73
|
+
'onContentUnpublish': 'okcms.content.unpublished',
|
|
74
|
+
};
|
|
75
|
+
const hookName = hookMap[type];
|
|
76
|
+
if (!hookName) {
|
|
77
|
+
console.warn(`[PluginAPI] Hook type "${type}" não mapeado — ignorado`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
hooks.addAction(hookName, async (...args) => {
|
|
81
|
+
const [context, payload] = args;
|
|
82
|
+
await handler(context, payload);
|
|
83
|
+
}, { sourceId: manifest.name, sourceType: 'plugin' });
|
|
84
|
+
},
|
|
85
|
+
addRoute(route) {
|
|
86
|
+
if (route.requiredPermissions) {
|
|
87
|
+
for (const perm of route.requiredPermissions) {
|
|
88
|
+
if (!allowedPermissions.includes(perm)) {
|
|
89
|
+
throw new Error(`Plugin route permission denied: ${perm}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
registeredRoutes.push(route);
|
|
94
|
+
},
|
|
95
|
+
addContentField(field) {
|
|
96
|
+
registeredFields.push(field);
|
|
97
|
+
},
|
|
98
|
+
async getSetting(key, group) {
|
|
99
|
+
if (!allowedPermissions.includes('settings:read')) {
|
|
100
|
+
throw new Error('Plugin permission denied: settings:read');
|
|
101
|
+
}
|
|
102
|
+
const fullKey = group ? `${group}.${key}` : key;
|
|
103
|
+
return settings.get(fullKey);
|
|
104
|
+
},
|
|
105
|
+
async setSetting(key, value, group) {
|
|
106
|
+
if (!allowedPermissions.includes('settings:write')) {
|
|
107
|
+
throw new Error('Plugin permission denied: settings:write');
|
|
108
|
+
}
|
|
109
|
+
const fullKey = group ? `${group}.${key}` : key;
|
|
110
|
+
return settings.set(fullKey, value);
|
|
111
|
+
},
|
|
112
|
+
async getTenant() {
|
|
113
|
+
const tenantId = getTenantId();
|
|
114
|
+
if (!tenantId)
|
|
115
|
+
throw new Error('No tenant context');
|
|
116
|
+
const tenant = await getTenantById(tenantId);
|
|
117
|
+
if (!tenant)
|
|
118
|
+
throw new Error('Tenant not found');
|
|
119
|
+
return tenant;
|
|
120
|
+
},
|
|
121
|
+
async getUser() {
|
|
122
|
+
const userId = getUserId();
|
|
123
|
+
if (!userId)
|
|
124
|
+
throw new Error('No user context');
|
|
125
|
+
const user = await getUserById(userId);
|
|
126
|
+
if (!user)
|
|
127
|
+
throw new Error('User not found');
|
|
128
|
+
return user;
|
|
129
|
+
},
|
|
130
|
+
async query(sql, params) {
|
|
131
|
+
checkDbPermission();
|
|
132
|
+
return db.query(sql, params);
|
|
133
|
+
},
|
|
134
|
+
async emit(eventType, payload) {
|
|
135
|
+
if (!allowedPermissions.includes('events:emit')) {
|
|
136
|
+
throw new Error('Plugin permission denied: events:emit');
|
|
137
|
+
}
|
|
138
|
+
return eventBus.emit({ type: eventType, payload, id: randomUUID(), aggregateType: 'plugin', aggregateId: '', processed: false, createdAt: new Date() });
|
|
139
|
+
},
|
|
140
|
+
// Hooks WordPress-style (delegam para o registry)
|
|
141
|
+
addAction(action, callback, options) {
|
|
142
|
+
hooks.addAction(action, callback, { ...options, sourceId: manifest.name, sourceType: 'plugin' });
|
|
143
|
+
},
|
|
144
|
+
addFilter(filter, callback, options) {
|
|
145
|
+
hooks.addFilter(filter, callback, { ...options, sourceId: manifest.name, sourceType: 'plugin' });
|
|
146
|
+
},
|
|
147
|
+
removeAction(action, callback, priority) {
|
|
148
|
+
return hooks.removeAction(action, callback, priority);
|
|
149
|
+
},
|
|
150
|
+
removeFilter(filter, callback, priority) {
|
|
151
|
+
return hooks.removeFilter(filter, callback, priority);
|
|
152
|
+
},
|
|
153
|
+
hasAction(action, callback) {
|
|
154
|
+
return hooks.hasAction(action, callback);
|
|
155
|
+
},
|
|
156
|
+
hasFilter(filter, callback) {
|
|
157
|
+
return hooks.hasFilter(filter, callback);
|
|
158
|
+
},
|
|
159
|
+
didAction(action) {
|
|
160
|
+
return hooks.didAction(action);
|
|
161
|
+
},
|
|
162
|
+
currentHook() {
|
|
163
|
+
return hooks.getCurrentHook();
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
api,
|
|
168
|
+
internal: {
|
|
169
|
+
getRoutes: () => registeredRoutes,
|
|
170
|
+
getFields: () => registeredFields,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=plugin-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-api.js","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"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"}
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
import type { PluginManifest, PluginContext, PluginHookHandler, PluginAPI } from '@oktis-works/plugin-sdk';
|
|
2
2
|
export interface SandboxConfig {
|
|
3
|
+
/** Timeout para callbacks de hook (ms). 0 = sem timeout. */
|
|
3
4
|
timeoutMs: number;
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* **Política** de permissões concedidas (allowlist vinda de configuração /
|
|
7
|
+
* catálogo). Nunca o manifesto: passar as permissões do próprio manifesto
|
|
8
|
+
* aqui seria uma tautologia (aprovação garantida).
|
|
9
|
+
*/
|
|
5
10
|
allowedPermissions: string[];
|
|
6
11
|
}
|
|
7
12
|
export declare class PluginSandbox {
|
|
8
13
|
private config;
|
|
9
14
|
constructor(config?: Partial<SandboxConfig>);
|
|
10
15
|
loadPlugin(manifest: PluginManifest, api: PluginAPI): LoadedPlugin;
|
|
11
|
-
/** BUSI plugin-style-isolation:
|
|
16
|
+
/** BUSI plugin-style-isolation: CSS global sem escopo é escopado ao servir via scopePluginCss */
|
|
12
17
|
private enforceStyleIsolation;
|
|
13
18
|
executeHook(hookName: string, context: PluginContext, handler: PluginHookHandler, payload: unknown, pluginPermissions?: string[]): Promise<void>;
|
|
14
19
|
callHandler<T>(handler: (...args: unknown[]) => T | Promise<T>, context: PluginContext, ...args: unknown[]): Promise<T>;
|
|
15
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Aplica o timeout **no ponto real de execução** (registro do callback).
|
|
22
|
+
*
|
|
23
|
+
* - retorno síncrono → devolve o valor como está (semântica síncrona dos
|
|
24
|
+
* filtros, DECI-026 — um `applyFilters` não pode virar Promise);
|
|
25
|
+
* - retorno assíncrono → corre contra o timeout (`timeoutMs`).
|
|
26
|
+
*
|
|
27
|
+
* Limite honesto: `Promise.race` não interrompe CPU síncrona; plugins
|
|
28
|
+
* custosos de bloco continuam travando o processo (isolamento real seria
|
|
29
|
+
* worker/processo separado).
|
|
30
|
+
*/
|
|
31
|
+
wrapCallback<TArgs extends unknown[]>(fn: (...args: TArgs) => unknown): (...args: TArgs) => unknown;
|
|
32
|
+
/** Race Promise × timeout (API pública usada pelo bootstrap). */
|
|
33
|
+
withTimeout<T>(promise: Promise<T>): Promise<T>;
|
|
34
|
+
/** Política vigente (para testes/observabilidade). */
|
|
35
|
+
getPolicy(): SandboxConfig;
|
|
16
36
|
private checkPermissions;
|
|
17
37
|
}
|
|
18
38
|
export interface LoadedPlugin {
|
package/dist/sandbox.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE3G,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE3G,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAOD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAI/C,UAAU,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,EAAE,SAAS,GAAG,YAAY;IAMlE,iGAAiG;IACjG,OAAO,CAAC,qBAAqB;IAUvB,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,OAAO,EAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC;IAOV,WAAW,CAAC,CAAC,EACjB,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC/C,OAAO,EAAE,aAAa,EACtB,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,CAAC,CAAC;IAIb;;;;;;;;;;OAUG;IACH,YAAY,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO;IAWnG,iEAAiE;IAC3D,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAcrD,sDAAsD;IACtD,SAAS,IAAI,aAAa;IAI1B,OAAO,CAAC,gBAAgB;CAOzB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
package/dist/sandbox.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const defaultSandboxConfig = {
|
|
2
2
|
timeoutMs: 5000,
|
|
3
|
-
maxMemoryMb: 128,
|
|
4
3
|
allowedPermissions: [],
|
|
5
4
|
};
|
|
6
5
|
export class PluginSandbox {
|
|
@@ -13,13 +12,12 @@ export class PluginSandbox {
|
|
|
13
12
|
this.enforceStyleIsolation(manifest);
|
|
14
13
|
return { manifest, api, loaded: true, loadedAt: Date.now() };
|
|
15
14
|
}
|
|
16
|
-
/** BUSI plugin-style-isolation:
|
|
15
|
+
/** BUSI plugin-style-isolation: CSS global sem escopo é escopado ao servir via scopePluginCss */
|
|
17
16
|
enforceStyleIsolation(manifest) {
|
|
18
17
|
const anyManifest = manifest;
|
|
19
18
|
const style = anyManifest['style'] ?? anyManifest['styles'];
|
|
20
19
|
if (typeof style === 'string' && (style.includes(':root') || style.includes('html{') || style.includes('body{')) && !style.includes('data-plugin')) {
|
|
21
|
-
|
|
22
|
-
console.warn(`[sandbox] Plugin ${manifest.name} declara CSS global sem [data-plugin] — será escopado automaticamente`);
|
|
20
|
+
console.warn(`[sandbox] Plugin ${manifest.name} declara CSS global sem [data-plugin] — será escopado via scopePluginCss ao ser servido em /style.css`);
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
async executeHook(hookName, context, handler, payload, pluginPermissions) {
|
|
@@ -31,6 +29,29 @@ export class PluginSandbox {
|
|
|
31
29
|
async callHandler(handler, context, ...args) {
|
|
32
30
|
return this.withTimeout(Promise.resolve(handler(context, ...args)));
|
|
33
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Aplica o timeout **no ponto real de execução** (registro do callback).
|
|
34
|
+
*
|
|
35
|
+
* - retorno síncrono → devolve o valor como está (semântica síncrona dos
|
|
36
|
+
* filtros, DECI-026 — um `applyFilters` não pode virar Promise);
|
|
37
|
+
* - retorno assíncrono → corre contra o timeout (`timeoutMs`).
|
|
38
|
+
*
|
|
39
|
+
* Limite honesto: `Promise.race` não interrompe CPU síncrona; plugins
|
|
40
|
+
* custosos de bloco continuam travando o processo (isolamento real seria
|
|
41
|
+
* worker/processo separado).
|
|
42
|
+
*/
|
|
43
|
+
wrapCallback(fn) {
|
|
44
|
+
if (this.config.timeoutMs <= 0)
|
|
45
|
+
return fn;
|
|
46
|
+
return (...args) => {
|
|
47
|
+
const result = fn(...args);
|
|
48
|
+
if (result && typeof result.then === 'function') {
|
|
49
|
+
return this.withTimeout(result);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Race Promise × timeout (API pública usada pelo bootstrap). */
|
|
34
55
|
async withTimeout(promise) {
|
|
35
56
|
let timer;
|
|
36
57
|
try {
|
|
@@ -46,6 +67,10 @@ export class PluginSandbox {
|
|
|
46
67
|
clearTimeout(timer);
|
|
47
68
|
}
|
|
48
69
|
}
|
|
70
|
+
/** Política vigente (para testes/observabilidade). */
|
|
71
|
+
getPolicy() {
|
|
72
|
+
return { ...this.config };
|
|
73
|
+
}
|
|
49
74
|
checkPermissions(permissions) {
|
|
50
75
|
for (const permission of permissions) {
|
|
51
76
|
if (!this.config.allowedPermissions.includes(permission)) {
|
package/dist/sandbox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oktis-works/plugin-runtime",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@oktis-works/plugin-sdk": "^0.5.6",
|
|
20
|
-
"@oktis-works/types": "^0.5.
|
|
21
|
-
"@oktis-works/validation": "^0.
|
|
20
|
+
"@oktis-works/types": "^0.5.6",
|
|
21
|
+
"@oktis-works/validation": "^0.6.0",
|
|
22
22
|
"semver": "7"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|