@oktis-works/plugin-runtime 0.5.10 → 0.7.0

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.
Files changed (46) hide show
  1. package/dist/bootstrap.d.ts +86 -21
  2. package/dist/bootstrap.d.ts.map +1 -1
  3. package/dist/bootstrap.js +254 -42
  4. package/dist/bootstrap.js.map +1 -1
  5. package/dist/content-query.d.ts +29 -0
  6. package/dist/content-query.d.ts.map +1 -0
  7. package/dist/content-query.js +109 -0
  8. package/dist/content-query.js.map +1 -0
  9. package/dist/hook-registry.d.ts +21 -21
  10. package/dist/hook-registry.d.ts.map +1 -1
  11. package/dist/hook-registry.js +26 -26
  12. package/dist/hook-registry.js.map +1 -1
  13. package/dist/http.d.ts +49 -0
  14. package/dist/http.d.ts.map +1 -0
  15. package/dist/http.js +313 -0
  16. package/dist/http.js.map +1 -0
  17. package/dist/i18n.d.ts +16 -0
  18. package/dist/i18n.d.ts.map +1 -0
  19. package/dist/i18n.js +73 -0
  20. package/dist/i18n.js.map +1 -0
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/loader.js +3 -3
  26. package/dist/loader.js.map +1 -1
  27. package/dist/manifest.d.ts +11 -6
  28. package/dist/manifest.d.ts.map +1 -1
  29. package/dist/manifest.js +227 -17
  30. package/dist/manifest.js.map +1 -1
  31. package/dist/plugin-api.d.ts +191 -38
  32. package/dist/plugin-api.d.ts.map +1 -1
  33. package/dist/plugin-api.js +572 -10
  34. package/dist/plugin-api.js.map +1 -1
  35. package/dist/plugin-migrations.d.ts +15 -0
  36. package/dist/plugin-migrations.d.ts.map +1 -0
  37. package/dist/plugin-migrations.js +68 -0
  38. package/dist/plugin-migrations.js.map +1 -0
  39. package/dist/sandbox.d.ts +13 -11
  40. package/dist/sandbox.d.ts.map +1 -1
  41. package/dist/sandbox.js +11 -9
  42. package/dist/sandbox.js.map +1 -1
  43. package/dist/style-isolation.d.ts +3 -3
  44. package/dist/style-isolation.js +6 -6
  45. package/dist/style-isolation.js.map +1 -1
  46. package/package.json +7 -6
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-api.d.ts","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin-api.d.ts","sourceRoot":"","sources":["../src/plugin-api.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,48 @@
1
- // @oktis-works/plugin-runtime - PluginAPI completa (WP7 + WP8)
1
+ // @oktis-works/plugin-runtime - Full PluginAPI (WP7 + WP8)
2
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).
3
+ // This module exposes a `createPluginApi` factory that the core injects with
4
+ // the real services (settings, eventBus, db, etc.). The plugin receives an
5
+ // object with typed methods; the runtime only knows the interface (avoids a
6
+ // dependency cycle).
6
7
  import { randomUUID } from 'node:crypto';
8
+ import { PERMISSIONS, createPluginAdminApi } from '@oktis-works/plugin-sdk';
9
+ import { createHttpApi } from './http.js';
10
+ import { i18nFallbackChain, i18nInterpolate } from './i18n.js';
11
+ import { ContentQueryBuilder } from './content-query.js';
7
12
  /**
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.
13
+ * Creates the real PluginAPI from the core dependencies.
14
+ * Called by the core at bootstrap (not by plugin-runtime directly).
15
+ * Returns { api: PluginAPI, internal: PluginApiInternal } to separate the
16
+ * public API from the internal details.
11
17
  */
18
+ /**
19
+ * In-memory cache fallback when the core provided no backend (dev or legacy
20
+ * API). Always available — `api.cache` never throws for unavailability.
21
+ */
22
+ function createMemoryCacheBackend() {
23
+ const store = new Map();
24
+ return {
25
+ get: async (key) => {
26
+ const entry = store.get(key);
27
+ if (!entry)
28
+ return null;
29
+ if (Date.now() > entry.expiresAt) {
30
+ store.delete(key);
31
+ return null;
32
+ }
33
+ return entry.value;
34
+ },
35
+ set: async (key, value, ttlSeconds) => {
36
+ store.set(key, { value, expiresAt: Date.now() + (ttlSeconds ?? 300) * 1000 });
37
+ },
38
+ del: async (key) => {
39
+ store.delete(key);
40
+ },
41
+ };
42
+ }
12
43
  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
