@oktis-works/plugin-runtime 0.6.1 → 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 +231 -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 +1 -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 +184 -39
  32. package/dist/plugin-api.d.ts.map +1 -1
  33. package/dist/plugin-api.js +553 -11
  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 +6 -5
@@ -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, registerFieldTypes } = 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');
@@ -21,6 +52,404 @@ export function createPluginApi(deps) {
21
52
  const registeredFields = [];
22
53
  // Runtime type includes pluginName and isPluginType added during registration
23
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
+ };
24
453
  // Build the public API object
25
454
  const api = {
26
455
  registerHook(type, handler) {
@@ -76,7 +505,7 @@ export function createPluginApi(deps) {
76
505
  };
77
506
  const hookName = hookMap[type];
78
507
  if (!hookName) {
79
- console.warn(`[PluginAPI] Hook type "${type}" não mapeado — ignorado`);
508
+ console.warn(`[PluginAPI] Hook type "${type}" not mapped — ignored`);
80
509
  return;
81
510
  }
82
511
  hooks.addAction(hookName, async (...args) => {
@@ -93,6 +522,10 @@ export function createPluginApi(deps) {
93
522
  }
94
523
  }
95
524
  registeredRoutes.push(route);
525
+ auditPlugin('plugin.route.register', 'route', {
526
+ method: route.method,
527
+ path: route.path,
528
+ });
96
529
  },
97
530
  addContentField(field) {
98
531
  registeredFields.push(field);
@@ -101,7 +534,7 @@ export function createPluginApi(deps) {
101
534
  if (!allowedPermissions.includes('field-types:register')) {
102
535
  throw new Error('Plugin permission denied: field-types:register');
103
536
  }
104
- // Validar se o tipo já existe (built-in ou outro plugin)
537
+ // Validate whether the type already exists (built-in or another plugin)
105
538
  const existing = registeredFieldTypes.find(f => f.type === definition.type);
106
539
  if (existing) {
107
540
  throw new Error(`Field type "${definition.type}" already registered by plugin "${existing.pluginName || 'unknown'}"`);
@@ -114,6 +547,99 @@ export function createPluginApi(deps) {
114
547
  registeredFieldTypes.push(withPluginName);
115
548
  registerFieldTypes(registeredFieldTypes);
116
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,
117
643
  async getSetting(key, group) {
118
644
  if (!allowedPermissions.includes('settings:read')) {
119
645
  throw new Error('Plugin permission denied: settings:read');
@@ -148,6 +674,14 @@ export function createPluginApi(deps) {
148
674
  },
149
675
  async query(sql, params) {
150
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
+ }
151
685
  return db.query(sql, params);
152
686
  },
153
687
  async emit(eventType, payload) {
@@ -188,6 +722,14 @@ export function createPluginApi(deps) {
188
722
  getRoutes: () => registeredRoutes,
189
723
  getFields: () => registeredFields,
190
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 })),
191
733
  },
192
734
  };
193
735
  }