@oktis-works/plugin-runtime 0.5.6 → 0.5.7

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.
@@ -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
- maxMemoryMb: number;
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: bloqueia CSS global se plugin declarar style inline sem escopo */
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
- private withTimeout;
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 {
@@ -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,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAQD,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,kGAAkG;IAClG,OAAO,CAAC,qBAAqB;IASvB,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;YAIC,WAAW;IAczB,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"}
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: bloqueia CSS global se plugin declarar style inline sem escopo */
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
- // apenas warn — escopo será aplicado em runtime via scopePluginCss
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)) {
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"AAQA,MAAM,oBAAoB,GAAkB;IAC1C,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG;IAChB,kBAAkB,EAAE,EAAE;CACvB,CAAC;AAEF,MAAM,OAAO,aAAa;IAChB,MAAM,CAAgB;IAE9B,YAAY,SAAiC,EAAE;QAC7C,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,oBAAoB,EAAE,GAAG,MAAM,EAAE,CAAC;IACvD,CAAC;IAED,UAAU,CAAC,QAAwB,EAAE,GAAc;QACjD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,kGAAkG;IAC1F,qBAAqB,CAAC,QAAwB;QACpD,MAAM,WAAW,GAAG,QAA8C,CAAC;QACnE,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACnJ,mEAAmE;YACnE,OAAO,CAAC,IAAI,CAAC,oBAAoB,QAAQ,CAAC,IAAI,uEAAuE,CAAC,CAAC;QACzH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CACf,QAAgB,EAChB,OAAsB,EACtB,OAA0B,EAC1B,OAAgB,EAChB,iBAA4B;QAE5B,IAAI,iBAAiB,EAAE,CAAC;YACtB,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAA+C,EAC/C,OAAsB,EACtB,GAAG,IAAe;QAElB,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAEO,KAAK,CAAC,WAAW,CAAI,OAAmB;QAC9C,IAAI,KAAiC,CAAC;QACtC,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;gBACxB,OAAO;gBACP,IAAI,OAAO,CAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;oBAC3B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBACnG,CAAC,CAAC;aACH,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAC,WAAqB;QAC5C,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBACzD,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,EAAE,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
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.6",
3
+ "version": "0.5.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",