44
+ const { hooks, manifest, settings, eventBus, db, getTenantId, getUserId, getTenantById, getUserById, allowedPermissions, registerFieldTypes, registerPostTypes, registerTaxonomies } = deps;
45
+ // Validates the permission before running a query
15
46
  function checkDbPermission() {
16
47
  if (!allowedPermissions.includes('db:query')) {
17
48
  throw new Error('Plugin permission denied: db:query');
@@ -19,6 +50,406 @@ export function createPluginApi(deps) {
19
50
  }
20
51
  const registeredRoutes = [];
21
52
  const registeredFields = [];
53
+ // Runtime type includes pluginName and isPluginType added during registration
54
+ const registeredFieldTypes = [];
55
+ const registeredPostTypes = [];
56
+ const registeredTaxonomies = [];
57
+ const registeredBlocks = [];
58
+ const registeredPatterns = [];
59
+ // ── api.admin (FEAT-098/DECI-027): declarative slots registered at
60
+ // runtime; the /api/v1/plugins/extensions endpoint merges with manifest.admin.
61
+ const adminApi = createPluginAdminApi(manifest.name);
62
+ /** CPT/taxonomy slugs: lowercase, digits, underscore and hyphen (WP style). */
63
+ const SLUG_PATTERN = /^[a-z][a-z0-9_-]*$/;
64
+ /** Reserved slugs no plugin can claim. */
65
+ const RESERVED_SLUGS = new Set(['post', 'page', 'media', 'user', 'content', 'attachment', 'category', 'tag']);
66
+ // ── api.cache (Item 2): plugin:{tenant}:{plugin}:{key} namespace + tags ──
67
+ const cacheBackend = deps.cache ?? createMemoryCacheBackend();
68
+ function cacheKeyFor(key) {
69
+ if (typeof key !== 'string' || key.trim().length === 0) {
70
+ throw new Error('cache key must be a non-empty string');
71
+ }
72
+ if (key.length > 200) {
73
+ throw new Error('cache key too long (max 200 chars)');
74
+ }
75
+ return `plugin:${getTenantId() ?? 'platform'}:${manifest.name}:${key}`;
76
+ }
77
+ function tagIndexKeyFor(tag) {
78
+ return `plugin:${getTenantId() ?? 'platform'}:${manifest.name}:__tag__:${tag}`;
79
+ }
80
+ function requirePermission(permission) {
81
+ if (!allowedPermissions.includes(permission)) {
82
+ throw new Error(`Plugin permission denied: ${permission}`);
83
+ }
84
+ }
85
+ // ── Item 18: audit of sensitive plugin operations (write queries,
86
+ // addRoute, jobs) → audit_log. Fire-and-forget: an audit failure never
87
+ // blocks or breaks the plugin operation (same rule as auditService).
88
+ const MUTATION_PATTERN = /^\s*(INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE|GRANT|REVOKE)\b/i;
89
+ function auditPlugin(action, resourceType, changes) {
90
+ try {
91
+ void deps.audit?.record({
92
+ tenantId: getTenantId(),
93
+ action,
94
+ resourceType,
95
+ resourceId: manifest.name,
96
+ changes: { plugin: manifest.name, ...changes },
97
+ });
98
+ }
99
+ catch {
100
+ // auditing never blocks the operation
101
+ }
102
+ }
103
+ const cacheApi = {
104
+ async get(key) {
105
+ requirePermission(PERMISSIONS.CACHE_READ);
106
+ return cacheBackend.get(cacheKeyFor(key));
107
+ },
108
+ async set(key, value, options) {
109
+ requirePermission(PERMISSIONS.CACHE_WRITE);
110
+ const fullKey = cacheKeyFor(key);
111
+ const ttl = options?.ttlSeconds;
112
+ await cacheBackend.set(fullKey, value, ttl);
113
+ // Tag → keys index (TTL tracking the value; the index expires with it
114
+ // and orphan keys expire through their own value TTL).
115
+ for (const tag of options?.tags ?? []) {
116
+ if (typeof tag !== 'string' || tag.trim().length === 0) {
117
+ throw new Error('cache tag must be a non-empty string');
118
+ }
119
+ const indexKey = tagIndexKeyFor(tag);
120
+ const indexed = (await cacheBackend.get(indexKey)) ?? [];
121
+ if (!indexed.includes(fullKey))
122
+ indexed.push(fullKey);
123
+ await cacheBackend.set(indexKey, indexed, ttl);
124
+ }
125
+ },
126
+ async delete(key) {
127
+ requirePermission(PERMISSIONS.CACHE_WRITE);
128
+ await cacheBackend.del(cacheKeyFor(key));
129
+ },
130
+ async wrap(key, ttlSeconds, producer) {
131
+ requirePermission(PERMISSIONS.CACHE_WRITE);
132
+ const fullKey = cacheKeyFor(key);
133
+ const cached = await cacheBackend.get(fullKey);
134
+ if (cached !== null)
135
+ return cached;
136
+ const value = await producer();
137
+ await cacheBackend.set(fullKey, value, ttlSeconds);
138
+ return value;
139
+ },
140
+ async invalidateTags(tags) {
141
+ requirePermission(PERMISSIONS.CACHE_WRITE);
142
+ for (const tag of tags) {
143
+ const indexKey = tagIndexKeyFor(tag);
144
+ const indexed = (await cacheBackend.get(indexKey)) ?? [];
145
+ for (const key of indexed) {
146
+ await cacheBackend.del(key);
147
+ }
148
+ await cacheBackend.del(indexKey);
149
+ }
150
+ },
151
+ };
152
+ // ── api.jobs (Item 3): local handlers + `plugins` queue (repeat/one-shot) ──
153
+ const JOB_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_.-]{0,63}$/;
154
+ const MAX_SCHEDULED_JOBS = 10;
155
+ const jobHandlers = new Map();
156
+ const scheduledJobNames = new Set();
157
+ const jobsCtx = () => ({ pluginName: manifest.name, tenantId: getTenantId() });
158
+ const jobsApi = {
159
+ on(jobName, handler) {
160
+ if (!JOB_NAME_PATTERN.test(jobName)) {
161
+ throw new Error(`Invalid job name "${jobName}" (expected ${JOB_NAME_PATTERN})`);
162
+ }
163
+ if (typeof handler !== 'function') {
164
+ throw new Error(`Job handler for "${jobName}" must be a function`);
165
+ }
166
+ jobHandlers.set(jobName, handler);
167
+ },
168
+ async schedule(jobName, spec) {
169
+ requirePermission(PERMISSIONS.JOBS_SCHEDULE);
170
+ if (!JOB_NAME_PATTERN.test(jobName)) {
171
+ throw new Error(`Invalid job name "${jobName}" (expected ${JOB_NAME_PATTERN})`);
172
+ }
173
+ const hasEvery = typeof spec?.every === 'number' && spec.every > 0;
174
+ const hasCron = typeof spec?.cron === 'string' && spec.cron.trim().length > 0;
175
+ if (hasEvery === hasCron) {
176
+ throw new Error(`schedule("${jobName}") requires exactly one of: every | cron`);
177
+ }
178
+ // Per-plugin ceiling — only new schedules count (re-scheduling the same name is free)
179
+ if (!scheduledJobNames.has(jobName)) {
180
+ if (scheduledJobNames.size >= MAX_SCHEDULED_JOBS) {
181
+ throw new Error(`Job schedule limit reached (${MAX_SCHEDULED_JOBS} per plugin)`);
182
+ }
183
+ scheduledJobNames.add(jobName);
184
+ }
185
+ if (!deps.jobs)
186
+ return false; // queue unavailable: degradation, never throws
187
+ const scheduled = await deps.jobs.schedule(jobName, hasCron ? { cron: spec.cron } : { every: spec.every }, jobsCtx());
188
+ if (scheduled) {
189
+ auditPlugin('plugin.jobs.schedule', 'job', { jobName, spec: hasCron ? { cron: spec.cron } : { every: spec.every } });
190
+ }
191
+ return scheduled;
192
+ },
193
+ async cancel(jobName) {
194
+ requirePermission(PERMISSIONS.JOBS_SCHEDULE);
195
+ scheduledJobNames.delete(jobName);
196
+ if (!deps.jobs)
197
+ return false;
198
+ const cancelled = await deps.jobs.cancel(jobName, jobsCtx());
199
+ if (cancelled) {
200
+ auditPlugin('plugin.jobs.cancel', 'job', { jobName });
201
+ }
202
+ return cancelled;
203
+ },
204
+ async enqueue(jobName, payload = {}) {
205
+ requirePermission(PERMISSIONS.JOBS_SCHEDULE);
206
+ if (!JOB_NAME_PATTERN.test(jobName)) {
207
+ throw new Error(`Invalid job name "${jobName}" (expected ${JOB_NAME_PATTERN})`);
208
+ }
209
+ if (!deps.jobs)
210
+ return false;
211
+ const enqueued = await deps.jobs.enqueue(jobName, payload, jobsCtx());
212
+ if (enqueued) {
213
+ auditPlugin('plugin.jobs.enqueue', 'job', { jobName });
214
+ }
215
+ return enqueued;
216
+ },
217
+ };
218
+ // ── api.http (Item 4 + Item 16): anti-SSRF with the manifest allowlist ──
219
+ const httpApi = createHttpApi({
220
+ allowHosts: manifest.httpPolicy?.allowHosts,
221
+ requirePermission,
222
+ });
223
+ // ── api.roles (Item 6): tenant role management, anti-escalation + audit.
224
+ // Permission, tenant scope and backend presence are validated here; the
225
+ // escalation rules (reserved names, wildcards, platform operations) live in
226
+ // the core service — a single enforcement point.
227
+ function rolesBackend() {
228
+ if (!deps.roles) {
229
+ throw new Error('api.roles is not available (roles backend not wired)');
230
+ }
231
+ return deps.roles;
232
+ }
233
+ function requireTenantScopeForRoles() {
234
+ const tenantId = getTenantId();
235
+ if (!tenantId) {
236
+ throw new Error('api.roles requires a tenant scope (platform plugins cannot manage roles)');
237
+ }
238
+ return tenantId;
239
+ }
240
+ const rolesApi = {
241
+ async add(input) {
242
+ requirePermission(PERMISSIONS.ROLES_CREATE);
243
+ const tenantId = requireTenantScopeForRoles();
244
+ if (!input || typeof input.name !== 'string' || input.name.trim().length === 0) {
245
+ throw new Error('Role "name" is required');
246
+ }
247
+ return rolesBackend().add({
248
+ tenantId,
249
+ pluginName: manifest.name,
250
+ name: input.name,
251
+ slug: input.slug,
252
+ permissions: input.permissions,
253
+ });
254
+ },
255
+ async remove(slug) {
256
+ requirePermission(PERMISSIONS.ROLES_CREATE);
257
+ const tenantId = requireTenantScopeForRoles();
258
+ if (!slug || typeof slug !== 'string') {
259
+ throw new Error('Role "slug" is required');
260
+ }
261
+ return rolesBackend().remove({ tenantId, pluginName: manifest.name, slug });
262
+ },
263
+ async addPermission(slug, permission) {
264
+ requirePermission(PERMISSIONS.ROLES_CREATE);
265
+ const tenantId = requireTenantScopeForRoles();
266
+ if (!slug || typeof slug !== 'string') {
267
+ throw new Error('Role "slug" is required');
268
+ }
269
+ if (!permission || typeof permission !== 'string') {
270
+ throw new Error('Permission must be an "action:resource" string');
271
+ }
272
+ return rolesBackend().addPermission({ tenantId, pluginName: manifest.name, slug, permission });
273
+ },
274
+ };
275
+ // ── api.assets (Item 8): asset enqueue for the public site. Per-plugin
276
+ // URL dedupe (repeated calls are no-ops); the cross-plugin merge happens at
277
+ // render time (first enqueue wins). SRI is declared by the plugin
278
+ // (integrity + crossOrigin); src accepts http(s):// or root-relative (/...).
279
+ const ASSET_SRC_PATTERN = /^(https?:\/\/|\/(?!\/))[^\s"']+$/i;
280
+ const registeredAssets = [];
281
+ function validateAssetSrc(src) {
282
+ if (typeof src !== 'string' || !ASSET_SRC_PATTERN.test(src)) {
283
+ throw new Error(`Invalid asset src "${String(src)}" (expected http(s):// URL or root-relative /path)`);
284
+ }
285
+ return src;
286
+ }
287
+ const assetsApi = {
288
+ enqueueStyle(style) {
289
+ requirePermission(PERMISSIONS.ASSETS_ENQUEUE);
290
+ const src = validateAssetSrc(style?.src);
291
+ if (registeredAssets.some((asset) => asset.src === src))
292
+ return;
293
+ const entry = {
294
+ kind: 'style',
295
+ src,
296
+ version: typeof style?.version === 'string' && style.version ? style.version : undefined,
297
+ media: typeof style?.media === 'string' && style.media ? style.media : undefined,
298
+ integrity: typeof style?.integrity === 'string' && style.integrity ? style.integrity : undefined,
299
+ crossOrigin: typeof style?.crossOrigin === 'string' && style.crossOrigin ? style.crossOrigin : undefined,
300
+ pluginName: manifest.name,
301
+ };
302
+ registeredAssets.push(entry);
303
+ },
304
+ enqueueScript(script) {
305
+ requirePermission(PERMISSIONS.ASSETS_ENQUEUE);
306
+ const src = validateAssetSrc(script?.src);
307
+ if (registeredAssets.some((asset) => asset.src === src))
308
+ return;
309
+ const strategy = script?.strategy === 'defer' || script?.strategy === 'async' ? script.strategy : 'blocking';
310
+ const entry = {
311
+ kind: 'script',
312
+ src,
313
+ version: typeof script?.version === 'string' && script.version ? script.version : undefined,
314
+ strategy,
315
+ placement: script?.placement === 'footer' ? 'footer' : 'head',
316
+ integrity: typeof script?.integrity === 'string' && script.integrity ? script.integrity : undefined,
317
+ crossOrigin: typeof script?.crossOrigin === 'string' && script.crossOrigin ? script.crossOrigin : undefined,
318
+ pluginName: manifest.name,
319
+ };
320
+ registeredAssets.push(entry);
321
+ },
322
+ };
323
+ // ── api.i18n (Item 9): per-plugin server-side translations. Bundles are
324
+ // private to the plugin (namespacing is natural — each plugin owns its
325
+ // store); fallback chain locale → base language → 'en' → the key itself.
326
+ const i18nBundles = new Map();
327
+ let i18nDefaultLocale = 'en';
328
+ const i18nApi = {
329
+ load(locale, bundle) {
330
+ if (typeof locale !== 'string' || locale.trim().length === 0) {
331
+ throw new Error('i18n.load requires a locale');
332
+ }
333
+ if (!bundle || typeof bundle !== 'object' || Array.isArray(bundle)) {
334
+ throw new Error('i18n.load requires a flat { key: string } bundle');
335
+ }
336
+ const existing = i18nBundles.get(locale) ?? {};
337
+ for (const [key, value] of Object.entries(bundle)) {
338
+ if (typeof value !== 'string') {
339
+ throw new Error(`i18n bundle value for "${key}" must be a string`);
340
+ }
341
+ existing[key] = value;
342
+ }
343
+ i18nBundles.set(locale, existing);
344
+ },
345
+ translate(key, params, locale) {
346
+ if (typeof key !== 'string' || key.length === 0)
347
+ return String(key ?? '');
348
+ const requested = typeof locale === 'string' && locale ? locale : i18nDefaultLocale;
349
+ for (const candidate of i18nFallbackChain(requested)) {
350
+ const value = i18nBundles.get(candidate)?.[key];
351
+ if (typeof value === 'string')
352
+ return i18nInterpolate(value, params);
353
+ }
354
+ return key;
355
+ },
356
+ locale: () => i18nDefaultLocale,
357
+ setDefaultLocale(locale) {
358
+ if (typeof locale !== 'string' || locale.trim().length === 0) {
359
+ throw new Error('i18n.setDefaultLocale requires a locale');
360
+ }
361
+ i18nDefaultLocale = locale;
362
+ },
363
+ };
364
+ // ── api.health (Item 14): named per-plugin health checks, aggregated by
365
+ // GET /api/v1/health with a 2s budget per check. Duplicate names reject.
366
+ const healthChecks = new Map();
367
+ const healthApi = {
368
+ register(name, check) {
369
+ requirePermission(PERMISSIONS.HEALTH_REGISTER);
370
+ if (typeof name !== 'string' || name.trim().length === 0) {
371
+ throw new Error('health.register requires a non-empty name');
372
+ }
373
+ if (typeof check !== 'function') {
374
+ throw new Error('health.register requires a check function');
375
+ }
376
+ if (healthChecks.has(name)) {
377
+ throw new Error(`Health check "${name}" already registered`);
378
+ }
379
+ healthChecks.set(name, check);
380
+ },
381
+ };
382
+ // ── api.mail (Item 12): per-plugin templates + send through the core
383
+ // outbox. Templates support {param} (same interpolation as i18n). The
384
+ // backend is optional: absent → send returns false (queue down, like jobs).
385
+ const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
386
+ const mailTemplates = new Map();
387
+ function renderMailString(template, params) {
388
+ return i18nInterpolate(template, params);
389
+ }
390
+ const mailApi = {
391
+ registerTemplate(name, template) {
392
+ requirePermission(PERMISSIONS.MAIL_SEND);
393
+ if (typeof name !== 'string' || name.trim().length === 0) {
394
+ throw new Error('mail.registerTemplate requires a non-empty name');
395
+ }
396
+ if (!template || typeof template.subject !== 'string' || template.subject.trim().length === 0) {
397
+ throw new Error('mail template "subject" is required');
398
+ }
399
+ if (mailTemplates.has(name)) {
400
+ throw new Error(`Mail template "${name}" already registered`);
401
+ }
402
+ mailTemplates.set(name, {
403
+ subject: template.subject,
404
+ html: typeof template.html === 'string' ? template.html : undefined,
405
+ text: typeof template.text === 'string' ? template.text : undefined,
406
+ });
407
+ },
408
+ async send(input) {
409
+ requirePermission(PERMISSIONS.MAIL_SEND);
410
+ if (!input || typeof input.to !== 'string' || !EMAIL_PATTERN.test(input.to)) {
411
+ throw new Error(`Invalid recipient email "${String(input?.to)}"`);
412
+ }
413
+ let subject = input.subject;
414
+ let html = input.html;
415
+ let text = input.text;
416
+ if (input.template !== undefined) {
417
+ const template = mailTemplates.get(input.template);
418
+ if (!template) {
419
+ throw new Error(`Mail template "${input.template}" is not registered`);
420
+ }
421
+ subject = renderMailString(template.subject, input.params);
422
+ html = template.html !== undefined ? renderMailString(template.html, input.params) : html;
423
+ text = template.text !== undefined ? renderMailString(template.text, input.params) : text;
424
+ }
425
+ if (typeof subject !== 'string' || subject.trim().length === 0) {
426
+ throw new Error('Mail "subject" is required (or register/use a template)');
427
+ }
428
+ if (!html && !text) {
429
+ throw new Error('Mail requires html or text body');
430
+ }
431
+ if (!deps.mail)
432
+ return false;
433
+ return deps.mail.send({
434
+ tenantId: getTenantId(),
435
+ pluginName: manifest.name,
436
+ to: input.to,
437
+ subject,
438
+ html,
439
+ text,
440
+ template: input.template,
441
+ params: input.params,
442
+ });
443
+ },
444
+ };
445
+ // ── api.content (Item 22): typed query builder — declarative filters
446
+ // over allowlisted columns, fully parameterized (db:query).
447
+ const contentApi = {
448
+ query() {
449
+ requirePermission('db:query');
450
+ return new ContentQueryBuilder((query, params) => db.query(query, params));
451
+ },
452
+ };
22
453
  // Build the public API object
23
454
  const api = {
24
455
  registerHook(type, handler) {
@@ -74,7 +505,7 @@ export function createPluginApi(deps) {
74
505
  };
75
506
  const hookName = hookMap[type];
76
507
  if (!hookName) {
77
- console.warn(`[PluginAPI] Hook type "${type}" não mapeado — ignorado`);
508
+ console.warn(`[PluginAPI] Hook type "${type}" not mapped — ignored`);
78
509
  return;
79
510
  }
80
511
  hooks.addAction(hookName, async (...args) => {
@@ -91,10 +522,124 @@ export function createPluginApi(deps) {
91
522
  }
92
523
  }
93
524
  registeredRoutes.push(route);
525
+ auditPlugin('plugin.route.register', 'route', {
526
+ method: route.method,
527
+ path: route.path,
528
+ });
94
529
  },
95
530
  addContentField(field) {
96
531
  registeredFields.push(field);
97
532
  },
533
+ addFieldType(definition) {
534
+ if (!allowedPermissions.includes('field-types:register')) {
535
+ throw new Error('Plugin permission denied: field-types:register');
536
+ }
537
+ // Validate whether the type already exists (built-in or another plugin)
538
+ const existing = registeredFieldTypes.find(f => f.type === definition.type);
539
+ if (existing) {
540
+ throw new Error(`Field type "${definition.type}" already registered by plugin "${existing.pluginName || 'unknown'}"`);
541
+ }
542
+ const withPluginName = {
543
+ ...definition,
544
+ pluginName: manifest.name,
545
+ isPluginType: true,
546
+ };
547
+ registeredFieldTypes.push(withPluginName);
548
+ registerFieldTypes(registeredFieldTypes);
549
+ },
550
+ addPostType(declaration) {
551
+ if (!allowedPermissions.includes(PERMISSIONS.POST_TYPES_REGISTER)) {
552
+ throw new Error(`Plugin permission denied: ${PERMISSIONS.POST_TYPES_REGISTER}`);
553
+ }
554
+ if (!SLUG_PATTERN.test(declaration.key)) {
555
+ throw new Error(`Invalid post type key "${declaration.key}" (expected ${SLUG_PATTERN})`);
556
+ }
557
+ if (RESERVED_SLUGS.has(declaration.key)) {
558
+ throw new Error(`Post type key "${declaration.key}" is reserved`);
559
+ }
560
+ if (!declaration.label || typeof declaration.label !== 'string') {
561
+ throw new Error('Post type "label" is required');
562
+ }
563
+ const existing = registeredPostTypes.find((type) => type.key === declaration.key);
564
+ if (existing) {
565
+ throw new Error(`Post type "${declaration.key}" already registered by plugin "${existing.pluginName || 'unknown'}"`);
566
+ }
567
+ const withPluginName = { ...declaration, pluginName: manifest.name };
568
+ registeredPostTypes.push(withPluginName);
569
+ registerPostTypes?.([...registeredPostTypes]);
570
+ },
571
+ addTaxonomy(declaration) {
572
+ if (!allowedPermissions.includes(PERMISSIONS.TAXONOMIES_REGISTER)) {
573
+ throw new Error(`Plugin permission denied: ${PERMISSIONS.TAXONOMIES_REGISTER}`);
574
+ }
575
+ if (!SLUG_PATTERN.test(declaration.key)) {
576
+ throw new Error(`Invalid taxonomy key "${declaration.key}" (expected ${SLUG_PATTERN})`);
577
+ }
578
+ if (RESERVED_SLUGS.has(declaration.key)) {
579
+ throw new Error(`Taxonomy key "${declaration.key}" is reserved`);
580
+ }
581
+ if (!declaration.label || typeof declaration.label !== 'string') {
582
+ throw new Error('Taxonomy "label" is required');
583
+ }
584
+ if (!Array.isArray(declaration.postTypes) || declaration.postTypes.length === 0) {
585
+ throw new Error(`Taxonomy "${declaration.key}" requires a non-empty postTypes[]`);
586
+ }
587
+ const existing = registeredTaxonomies.find((taxonomy) => taxonomy.key === declaration.key);
588
+ if (existing) {
589
+ throw new Error(`Taxonomy "${declaration.key}" already registered by plugin "${existing.pluginName || 'unknown'}"`);
590
+ }
591
+ const withPluginName = { ...declaration, pluginName: manifest.name };
592
+ registeredTaxonomies.push(withPluginName);
593
+ registerTaxonomies?.([...registeredTaxonomies]);
594
+ },
595
+ registerBlock(block) {
596
+ if (!allowedPermissions.includes(PERMISSIONS.BLOCKS_REGISTER)) {
597
+ throw new Error(`Plugin permission denied: ${PERMISSIONS.BLOCKS_REGISTER}`);
598
+ }
599
+ if (!block?.type || typeof block.type !== 'string') {
600
+ throw new Error('Block "type" is required');
601
+ }
602
+ if (!block.label || typeof block.label !== 'string') {
603
+ throw new Error('Block "label" is required');
604
+ }
605
+ if (!block.adminComponentPath || typeof block.adminComponentPath !== 'string') {
606
+ throw new Error('Block "adminComponentPath" is required');
607
+ }
608
+ const existing = registeredBlocks.find((registered) => registered.type === block.type);
609
+ if (existing) {
610
+ throw new Error(`Block type "${block.type}" already registered by plugin "${existing.pluginName || 'unknown'}"`);
611
+ }
612
+ registeredBlocks.push({ ...block, pluginName: manifest.name });
613
+ },
614
+ registerPattern(pattern) {
615
+ if (!allowedPermissions.includes(PERMISSIONS.PATTERNS_REGISTER)) {
616
+ throw new Error(`Plugin permission denied: ${PERMISSIONS.PATTERNS_REGISTER}`);
617
+ }
618
+ if (!pattern?.name || typeof pattern.name !== 'string') {
619
+ throw new Error('Pattern "name" is required');
620
+ }
621
+ if (!pattern.label || typeof pattern.label !== 'string') {
622
+ throw new Error('Pattern "label" is required');
623
+ }
624
+ if (!pattern.content || typeof pattern.content !== 'string') {
625
+ throw new Error('Pattern "content" is required');
626
+ }
627
+ const existing = registeredPatterns.find((registered) => registered.name === pattern.name);
628
+ if (existing) {
629
+ throw new Error(`Pattern name "${pattern.name}" already registered by plugin "${existing.pluginName || 'unknown'}"`);
630
+ }
631
+ registeredPatterns.push({ ...pattern, pluginName: manifest.name });
632
+ },
633
+ cache: cacheApi,
634
+ jobs: jobsApi,
635
+ http: httpApi,
636
+ admin: adminApi,
637
+ roles: rolesApi,
638
+ assets: assetsApi,
639
+ i18n: i18nApi,
640
+ health: healthApi,
641
+ mail: mailApi,
642
+ content: contentApi,
98
643
  async getSetting(key, group) {
99
644
  if (!allowedPermissions.includes('settings:read')) {
100
645
  throw new Error('Plugin permission denied: settings:read');
@@ -129,6 +674,14 @@ export function createPluginApi(deps) {
129
674
  },
130
675
  async query(sql, params) {
131
676
  checkDbPermission();
677
+ // Item 18: only MUTATIONS hit the audit log (mass SELECTs would flood
678
+ // it; reads stay in the database query logs).
679
+ if (MUTATION_PATTERN.test(sql)) {
680
+ auditPlugin('plugin.db.query', 'db', {
681
+ statement: sql.slice(0, 500),
682
+ paramsCount: Array.isArray(params) ? params.length : 0,
683
+ });
684
+ }
132
685
  return db.query(sql, params);
133
686
  },
134
687
  async emit(eventType, payload) {
@@ -168,6 +721,15 @@ export function createPluginApi(deps) {
168
721
  internal: {
169
722
  getRoutes: () => registeredRoutes,
170
723
  getFields: () => registeredFields,
724
+ getFieldTypes: () => registeredFieldTypes,
725
+ getPostTypes: () => registeredPostTypes,
726
+ getTaxonomies: () => registeredTaxonomies,
727
+ getJobHandlers: () => jobHandlers,
728
+ getAdminState: () => adminApi.state,
729
+ getBlocks: () => registeredBlocks,
730
+ getPatterns: () => registeredPatterns,
731
+ getEnqueuedAssets: () => registeredAssets,
732
+ getHealthChecks: () => [...healthChecks.entries()].map(([name, check]) => ({ name, check })),
171
733
  },
172
734
  };
173
735
  }