@wordrhyme/plugin 0.1.0-alpha.10

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 (57) hide show
  1. package/dist/admin/index.d.ts +19 -0
  2. package/dist/admin/index.js +42 -0
  3. package/dist/admin/index.js.map +1 -0
  4. package/dist/artifact.d.ts +17 -0
  5. package/dist/artifact.js +97 -0
  6. package/dist/artifact.js.map +1 -0
  7. package/dist/chunk-3IM3FPTJ.js +1470 -0
  8. package/dist/chunk-3IM3FPTJ.js.map +1 -0
  9. package/dist/chunk-6GDCFR67.js +218 -0
  10. package/dist/chunk-6GDCFR67.js.map +1 -0
  11. package/dist/chunk-7EM22QYB.js +333 -0
  12. package/dist/chunk-7EM22QYB.js.map +1 -0
  13. package/dist/chunk-BI7E5CVM.js +26 -0
  14. package/dist/chunk-BI7E5CVM.js.map +1 -0
  15. package/dist/chunk-BVOTSKM2.js +254 -0
  16. package/dist/chunk-BVOTSKM2.js.map +1 -0
  17. package/dist/chunk-DY44Q4CK.js +188 -0
  18. package/dist/chunk-DY44Q4CK.js.map +1 -0
  19. package/dist/chunk-MZOLSLJ7.js +65 -0
  20. package/dist/chunk-MZOLSLJ7.js.map +1 -0
  21. package/dist/chunk-O4AYK3YP.js +156 -0
  22. package/dist/chunk-O4AYK3YP.js.map +1 -0
  23. package/dist/chunk-UGMYO6AU.js +37 -0
  24. package/dist/chunk-UGMYO6AU.js.map +1 -0
  25. package/dist/client-poND5ovI.d.ts +679 -0
  26. package/dist/client.d.ts +9 -0
  27. package/dist/client.js +68 -0
  28. package/dist/client.js.map +1 -0
  29. package/dist/dev-utils.d.ts +105 -0
  30. package/dist/dev-utils.js +35 -0
  31. package/dist/dev-utils.js.map +1 -0
  32. package/dist/entity-extensions-CnhKoT4k.d.ts +56 -0
  33. package/dist/globalization.d.ts +85 -0
  34. package/dist/globalization.js +53 -0
  35. package/dist/globalization.js.map +1 -0
  36. package/dist/index.d.ts +724 -0
  37. package/dist/index.js +931 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/locale.d.ts +15 -0
  40. package/dist/locale.js +13 -0
  41. package/dist/locale.js.map +1 -0
  42. package/dist/manifest-CTFX-h0w.d.ts +2053 -0
  43. package/dist/react.d.ts +227 -0
  44. package/dist/react.js +226 -0
  45. package/dist/react.js.map +1 -0
  46. package/dist/release-BDJeO54k.d.ts +230 -0
  47. package/dist/server.d.ts +115 -0
  48. package/dist/server.js +194 -0
  49. package/dist/server.js.map +1 -0
  50. package/dist/time.d.ts +34 -0
  51. package/dist/time.js +31 -0
  52. package/dist/time.js.map +1 -0
  53. package/dist/trpc.d.ts +44 -0
  54. package/dist/trpc.js +11 -0
  55. package/dist/trpc.js.map +1 -0
  56. package/dist/types-BJo3_91V.d.ts +1997 -0
  57. package/package.json +92 -0
@@ -0,0 +1,1997 @@
1
+ import { GlobalizationState } from './globalization.js';
2
+ import { R as RegistryReleaseEnvelope, a as RegistrySignature, b as RegistryCatalogPageEnvelope } from './release-BDJeO54k.js';
3
+ import { DateRangeResolver } from './time.js';
4
+
5
+ /**
6
+ * Plugin Context - Injected into plugin handlers
7
+ *
8
+ * All plugin code receives this context, which provides:
9
+ * - Identity (pluginId, organizationId, userId)
10
+ * - Capabilities (logger, db, permissions, queue, notifications, settings, media, storage)
11
+ * - Observability (metrics, trace)
12
+ */
13
+
14
+ interface PluginContext {
15
+ /** Plugin ID from manifest */
16
+ pluginId: string;
17
+ /** Host-resolved uninstall retention choice; read-only lifecycle input. */
18
+ readonly uninstallRetention?: "retain" | "archive" | "delete" | undefined;
19
+ /** Current organization ID (from request context) */
20
+ organizationId?: string | undefined;
21
+ /** Original organization ID before any infrastructure policy context swap */
22
+ originalOrganizationId?: string | undefined;
23
+ /** Current user ID (from request context) */
24
+ userId?: string | undefined;
25
+ /** Current user profile snapshot from request context */
26
+ user?: {
27
+ id: string;
28
+ name?: string;
29
+ email?: string;
30
+ } | undefined;
31
+ /** Request/correlation ID from the host runtime */
32
+ requestId?: string | undefined;
33
+ /** Current user's primary role and expanded role set */
34
+ userRole?: string | undefined;
35
+ userRoles?: string[] | undefined;
36
+ /** Current team context for team-level permissions */
37
+ currentTeamId?: string | undefined;
38
+ /** Locale/timezone resolved by the host runtime */
39
+ locale?: string | undefined;
40
+ timezone?: string | undefined;
41
+ /** Client-reported timezone; business logic must not treat it as authoritative. */
42
+ clientTimeZone?: string | undefined;
43
+ /** Host-provided calendar-date resolver for shared query infrastructure. */
44
+ resolveDateRange?: DateRangeResolver | undefined;
45
+ /** Host-provided actor metadata; runtime plugin contexts resolve to `plugin`. */
46
+ actorType?: "plugin" | undefined;
47
+ apiTokenId?: string | undefined;
48
+ apiTokenScopes?: string[] | undefined;
49
+ isSystemContext?: false | undefined;
50
+ principal?: {
51
+ kind: "plugin";
52
+ id: string;
53
+ pluginId: string;
54
+ } | undefined;
55
+ invoker?: string | undefined;
56
+ /** Scoped logger */
57
+ logger: PluginLogger;
58
+ /**
59
+ * Drizzle-compatible ScopedDb bound to the plugin's private table prefix.
60
+ * Automatically enforces LBAC, tenant filtering, auditing, and plugin table isolation.
61
+ */
62
+ db: PluginScopedDb;
63
+ /** Host-only Marketplace execution boundary for platform reads and Publisher callbacks. */
64
+ marketplaceOrganizationExecution?: MarketplaceOrganizationExecutionV1 | undefined;
65
+ /** Authenticated upload actor supplied by the Host; never derived from request payloads. */
66
+ marketplacePublishActor?: MarketplacePublishActor | undefined;
67
+ /** Host-only Registry signing boundary. The private key never enters plugin settings or storage. */
68
+ marketplaceRegistrySigner?: MarketplaceRegistrySigningCapability | undefined;
69
+ /** Host-configured public Marketplace origin; null means production configuration is missing. */
70
+ marketplaceRegistryBaseUrl?: string | null | undefined;
71
+ /** Host-mediated Core organization creation for explicitly trusted plugins. */
72
+ organizationProvisioning?: PluginOrganizationProvisioningCapability | undefined;
73
+ /** Host-mediated exact membership lookup within the current organization. */
74
+ organizationMembers?: PluginOrganizationMembersCapability | undefined;
75
+ /**
76
+ * Shared database transaction for synchronous cross-plugin pipe calls.
77
+ *
78
+ * When present, plugin code may use this transaction to participate in the
79
+ * caller's outer SQL transaction instead of opening an independent one.
80
+ */
81
+ tx?: any;
82
+ /** Permission capability */
83
+ permissions: PluginPermissionCapability;
84
+ /** Public plugin API caller alias over the host's pluginApis route tree */
85
+ plugins?: PluginApisCapability | undefined;
86
+ /** Queue capability (for async job processing) */
87
+ queue?: PluginQueueCapability | undefined;
88
+ /** Notification capability (for sending notifications) */
89
+ notifications?: PluginNotificationCapability | undefined;
90
+ /** Settings capability (for plugin configuration) */
91
+ settings: PluginSettingsCapability;
92
+ /** Currency capability (for effective organization currency/rate access) */
93
+ currency?: PluginCurrencyCapability | undefined;
94
+ /** Media capability (for unified file and asset management) */
95
+ media?: PluginMediaCapability | undefined;
96
+ /** Storage capability (for registering custom storage providers) */
97
+ storage?: PluginStorageCapability | undefined;
98
+ /** Opaque plugin artifact storage for explicitly approved first-party workflows. */
99
+ artifacts?: PluginArtifactCapability | undefined;
100
+ /** Metrics capability (for recording usage metrics) */
101
+ metrics?: PluginMetricsCapability | undefined;
102
+ /** Trace capability (for accessing trace context) */
103
+ trace?: PluginTraceCapability | undefined;
104
+ /** Hook capability (for registering hook handlers) */
105
+ hooks?: PluginHookCapability | undefined;
106
+ /** Usage capability (for explicit billing consumption in dynamic scenarios) */
107
+ usage?: PluginUsageCapability | undefined;
108
+ /** External authorization capability for tenant platform/API connections */
109
+ eAuth?: PluginEAuthCapability | undefined;
110
+ /** Entity extension capability (Core-mediated extension value persistence) */
111
+ entityExtensions?: PluginEntityExtensionCapability | undefined;
112
+ /** Generic AutoCrud extension provider injected by the host runtime. */
113
+ crudExtensions?: PluginCrudExtensionsCapability | undefined;
114
+ /** Public web surface capability injected for plugin-owned web route handlers. */
115
+ web?: PluginWebCapability | undefined;
116
+ /** Agent runtime capability; injected only for plugins declaring `capabilities.agent.runtime`. */
117
+ agent?: PluginAgentCapability | undefined;
118
+ /** Governed action invoker; injected only for plugins declaring `capabilities.agent.invoker`. */
119
+ actions?: PluginActionInvokerCapability | undefined;
120
+ /** Governed AI generation; available to plugins and resolved through the official Runtime. */
121
+ ai?: PluginAiCapability | undefined;
122
+ /** Host registration boundary; injected only for the declared official AI Runtime provider. */
123
+ aiRuntime?: PluginAiRuntimeCapability | undefined;
124
+ }
125
+ /**
126
+ * Public SDK shape for the Host-provided Drizzle-compatible database.
127
+ *
128
+ * The concrete type deliberately remains structural so plugin packages do not
129
+ * depend on Server internals. Runtime enforcement is provided by ScopedDb.
130
+ */
131
+ interface PluginScopedDb {
132
+ readonly query: any;
133
+ /** @deprecated Prefer the v2 object-style `query` API. */
134
+ readonly _query: any;
135
+ select(...args: any[]): any;
136
+ selectDistinct(...args: any[]): any;
137
+ selectDistinctOn(...args: any[]): any;
138
+ insert(table: any): any;
139
+ update(table: any): any;
140
+ /**
141
+ * Replace the dynamic visibility tags cached on matching rows.
142
+ *
143
+ * Use this after the plugin recalculates who may read its own records. The
144
+ * Host still enforces the current organization, existing row visibility,
145
+ * tag syntax and audit logging. An explicit `where` is required, and this
146
+ * cannot change row ownership or deny tags.
147
+ */
148
+ setAclTags(table: any, input: {
149
+ tags: readonly string[];
150
+ where: any;
151
+ }): Promise<unknown>;
152
+ delete(table: any, options?: {
153
+ softDelete?: false;
154
+ }): any;
155
+ $count(source: any, filters?: any): PromiseLike<number> & {
156
+ execute(placeholderValues?: Record<string, unknown>): Promise<number>;
157
+ };
158
+ transaction<T>(callback: (tx: PluginScopedDb) => Promise<T>, options?: unknown): Promise<T>;
159
+ forOrganization<T>(organizationId: string, callback: (db: PluginScopedDb) => Promise<T> | T): Promise<T>;
160
+ }
161
+ interface ReadonlyPluginScopedDb {
162
+ readonly query: any;
163
+ /** @deprecated Prefer the v2 object-style `query` API. */
164
+ readonly _query: any;
165
+ select(...args: any[]): any;
166
+ selectDistinct(...args: any[]): any;
167
+ selectDistinctOn(...args: any[]): any;
168
+ $count(source: any, filters?: any): PromiseLike<number> & {
169
+ execute(placeholderValues?: Record<string, unknown>): Promise<number>;
170
+ };
171
+ }
172
+ type MarketplacePlatformReadAction = "route" | "review-list" | "attestation-target" | "catalog";
173
+ type MarketplacePublisherAction = "publish" | "review-command" | "release-attest" | "profile-manage";
174
+ type MarketplaceExecutionErrorCode = "MARKETPLACE_EXECUTION_ACTION_DENIED" | "MARKETPLACE_PUBLISHER_UNAVAILABLE";
175
+ type MarketplaceExecutionFailureCode = MarketplaceExecutionErrorCode | "PLUGIN_DB_SCOPE_EXPIRED";
176
+ declare const MARKETPLACE_PUBLISH_AUTH_METHODS: readonly ["portal-session", "scoped-api-key"];
177
+ type MarketplacePublishAuthMethod = (typeof MARKETPLACE_PUBLISH_AUTH_METHODS)[number];
178
+ interface MarketplacePublishActor {
179
+ actorId: string;
180
+ authenticationMethod: MarketplacePublishAuthMethod;
181
+ authenticatedAt: string;
182
+ credentialId?: string | undefined;
183
+ }
184
+ interface MarketplaceRegistrySigningCapability {
185
+ /** Serialize Catalog generations and Release projection changes on the Registry database clock. */
186
+ withCatalogGeneration<T>(run: (generatedAt: string) => Promise<T>): Promise<T>;
187
+ sign(targetId: string, envelope: RegistryReleaseEnvelope): Promise<RegistrySignature>;
188
+ signCatalog(envelope: RegistryCatalogPageEnvelope): Promise<RegistrySignature>;
189
+ }
190
+ interface MarketplaceAttestationTargetV1 {
191
+ organizationId: string;
192
+ targetId: string;
193
+ envelopeSha256: string;
194
+ }
195
+ declare const publisherCandidateBrand: unique symbol;
196
+ interface OpaquePublisherCandidateV1 {
197
+ readonly [publisherCandidateBrand]: true;
198
+ }
199
+ interface MarketplaceOrganizationExecutionV1 {
200
+ withPlatformRead(ctx: PluginContext, action: "route", run: (db: ReadonlyPluginScopedDb) => Promise<string | undefined>): Promise<OpaquePublisherCandidateV1 | undefined>;
201
+ withPlatformRead(ctx: PluginContext, action: "review-list", run: (db: ReadonlyPluginScopedDb) => Promise<string | undefined>): Promise<OpaquePublisherCandidateV1 | undefined>;
202
+ withPlatformRead(ctx: PluginContext, action: "attestation-target", run: (db: ReadonlyPluginScopedDb) => Promise<MarketplaceAttestationTargetV1 | undefined>): Promise<OpaquePublisherCandidateV1 | undefined>;
203
+ withPlatformRead<T>(ctx: PluginContext, action: Exclude<MarketplacePlatformReadAction, "route" | "attestation-target">, run: (db: ReadonlyPluginScopedDb) => Promise<T>): Promise<T>;
204
+ withPublisher<T>(ctx: PluginContext, binding: "current" | OpaquePublisherCandidateV1, action: MarketplacePublisherAction, run: (db: PluginScopedDb) => Promise<T>): Promise<T>;
205
+ }
206
+ interface PluginOrganizationProvisioningCapability {
207
+ provision(input: {
208
+ name: string;
209
+ idempotencyKey: string;
210
+ transaction: PluginScopedDb;
211
+ metadata?: Record<string, string | number | boolean | null> | undefined;
212
+ }): Promise<{
213
+ id: string;
214
+ name: string;
215
+ slug: string;
216
+ status: "created" | "existing";
217
+ }>;
218
+ }
219
+ interface PluginOrganizationMembersCapability {
220
+ find(input: {
221
+ userId: string;
222
+ roleSlugs?: readonly string[] | undefined;
223
+ }): Promise<{
224
+ id: string;
225
+ userId: string;
226
+ role: string;
227
+ status: string;
228
+ user: {
229
+ id: string;
230
+ banned: boolean | null;
231
+ };
232
+ } | null>;
233
+ }
234
+ /**
235
+ * Framework-neutral request envelope for plugin-owned public web routes.
236
+ *
237
+ * This contract intentionally avoids Next.js, Pages Router, App Router, RSC,
238
+ * TanStack Router, or any other host-specific request type. Host adapters
239
+ * translate their native request shape into this envelope before invoking a
240
+ * plugin web handler.
241
+ */
242
+ interface WebPluginRouteRequest {
243
+ url: string;
244
+ method: string;
245
+ headers: Record<string, string>;
246
+ cookies: Record<string, string>;
247
+ path: string;
248
+ /** Stable manifest route identity selected by the Host. */
249
+ routeId?: string | undefined;
250
+ /** Declared route path; differs from `path` when the tenant root is an alias. */
251
+ matchedPath?: string | undefined;
252
+ query: Record<string, string | string[]>;
253
+ organizationId: string;
254
+ locale?: string | undefined;
255
+ direction?: GlobalizationState["direction"] | undefined;
256
+ currency?: string | undefined;
257
+ timezone?: string | undefined;
258
+ globalization?: GlobalizationState | undefined;
259
+ /** Host-bound translator for common + the current route owner namespace. */
260
+ t?: NonNullable<GlobalizationState["t"]> | undefined;
261
+ tenant?: WebPluginTenantInfo | undefined;
262
+ site?: WebPluginSiteInfo | undefined;
263
+ /**
264
+ * Host-resolved, read-only presentation snapshot for this request.
265
+ * Route owners may use only coarse presentation state (for example, to
266
+ * avoid rendering duplicate page chrome); they must not branch on a
267
+ * concrete theme implementation or treat this data as authorization.
268
+ */
269
+ presentation?: WebResolvedSitePresentation | undefined;
270
+ renderSlot?: WebSlotRenderer | undefined;
271
+ }
272
+ interface WebResolvedThemeAsset {
273
+ kind: "stylesheet" | "script" | "font" | "image" | "other";
274
+ href: string;
275
+ integrity?: string | undefined;
276
+ media?: string | undefined;
277
+ preload?: boolean | undefined;
278
+ }
279
+ interface WebPresentationAdapterClientDescriptor {
280
+ pluginId: string;
281
+ component: string;
282
+ remoteEntry: string;
283
+ devRemoteEntry?: string | undefined;
284
+ moduleName?: string | undefined;
285
+ expose?: string | undefined;
286
+ }
287
+ interface WebResolvedPresentationAdapter {
288
+ ownerPluginId: string;
289
+ surfaceId: string;
290
+ surfaceVersion: string;
291
+ source: "theme" | "plugin" | "owner";
292
+ providerPluginId: string;
293
+ providerPluginVersion: string;
294
+ serverRenderer?: string | undefined;
295
+ client?: WebPresentationAdapterClientDescriptor | undefined;
296
+ settings: Readonly<Record<string, WebJsonValue>>;
297
+ }
298
+ interface WebResolvedSitePresentation {
299
+ pluginId: string | null;
300
+ pluginVersion: string | null;
301
+ revisionId: string | null;
302
+ mode: "published" | "preview" | "fallback" | "safe-mode";
303
+ head?: WebPluginHead | undefined;
304
+ assets: readonly WebResolvedThemeAsset[];
305
+ tokens: Readonly<Record<string, string>>;
306
+ settings: Readonly<Record<string, WebJsonValue>>;
307
+ adapters: readonly WebResolvedPresentationAdapter[];
308
+ }
309
+ type WebJsonPrimitive = string | number | boolean | null;
310
+ type WebJsonValue = WebJsonPrimitive | WebJsonValue[] | {
311
+ [key: string]: WebJsonValue;
312
+ };
313
+ type WebSerializableGlobalizationState = Omit<GlobalizationState, "t" | "p" | "changeLocale" | "changeCurrency">;
314
+ interface WebThemeShellRouteModel {
315
+ status: number;
316
+ routeId: string;
317
+ publicPath: string;
318
+ matchedPath?: string | undefined;
319
+ head?: WebPluginHead | undefined;
320
+ html: string;
321
+ initialData?: WebJsonValue | undefined;
322
+ clientEntries: readonly string[];
323
+ slotExtensions: readonly WebSlotRemoteExtension[];
324
+ }
325
+ /** Serializable, framework-neutral input passed to a theme-owned Site Shell. */
326
+ interface WebThemeShellDocumentModel {
327
+ version: 1;
328
+ route: WebThemeShellRouteModel;
329
+ tenant: WebPluginTenantInfo;
330
+ site: WebPluginSiteInfo;
331
+ globalization: WebSerializableGlobalizationState;
332
+ presentation: WebResolvedSitePresentation;
333
+ }
334
+ /**
335
+ * The Host inserts the already-authorized route content between these shell
336
+ * boundaries, so a broken or incomplete theme renderer cannot silently drop it.
337
+ */
338
+ interface WebThemeShellRenderResult {
339
+ startHtml: string;
340
+ endHtml: string;
341
+ head?: WebPluginHead | undefined;
342
+ initialData?: WebJsonValue | undefined;
343
+ }
344
+ type WebThemeShellRenderer = (document: WebThemeShellDocumentModel) => WebThemeShellRenderResult | Promise<WebThemeShellRenderResult>;
345
+ interface WebThemeShellClientDescriptor {
346
+ pluginId: string;
347
+ component: string;
348
+ remoteEntry: string;
349
+ devRemoteEntry?: string | undefined;
350
+ moduleName?: string | undefined;
351
+ expose?: string | undefined;
352
+ }
353
+ interface WebResolvedSiteShell {
354
+ source: "theme" | "host";
355
+ pluginId: string | null;
356
+ document: WebThemeShellDocumentModel;
357
+ initialData?: WebJsonValue | undefined;
358
+ client?: WebThemeShellClientDescriptor | undefined;
359
+ diagnostic?: {
360
+ code: string;
361
+ message: string;
362
+ } | undefined;
363
+ }
364
+ interface WebSlotRenderRequest {
365
+ slot: string;
366
+ props?: Record<string, unknown> | undefined;
367
+ targetPluginId?: string | undefined;
368
+ routeId?: string | undefined;
369
+ }
370
+ interface WebSlotRenderOptions {
371
+ slot: string;
372
+ props?: Record<string, unknown> | undefined;
373
+ ownerPluginId?: string | undefined;
374
+ routeId?: string | undefined;
375
+ }
376
+ interface WebSlotExtensionQuery {
377
+ id: string;
378
+ procedure: string;
379
+ inputFrom?: "slotProps" | "static" | undefined;
380
+ staticInput?: Record<string, unknown> | undefined;
381
+ }
382
+ interface WebSlotQueryResult {
383
+ id: string;
384
+ procedure: string;
385
+ data?: unknown;
386
+ error?: string | undefined;
387
+ }
388
+ interface WebSlotRemoteExtension {
389
+ id: string;
390
+ pluginId: string;
391
+ label?: string | undefined;
392
+ component: string;
393
+ slot: string;
394
+ targetPluginId: string;
395
+ props: Record<string, unknown>;
396
+ remoteEntry: string;
397
+ devRemoteEntry?: string | undefined;
398
+ moduleName?: string | undefined;
399
+ expose?: string | undefined;
400
+ order?: number | undefined;
401
+ queries?: WebSlotExtensionQuery[] | undefined;
402
+ queryResults?: WebSlotQueryResult[] | undefined;
403
+ }
404
+ type WebSlotRenderMode = "island" | "react";
405
+ interface WebSlotRenderResult {
406
+ html: string;
407
+ renderMode?: WebSlotRenderMode | undefined;
408
+ extensions?: WebSlotRemoteExtension[] | undefined;
409
+ head?: WebPluginHead | undefined;
410
+ initialData?: Record<string, unknown> | undefined;
411
+ clientEntries?: string[] | undefined;
412
+ }
413
+ type WebSlotRenderer = (request: WebSlotRenderRequest) => WebSlotRenderResult | Promise<WebSlotRenderResult>;
414
+ interface PluginWebCapability {
415
+ renderSlot(options: WebSlotRenderOptions): WebSlotRenderResult | Promise<WebSlotRenderResult>;
416
+ }
417
+ interface WebPluginTenantInfo {
418
+ organizationId: string;
419
+ name: string;
420
+ slug?: string | undefined;
421
+ logo?: string | null | undefined;
422
+ }
423
+ interface WebPluginSiteInfo {
424
+ mode: "custom-domain" | "platform-subdomain" | "platform-path" | "internal-override";
425
+ basePath: string;
426
+ publicOrigin?: string | undefined;
427
+ host?: string | undefined;
428
+ }
429
+ interface WebPluginHeadLink {
430
+ rel: string;
431
+ href: string;
432
+ as?: string | undefined;
433
+ type?: string | undefined;
434
+ }
435
+ interface WebPluginHead {
436
+ title?: string | undefined;
437
+ description?: string | undefined;
438
+ meta?: Record<string, string> | undefined;
439
+ links?: WebPluginHeadLink[] | undefined;
440
+ }
441
+ type WebPluginDocumentMode = "document" | "content";
442
+ interface WebPluginPresentationSurfaceResult {
443
+ id: string;
444
+ model: WebJsonValue;
445
+ }
446
+ /**
447
+ * Framework-neutral SSR result returned by a plugin web handler.
448
+ *
449
+ * Redirects are represented as a 3xx status plus a `location` header so every
450
+ * host adapter can map them into its own redirect primitive.
451
+ */
452
+ interface WebPluginRouteResult {
453
+ status: number;
454
+ /**
455
+ * `document` preserves a legacy route-owned page shell. `content` allows
456
+ * the active tenant theme to compose the route inside its Site Shell.
457
+ * Omitted values retain the legacy `document` behavior.
458
+ */
459
+ documentMode?: WebPluginDocumentMode | undefined;
460
+ headers?: Record<string, string> | undefined;
461
+ head?: WebPluginHead | undefined;
462
+ html?: string | undefined;
463
+ initialData?: unknown;
464
+ clientEntry?: string | undefined;
465
+ clientEntries?: string[] | undefined;
466
+ slotExtensions?: WebSlotRemoteExtension[] | undefined;
467
+ routeId?: string | undefined;
468
+ globalization?: GlobalizationState | undefined;
469
+ site?: WebPluginSiteInfo | undefined;
470
+ presentation?: WebResolvedSitePresentation | undefined;
471
+ shell?: WebResolvedSiteShell | undefined;
472
+ /**
473
+ * Authorized, JSON-only model exposed by the route owner to the selected
474
+ * presentation adapter. The Host resolves the contract version and action
475
+ * metadata from the owner's manifest instead of trusting route output.
476
+ */
477
+ presentationSurface?: WebPluginPresentationSurfaceResult | undefined;
478
+ /** Host-internal normalization flag set after a full-page adapter applies. */
479
+ suppressDefaultClient?: boolean | undefined;
480
+ }
481
+ type WebPluginRouteHandler<TContext extends PluginContext = PluginContext> = (request: WebPluginRouteRequest, context: TContext) => WebPluginRouteResult | Promise<WebPluginRouteResult>;
482
+ /**
483
+ * Plugin Permission Definition (CASL format)
484
+ *
485
+ * Defines a permission that a plugin registers for use in the CASL permission system.
486
+ * Plugins use this to declare what permissions they provide.
487
+ *
488
+ * @example
489
+ * // Simple permission (manage is default action)
490
+ * { subject: 'settings' }
491
+ *
492
+ * // Permission with specific actions
493
+ * { subject: 'analytics', actions: ['read', 'export'] }
494
+ *
495
+ * // Permission with field-level access
496
+ * { subject: 'report', actions: ['read'], fields: ['summary', 'chart'] }
497
+ */
498
+ interface PluginPermissionDef {
499
+ /** Subject name (will be prefixed with plugin:{pluginId}:) */
500
+ subject: string;
501
+ /** Actions supported (default: ['manage']) */
502
+ actions?: string[];
503
+ /** Field-level restrictions (default: null = all fields) */
504
+ fields?: string[] | null;
505
+ /** Human-readable description for Admin UI */
506
+ description?: string;
507
+ }
508
+ /**
509
+ * Plugin Logger - Scoped logging interface
510
+ *
511
+ * Per OBSERVABILITY_GOVERNANCE §3.3:
512
+ * - info, warn, error: Always available
513
+ * - debug: Optional, only available when explicitly enabled by tenant admin
514
+ */
515
+ interface PluginLogger {
516
+ info(message: string, meta?: Record<string, unknown>): void;
517
+ warn(message: string, meta?: Record<string, unknown>): void;
518
+ error(message: string, meta?: Record<string, unknown>): void;
519
+ /**
520
+ * Debug logging - only available when debug mode is enabled by tenant admin.
521
+ * Calls are silently ignored when debug mode is disabled.
522
+ */
523
+ debug?(message: string, meta?: Record<string, unknown>): void;
524
+ }
525
+ /**
526
+ * Plugin Permission Capability - Permission checking interface
527
+ *
528
+ * All permission checks are scoped to:
529
+ * - Permissions declared in the plugin manifest
530
+ * - Permissions granted to the current user
531
+ */
532
+ interface PluginPermissionCapability {
533
+ /**
534
+ * Check if current user has a capability
535
+ * @param capability - Capability in format `resource:action:scope`
536
+ * @param context - Optional context override for checks that resolve tenant or role after request setup
537
+ * @returns true if allowed, false if denied
538
+ */
539
+ can(capability: string, context?: PluginPermissionCheckContext): Promise<boolean>;
540
+ /**
541
+ * Require a capability - throws if denied
542
+ * @param capability - Capability to require
543
+ * @param context - Optional context override for checks that resolve tenant or role after request setup
544
+ * @throws PermissionDeniedError if permission denied
545
+ */
546
+ require(capability: string, context?: PluginPermissionCheckContext): Promise<void>;
547
+ /**
548
+ * Check if plugin has access to a capability
549
+ * (Plugin must have declared this capability in manifest)
550
+ * @param capability - Capability to check
551
+ */
552
+ hasDeclared(capability: string): boolean;
553
+ }
554
+ interface PluginPermissionCheckContext {
555
+ requestId?: string | undefined;
556
+ organizationId?: string | undefined;
557
+ userId?: string | undefined;
558
+ userRole?: string | undefined;
559
+ userRoles?: string[] | undefined;
560
+ currentTeamId?: string | undefined;
561
+ actorType?: PluginContext["actorType"] | undefined;
562
+ apiTokenId?: string | undefined;
563
+ apiTokenScopes?: string[] | undefined;
564
+ }
565
+ type PluginApisCapability = Record<string, any>;
566
+ /** A tool statically declared by a plugin manifest and reconciled into the Core agent tool registry. */
567
+ interface AgentToolDescriptor {
568
+ /** Tool id as declared in the manifest (unique within the plugin). */
569
+ id: string;
570
+ /** Declaring plugin id (reverse-domain). */
571
+ pluginId: string;
572
+ title: string;
573
+ summary?: string | undefined;
574
+ }
575
+ /**
576
+ * Read surface over the Core agent tool registry.
577
+ * Injected only for plugins with `capabilities.agent.runtime === true`.
578
+ * Listing is declaration-scoped: only tools from loaded plugins appear, and
579
+ * tenant-disabled contributors are filtered when an organization is in scope.
580
+ */
581
+ interface PluginAgentCapability {
582
+ listTools(): Promise<AgentToolDescriptor[]>;
583
+ }
584
+ interface AiUsage {
585
+ inputTokens: number;
586
+ outputTokens: number;
587
+ totalTokens: number;
588
+ costUsd: number;
589
+ }
590
+ interface AiBudget {
591
+ /** Per-request ceiling supplied by the caller; the effective deployment may lower it. */
592
+ maxCostUsd?: number | undefined;
593
+ maxOutputTokens?: number | undefined;
594
+ }
595
+ interface AiModelHint {
596
+ provider: string;
597
+ model: string;
598
+ }
599
+ interface AiTextRequest {
600
+ prompt: string;
601
+ system?: string | undefined;
602
+ /** Optional plugin-local alias declared in the manifest for administrator binding. */
603
+ alias?: string | undefined;
604
+ /** Explicit deployment selected from listModels(). */
605
+ model?: string | undefined;
606
+ /** Revision returned with the explicit model selection. */
607
+ revision?: string | undefined;
608
+ /** Developer fallback hint; the effective policy default wins when unavailable. */
609
+ defaultModel?: AiModelHint | undefined;
610
+ budget?: AiBudget | undefined;
611
+ signal?: AbortSignal | undefined;
612
+ }
613
+ interface AiTextResult {
614
+ text: string;
615
+ provider: string;
616
+ model: string;
617
+ responseModel?: string | undefined;
618
+ modelId: string;
619
+ revision: string;
620
+ alias?: string | undefined;
621
+ usage: AiUsage;
622
+ }
623
+ /** Structural on purpose: Zod and other validators can be passed without coupling the SDK to one library. */
624
+ interface AiObjectSchema<T> {
625
+ parse(value: unknown): T;
626
+ }
627
+ interface AiObjectRequest<T> extends AiTextRequest {
628
+ schema: AiObjectSchema<T>;
629
+ }
630
+ interface AiObjectResult<T> {
631
+ object: T;
632
+ provider: string;
633
+ model: string;
634
+ responseModel?: string | undefined;
635
+ modelId: string;
636
+ revision: string;
637
+ alias?: string | undefined;
638
+ usage: AiUsage;
639
+ }
640
+ interface AiModelOption {
641
+ id: string;
642
+ name: string;
643
+ provider: string;
644
+ model: string;
645
+ reasoning: boolean;
646
+ input: Array<'text' | 'image'>;
647
+ contextWindow: number;
648
+ maxOutputTokens: number;
649
+ }
650
+ interface AiModelCatalog {
651
+ revision: string;
652
+ defaultModel: string | null;
653
+ models: AiModelOption[];
654
+ }
655
+ interface AiModelListRequest {
656
+ alias?: string | undefined;
657
+ }
658
+ type AiStreamEvent = {
659
+ type: 'text-delta';
660
+ delta: string;
661
+ } | {
662
+ type: 'usage';
663
+ usage: AiUsage;
664
+ provider: string;
665
+ model: string;
666
+ responseModel?: string | undefined;
667
+ modelId: string;
668
+ revision: string;
669
+ alias?: string | undefined;
670
+ } | {
671
+ type: 'done';
672
+ };
673
+ interface PluginAiCapability {
674
+ /** Optional, backward-compatible availability probe for AI-enabled UI. */
675
+ status?(): Promise<{
676
+ available: boolean;
677
+ reason?: string | undefined;
678
+ }>;
679
+ listModels(request?: AiModelListRequest): Promise<AiModelCatalog>;
680
+ generateText(request: AiTextRequest): Promise<AiTextResult>;
681
+ generateObject<T>(request: AiObjectRequest<T>): Promise<AiObjectResult<T>>;
682
+ stream(request: AiTextRequest): AsyncIterable<AiStreamEvent>;
683
+ }
684
+ interface AiRuntimeInvocation {
685
+ invocationId: string;
686
+ organizationId: string;
687
+ userId: string;
688
+ pluginId: string;
689
+ alias?: string | undefined;
690
+ }
691
+ interface AiUsageAuthorization {
692
+ units: number;
693
+ deploymentId: string;
694
+ revision: string;
695
+ alias?: string | undefined;
696
+ provider: string;
697
+ model: string;
698
+ estimatedCostUsd: number;
699
+ }
700
+ interface AiUsageObservation {
701
+ status: 'succeeded' | 'failed' | 'aborted';
702
+ deploymentId: string;
703
+ revision: string;
704
+ alias?: string | undefined;
705
+ provider: string;
706
+ model: string;
707
+ responseModel?: string | undefined;
708
+ usage?: AiUsage | undefined;
709
+ errorCode?: string | undefined;
710
+ }
711
+ /** Narrow Host services offered to the AI Runtime handler at invocation time. */
712
+ interface AiRuntimeHost {
713
+ getSetting<T = unknown>(key: string): Promise<T | null>;
714
+ getSecret<T = unknown>(key: string): Promise<T>;
715
+ authorizeUsage(input: AiUsageAuthorization): Promise<void>;
716
+ recordUsage(input: AiUsageObservation): Promise<void>;
717
+ }
718
+ interface AiRuntimeHandler {
719
+ /** Read-only readiness probe. It validates the effective model and required credential without reserving usage. */
720
+ checkReady?(invocation: AiRuntimeInvocation, host: AiRuntimeHost): Promise<void>;
721
+ listModels(invocation: AiRuntimeInvocation, request: AiModelListRequest, host: AiRuntimeHost): Promise<AiModelCatalog>;
722
+ generateText(invocation: AiRuntimeInvocation, request: AiTextRequest, host: AiRuntimeHost): Promise<AiTextResult>;
723
+ generateObject<T>(invocation: AiRuntimeInvocation, request: AiObjectRequest<T>, host: AiRuntimeHost): Promise<AiObjectResult<T>>;
724
+ stream(invocation: AiRuntimeInvocation, request: AiTextRequest, host: AiRuntimeHost): AsyncIterable<AiStreamEvent>;
725
+ }
726
+ interface PluginAiRuntimeCapability {
727
+ register(handler: AiRuntimeHandler): () => void;
728
+ listAliases(): Promise<AiAliasDescriptor[]>;
729
+ }
730
+ interface AiAliasDescriptor {
731
+ id: string;
732
+ pluginId: string;
733
+ alias: string;
734
+ name: string;
735
+ description?: string | undefined;
736
+ }
737
+ /**
738
+ * Action Contract declared on a tRPC procedure via `.meta({ action: {...} })`.
739
+ * `actionId` is a stable identifier decoupled from the procedure path
740
+ * (renames are a rebinding, detected by drift tooling — plan decision 10).
741
+ */
742
+ interface ActionContractMeta {
743
+ /** Stable id, lowercase dot-separated (e.g. "spike-studio.greeting.create"). */
744
+ actionId: string;
745
+ /** Contract revision; approval tokens and callers bind to it. */
746
+ revision: number;
747
+ kind: "query" | "command";
748
+ risk: "low" | "medium" | "high";
749
+ summary?: string | undefined;
750
+ }
751
+ /** Catalog entry exposed to invoker plugins. Procedure paths are not exposed. */
752
+ interface ActionDescriptor extends ActionContractMeta {
753
+ /** Owning plugin id, or null for core-owned actions. */
754
+ pluginId: string | null;
755
+ permission: {
756
+ action: string;
757
+ subject: string;
758
+ };
759
+ }
760
+ interface ActionInvokeRequest {
761
+ actionId: string;
762
+ revision: number;
763
+ args?: unknown;
764
+ /** Required for actions the contract marks `risk: 'high'`. */
765
+ approvalToken?: string;
766
+ }
767
+ /**
768
+ * Governed action invocation surface (AI Action Gateway, Phase 0 spike).
769
+ * Injected only for plugins with `capabilities.agent.invoker === true`.
770
+ * The Host resolves `actionId` to a procedure binding itself — callers never
771
+ * choose paths — and derives principal identity from the live request context.
772
+ */
773
+ interface PluginActionInvokerCapability {
774
+ list(): Promise<ActionDescriptor[]>;
775
+ invoke(request: ActionInvokeRequest): Promise<unknown>;
776
+ }
777
+ type EAuthModel = "oauth_refresh" | "api_key" | "hmac" | "token" | "amazon_spapi";
778
+ type EAuthStatus = "ok" | "reauth" | "retry";
779
+ type EAuthUse = "products" | "orders" | "fulfillment" | "test" | string;
780
+ type EAuthTokenResult = {
781
+ status: "ok";
782
+ accessToken: string;
783
+ accessTokenExpiresAt?: Date | undefined;
784
+ } | {
785
+ status: "reauth";
786
+ code: string;
787
+ message: string;
788
+ } | {
789
+ status: "retry";
790
+ code: string;
791
+ message: string;
792
+ retryAt?: Date | undefined;
793
+ };
794
+ interface EAuthRefreshInput {
795
+ refreshToken: string;
796
+ accountId: string;
797
+ meta?: Record<string, unknown> | undefined;
798
+ }
799
+ interface EAuthRefreshResult {
800
+ accessToken: string;
801
+ refreshToken?: string | undefined;
802
+ accessTokenExpiresAt?: Date | undefined;
803
+ refreshTokenExpiresAt?: Date | undefined;
804
+ scope?: string | undefined;
805
+ meta?: Record<string, unknown> | undefined;
806
+ }
807
+ interface EAuthProvider {
808
+ refresh(input: EAuthRefreshInput): Promise<EAuthRefreshResult>;
809
+ }
810
+ interface EAuthUpsertInput {
811
+ id?: string | undefined;
812
+ model: EAuthModel;
813
+ connectionId: string;
814
+ accountId: string;
815
+ accessToken?: string | undefined;
816
+ refreshToken?: string | undefined;
817
+ accessTokenExpiresAt?: Date | undefined;
818
+ refreshTokenExpiresAt?: Date | undefined;
819
+ scope?: string | undefined;
820
+ status?: EAuthStatus | undefined;
821
+ meta?: Record<string, unknown> | undefined;
822
+ }
823
+ interface PluginEAuthCapability {
824
+ registerProvider(provider: EAuthProvider): void;
825
+ upsert(input: EAuthUpsertInput): Promise<{
826
+ id: string;
827
+ }>;
828
+ token(input: {
829
+ eauthId: string;
830
+ use?: EAuthUse | undefined;
831
+ }): Promise<EAuthTokenResult>;
832
+ }
833
+ interface PluginCurrencyCapability {
834
+ /**
835
+ * Get enabled currencies with effective current rates in the current tenant context.
836
+ *
837
+ * The host resolves platform-vs-tenant ownership according to infra policy.
838
+ */
839
+ getEffectiveEnabledCurrencies(options?: {
840
+ organizationId?: string | undefined;
841
+ }): Promise<Array<{
842
+ code: string;
843
+ nameI18n?: Record<string, string> | null;
844
+ symbol?: string | null;
845
+ decimalDigits?: number | null;
846
+ isBase?: boolean;
847
+ currentRate?: string | null;
848
+ }>>;
849
+ /**
850
+ * Get the effective current rate for a currency code in the current tenant context.
851
+ *
852
+ * The host resolves platform-vs-tenant ownership according to infra policy.
853
+ */
854
+ getEffectiveCurrentRate(code: string, options?: {
855
+ organizationId?: string | undefined;
856
+ }): Promise<string | null>;
857
+ /**
858
+ * Convenience helper for CNY to USD conversions.
859
+ * Returns the effective CNY → USD rate, or null when not configured.
860
+ */
861
+ getEffectiveCnyToUsdRate(options?: {
862
+ organizationId?: string | undefined;
863
+ }): Promise<number | null>;
864
+ }
865
+ interface PluginEntityExtensionFilter {
866
+ id: string;
867
+ value: string | string[];
868
+ variant: string;
869
+ operator: string;
870
+ filterId?: string | undefined;
871
+ }
872
+ interface PluginEntityExtensionCapability {
873
+ /**
874
+ * Save extension values for a target plugin CRUD row through the platform contract.
875
+ *
876
+ * Values are keyed by manifest field name. The platform resolves each
877
+ * field owner from enabled plugin manifests, invokes owner save handlers,
878
+ * and refreshes Core's query projection.
879
+ */
880
+ saveValues(options: {
881
+ /** Globally unique extension target id, e.g. "com.example.shop.stores". */
882
+ id: string;
883
+ entityId: string;
884
+ ext?: Record<string, unknown> | null | undefined;
885
+ tx?: unknown;
886
+ }): Promise<void>;
887
+ /**
888
+ * Match target CRUD row ids from Core's query projection for extension-field filters.
889
+ *
890
+ * This is a Core-mediated read model query. Plugins receive row ids only;
891
+ * plugin-owned semantic extension values stay in the owner plugin's private
892
+ * storage and are not exposed through this capability.
893
+ */
894
+ matchEntityIds(options: {
895
+ /** Globally unique extension target id, e.g. "com.example.shop.stores". */
896
+ id: string;
897
+ filters: PluginEntityExtensionFilter[];
898
+ joinOperator?: "and" | "or" | undefined;
899
+ limit?: number | undefined;
900
+ }): Promise<string[]>;
901
+ /**
902
+ * Match target CRUD row ids by global search over fields whose manifest
903
+ * declaration has `search: true`.
904
+ */
905
+ searchEntityIds(options: {
906
+ /** Globally unique extension target id, e.g. "com.example.shop.stores". */
907
+ id: string;
908
+ search: string;
909
+ limit?: number | undefined;
910
+ }): Promise<string[]>;
911
+ }
912
+ interface PluginCrudExtensionFilter {
913
+ id: string;
914
+ value: string | string[];
915
+ variant: string;
916
+ operator: string;
917
+ filterId?: string | undefined;
918
+ }
919
+ interface PluginCrudExtensionMetadata {
920
+ schema?: unknown;
921
+ fields?: Record<string, unknown>;
922
+ errors?: string[] | undefined;
923
+ }
924
+ interface PluginCrudExtensionsCapability {
925
+ getMetadata?(options: {
926
+ /** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
927
+ id: string;
928
+ }): Promise<PluginCrudExtensionMetadata>;
929
+ saveExtraValues(options: {
930
+ /** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
931
+ id: string;
932
+ entityId: string;
933
+ rawValues: Record<string, unknown>;
934
+ baseValues: Record<string, unknown>;
935
+ extraValues: Record<string, unknown>;
936
+ tx?: unknown;
937
+ }): Promise<void>;
938
+ readProjection(options: {
939
+ /** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
940
+ id: string;
941
+ entityIds: string[];
942
+ fields?: string[] | undefined;
943
+ }): Promise<Record<string, Record<string, unknown>>>;
944
+ matchEntityIds(options: {
945
+ /** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
946
+ id: string;
947
+ filters: PluginCrudExtensionFilter[];
948
+ joinOperator?: "and" | "or" | undefined;
949
+ limit?: number | undefined;
950
+ }): Promise<string[]>;
951
+ searchEntityIds(options: {
952
+ /** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
953
+ id: string;
954
+ search: string;
955
+ limit?: number | undefined;
956
+ }): Promise<string[]>;
957
+ }
958
+ /**
959
+ * Plugin Queue Capability - Async job processing
960
+ *
961
+ * All jobs are namespaced with plugin_{pluginId}_{jobName}
962
+ * Subject to rate limits and payload size restrictions.
963
+ */
964
+ interface PluginQueueCapability {
965
+ /**
966
+ * Add a job to the queue
967
+ * @param jobName - Job name (will be prefixed with plugin_{pluginId}_)
968
+ * @param data - Job payload (must be JSON-serializable, max 64KB)
969
+ * @param options - Job options
970
+ */
971
+ addJob<T = unknown>(jobName: string, data: T, options?: PluginJobOptions): Promise<{
972
+ jobId: string;
973
+ }>;
974
+ /**
975
+ * Get job status
976
+ * @param jobId - Job ID returned from addJob
977
+ */
978
+ getJobStatus(jobId: string): Promise<PluginJobStatus>;
979
+ /**
980
+ * Cancel a pending job
981
+ * @param jobId - Job ID to cancel
982
+ */
983
+ cancelJob(jobId: string): Promise<boolean>;
984
+ }
985
+ /**
986
+ * Plugin Job Options
987
+ */
988
+ interface PluginJobOptions {
989
+ /** Job priority: 'low' | 'normal' | 'high' | 'critical' */
990
+ priority?: "low" | "normal" | "high" | "critical";
991
+ /** Stable job id for idempotent queueing */
992
+ jobId?: string;
993
+ /** Delay in milliseconds before processing */
994
+ delay?: number;
995
+ /** Number of retry attempts on failure */
996
+ attempts?: number;
997
+ /** Backoff strategy for retries */
998
+ backoff?: {
999
+ type: "fixed" | "exponential";
1000
+ delay: number;
1001
+ };
1002
+ /** Remove job after completion */
1003
+ removeOnComplete?: boolean;
1004
+ /** Remove job after failure */
1005
+ removeOnFail?: boolean;
1006
+ }
1007
+ /**
1008
+ * Plugin Job Status
1009
+ */
1010
+ interface PluginJobStatus {
1011
+ id: string;
1012
+ name: string;
1013
+ state: "waiting" | "active" | "completed" | "failed" | "delayed";
1014
+ progress?: number;
1015
+ returnValue?: unknown;
1016
+ failedReason?: string;
1017
+ timestamp: number;
1018
+ processedOn?: number;
1019
+ finishedOn?: number;
1020
+ }
1021
+ /**
1022
+ * Plugin Notification Capability - Send notifications (Unified Contract v2)
1023
+ *
1024
+ * Plugins can send notifications to users via Core's notification system.
1025
+ * All notifications are tagged with sourcePluginId and validated against manifest.
1026
+ *
1027
+ * Key features:
1028
+ * - Type validation: notification type must be declared in manifest
1029
+ * - Rate limiting: plugin-level and user-level limits enforced
1030
+ * - Aggregation: automatic grouping based on manifest-declared strategy
1031
+ * - Webhooks: async callbacks for click/archive events
1032
+ */
1033
+ interface PluginNotificationCapability {
1034
+ /**
1035
+ * Send a notification using the unified contract
1036
+ *
1037
+ * The notification type must be declared in the plugin's manifest.
1038
+ * Rate limits are enforced (plugin: 100/min, 1000/hr, 10000/day; user: 10/min, 50/hr).
1039
+ *
1040
+ * @param params - Notification parameters
1041
+ * @returns Promise resolving to notification ID
1042
+ * @throws PluginNotificationValidationError if type not declared in manifest
1043
+ * @throws RateLimitExceededError if rate limit exceeded
1044
+ * @throws PermissionDeniedError if notification:send not declared
1045
+ */
1046
+ send(params: PluginNotificationSendParams): Promise<PluginNotificationSendResult>;
1047
+ /**
1048
+ * Register a notification template (legacy, still supported)
1049
+ * Templates are namespaced: plugin_{pluginId}_{templateKey}
1050
+ */
1051
+ registerTemplate(template: PluginNotificationTemplate): Promise<void>;
1052
+ /**
1053
+ * Register a notification channel (legacy, still supported)
1054
+ * Channels are namespaced: plugin_{pluginId}_{channelKey}
1055
+ */
1056
+ registerChannel(channel: PluginNotificationChannel): Promise<void>;
1057
+ /**
1058
+ * Subscribe to notification.created events
1059
+ * Allows plugins to enhance notifications (e.g., send to external services)
1060
+ */
1061
+ onNotificationCreated(handler: (event: PluginNotificationEvent) => void | Promise<void>): () => void;
1062
+ }
1063
+ /**
1064
+ * Plugin Notification Send Parameters (Unified Contract v2)
1065
+ *
1066
+ * Simplified API where plugins declare "intent", platform handles "execution".
1067
+ */
1068
+ interface PluginNotificationSendParams {
1069
+ /**
1070
+ * Notification type ID - must match a type declared in manifest.notifications.types
1071
+ * @example "task_reminder", "content_liked"
1072
+ */
1073
+ type: string;
1074
+ /**
1075
+ * Target user ID to receive the notification
1076
+ */
1077
+ userId: string;
1078
+ /**
1079
+ * Actor who triggered the notification (optional)
1080
+ * If not provided, the plugin itself is treated as the actor
1081
+ */
1082
+ actor?: PluginNotificationActor;
1083
+ /**
1084
+ * Target object the notification is about
1085
+ */
1086
+ target: PluginNotificationTarget;
1087
+ /**
1088
+ * Custom data for template rendering
1089
+ * These values are passed to i18n templates as variables
1090
+ */
1091
+ data?: Record<string, unknown>;
1092
+ /**
1093
+ * Locale for i18n (e.g., 'en-US', 'zh-CN')
1094
+ * Falls back to user preference or 'en-US'
1095
+ */
1096
+ locale?: string;
1097
+ }
1098
+ /**
1099
+ * Notification Actor - who triggered the notification
1100
+ */
1101
+ interface PluginNotificationActor {
1102
+ /** Actor ID (user ID or plugin ID) */
1103
+ id: string;
1104
+ /** Actor type */
1105
+ type: "user" | "plugin";
1106
+ /** Display name */
1107
+ name: string;
1108
+ /** Avatar URL (optional) */
1109
+ avatarUrl?: string;
1110
+ }
1111
+ /**
1112
+ * Notification Target - what the notification is about
1113
+ */
1114
+ interface PluginNotificationTarget {
1115
+ /** Target type (e.g., 'post', 'comment', 'task') */
1116
+ type: string;
1117
+ /** Target ID */
1118
+ id: string;
1119
+ /** URL to navigate when notification is clicked */
1120
+ url: string;
1121
+ /** Preview image URL (optional, for rich notifications) */
1122
+ previewImage?: string;
1123
+ }
1124
+ /**
1125
+ * Plugin Notification Send Result
1126
+ */
1127
+ interface PluginNotificationSendResult {
1128
+ /** The created notification ID */
1129
+ notificationId: string;
1130
+ }
1131
+ /**
1132
+ * Plugin Notification Input (Legacy - use PluginNotificationSendParams instead)
1133
+ * @deprecated Use PluginNotificationSendParams for new implementations
1134
+ */
1135
+ interface PluginNotificationInput {
1136
+ /** Target user ID */
1137
+ userId: string;
1138
+ /** Template key (will be prefixed with plugin_{pluginId}_ if not already) */
1139
+ templateKey: string;
1140
+ /** Variables for template interpolation */
1141
+ variables: Record<string, unknown>;
1142
+ /** Notification type */
1143
+ type?: "info" | "success" | "warning" | "error";
1144
+ /** Link to navigate when clicked */
1145
+ link?: string;
1146
+ /** Actor ID (who triggered the notification) */
1147
+ actorId?: string;
1148
+ /** Entity reference */
1149
+ entityId?: string;
1150
+ entityType?: string;
1151
+ /** Grouping key for bundling */
1152
+ groupKey?: string;
1153
+ /** Idempotency key to prevent duplicates */
1154
+ idempotencyKey?: string;
1155
+ /** Priority override */
1156
+ priority?: "low" | "normal" | "high" | "urgent";
1157
+ /** Channel overrides */
1158
+ channels?: string[];
1159
+ /** Locale for i18n */
1160
+ locale?: string;
1161
+ }
1162
+ /**
1163
+ * Plugin Notification Result (Legacy)
1164
+ * @deprecated Use PluginNotificationSendResult for new implementations
1165
+ */
1166
+ interface PluginNotificationResult {
1167
+ notificationId: string;
1168
+ channels: string[];
1169
+ decisionTrace: Array<{
1170
+ channel: string;
1171
+ included: boolean;
1172
+ reason: string;
1173
+ }>;
1174
+ }
1175
+ /**
1176
+ * Plugin Notification Template
1177
+ */
1178
+ interface PluginNotificationTemplate {
1179
+ /** Template key (will be prefixed with plugin_{pluginId}_) */
1180
+ key: string;
1181
+ /** Display name */
1182
+ name: string;
1183
+ /** Description */
1184
+ description?: string;
1185
+ /** i18n title templates */
1186
+ title: Record<string, string>;
1187
+ /** i18n message templates */
1188
+ message: Record<string, string>;
1189
+ /** Variables that can be interpolated */
1190
+ variables?: string[];
1191
+ /** Default channels */
1192
+ defaultChannels?: string[];
1193
+ /** Default priority */
1194
+ priority?: "low" | "normal" | "high" | "urgent";
1195
+ }
1196
+ /**
1197
+ * Plugin Notification Channel
1198
+ */
1199
+ interface PluginNotificationChannel {
1200
+ /** Channel key (will be prefixed with plugin_{pluginId}_) */
1201
+ key: string;
1202
+ /** i18n display name */
1203
+ name: Record<string, string>;
1204
+ /** i18n description */
1205
+ description?: Record<string, string>;
1206
+ /** Icon name */
1207
+ icon?: string;
1208
+ /** User configuration schema (JSON Schema) */
1209
+ configSchema?: Record<string, unknown>;
1210
+ }
1211
+ /**
1212
+ * Plugin Notification Event (for onNotificationCreated)
1213
+ */
1214
+ interface PluginNotificationEvent {
1215
+ notification: {
1216
+ id: string;
1217
+ userId: string;
1218
+ organizationId: string;
1219
+ templateKey?: string;
1220
+ type: string;
1221
+ title: string;
1222
+ message: string;
1223
+ html?: string;
1224
+ link?: string;
1225
+ priority: "low" | "normal" | "high" | "urgent";
1226
+ actorId?: string;
1227
+ entityId?: string;
1228
+ entityType?: string;
1229
+ groupKey?: string;
1230
+ sourcePluginId?: string;
1231
+ };
1232
+ user: {
1233
+ id: string;
1234
+ email?: string;
1235
+ preferences: {
1236
+ enabledChannels: string[];
1237
+ emailFrequency: "instant" | "hourly" | "daily";
1238
+ };
1239
+ };
1240
+ channels: string[];
1241
+ }
1242
+ /**
1243
+ * Plugin Settings Capability - Configuration management for plugins
1244
+ *
1245
+ * All settings are automatically scoped to the plugin's namespace:
1246
+ * - plugin_global: Plugin-wide settings (shared across all tenants)
1247
+ * - plugin_tenant: Per-tenant plugin settings
1248
+ *
1249
+ * Plugins cannot access Core settings or other plugins' settings.
1250
+ */
1251
+ interface PluginSettingsCapability {
1252
+ /**
1253
+ * Get a setting value
1254
+ * Resolution order: plugin_tenant → plugin_global → defaultValue
1255
+ *
1256
+ * @param key - Setting key (without plugin prefix)
1257
+ * @param defaultValue - Default value if not found
1258
+ * @returns The setting value or default
1259
+ */
1260
+ get<T = unknown>(key: string, defaultValue?: T): Promise<T | null>;
1261
+ /**
1262
+ * Check whether an exact scoped setting exists without reading its value.
1263
+ * Use encrypted=true for credential status probes that must not decrypt secrets.
1264
+ */
1265
+ has(key: string, options?: {
1266
+ global?: boolean;
1267
+ encrypted?: boolean;
1268
+ }): Promise<boolean>;
1269
+ /**
1270
+ * Set a setting value
1271
+ *
1272
+ * @param key - Setting key (without plugin prefix)
1273
+ * @param value - Value to store
1274
+ * @param options - Additional options
1275
+ */
1276
+ set(key: string, value: unknown, options?: PluginSettingOptions): Promise<void>;
1277
+ /**
1278
+ * Delete a setting
1279
+ *
1280
+ * @param key - Setting key to delete
1281
+ * @param options - Scope options
1282
+ */
1283
+ delete(key: string, options?: {
1284
+ global?: boolean;
1285
+ }): Promise<boolean>;
1286
+ /**
1287
+ * List all settings for the plugin
1288
+ *
1289
+ * @param options - Filter options
1290
+ * @returns Array of settings
1291
+ */
1292
+ list(options?: {
1293
+ global?: boolean;
1294
+ keyPrefix?: string;
1295
+ }): Promise<PluginSettingEntry[]>;
1296
+ /**
1297
+ * Check if a feature flag is enabled for the current context
1298
+ *
1299
+ * @param flagKey - Feature flag key
1300
+ * @returns true if enabled, false otherwise
1301
+ */
1302
+ isFeatureEnabled(flagKey: string): Promise<boolean>;
1303
+ }
1304
+ /**
1305
+ * Plugin Setting Options
1306
+ */
1307
+ interface PluginSettingOptions {
1308
+ /** Store as global (plugin_global) instead of tenant-scoped (plugin_tenant) */
1309
+ global?: boolean;
1310
+ /** Encrypt the value (for sensitive data like API keys) */
1311
+ encrypted?: boolean;
1312
+ /** Description for admin UI */
1313
+ description?: string;
1314
+ }
1315
+ /**
1316
+ * Plugin Setting Entry (for list operation)
1317
+ */
1318
+ interface PluginSettingEntry {
1319
+ key: string;
1320
+ value: unknown;
1321
+ scope: "plugin_global" | "plugin_tenant";
1322
+ encrypted: boolean;
1323
+ description?: string | undefined;
1324
+ }
1325
+ /**
1326
+ * Plugin Media Capability - Unified file and asset management
1327
+ *
1328
+ * Provides plugins with the ability to upload, manage, and organize media.
1329
+ * Replaces the separate File and Asset capabilities.
1330
+ * All operations are scoped to the current tenant.
1331
+ */
1332
+ interface PluginMediaCapability {
1333
+ /**
1334
+ * Upload a media file
1335
+ * @param input - Media upload input
1336
+ * @returns Uploaded media info
1337
+ */
1338
+ upload(input: PluginMediaUploadInput): Promise<PluginMediaInfo>;
1339
+ /**
1340
+ * Get media info by ID
1341
+ * @param mediaId - Media ID
1342
+ * @returns Media info or null if not found
1343
+ */
1344
+ get(mediaId: string): Promise<PluginMediaInfo | null>;
1345
+ /**
1346
+ * Update media metadata
1347
+ * @param mediaId - Media ID
1348
+ * @param data - Update data
1349
+ */
1350
+ update(mediaId: string, data: PluginMediaUpdateData): Promise<PluginMediaInfo>;
1351
+ /**
1352
+ * Download media content
1353
+ * @param mediaId - Media ID
1354
+ * @returns Media content as Buffer
1355
+ */
1356
+ download(mediaId: string): Promise<Buffer>;
1357
+ /**
1358
+ * Get signed URL for media access
1359
+ * @param mediaId - Media ID
1360
+ * @param options - URL options
1361
+ * @returns Signed URL with expiration
1362
+ */
1363
+ getSignedUrl(mediaId: string, options?: {
1364
+ expiresIn?: number;
1365
+ }): Promise<{
1366
+ url: string;
1367
+ expiresIn: number;
1368
+ }>;
1369
+ /**
1370
+ * Get fixed display URL for media access
1371
+ * @param mediaId - Media ID
1372
+ * @param options - Display URL options
1373
+ * @returns Stable application-controlled display URL
1374
+ */
1375
+ getDisplayUrl(mediaId: string, options?: {
1376
+ variant?: string;
1377
+ }): Promise<{
1378
+ url: string;
1379
+ variant: string;
1380
+ }>;
1381
+ /**
1382
+ * Resolve a media reference or legacy signed file URL to a display URL
1383
+ * @param value - Media ID, signed file URL, display URL, or external URL
1384
+ * @param options - Display URL options
1385
+ * @returns Application-controlled display URL when resolvable
1386
+ */
1387
+ resolveAccessUrl(value: string, options?: {
1388
+ variant?: string;
1389
+ }): Promise<{
1390
+ url: string;
1391
+ }>;
1392
+ /**
1393
+ * Delete a media (soft delete)
1394
+ * @param mediaId - Media ID
1395
+ */
1396
+ delete(mediaId: string): Promise<void>;
1397
+ /**
1398
+ * List media with filtering and pagination
1399
+ * @param query - Query options
1400
+ */
1401
+ list(query?: PluginMediaQuery): Promise<PluginPaginatedResult<PluginMediaInfo>>;
1402
+ /**
1403
+ * Get URL for a media variant
1404
+ * @param mediaId - Media ID
1405
+ * @param variant - Variant name (e.g., 'thumbnail', 'medium')
1406
+ */
1407
+ getVariantUrl(mediaId: string, variant: string): Promise<string>;
1408
+ /**
1409
+ * Get all variants for a media
1410
+ * @param mediaId - Media ID
1411
+ */
1412
+ getVariants(mediaId: string): Promise<PluginMediaVariant[]>;
1413
+ }
1414
+ /**
1415
+ * Plugin Media Upload Input
1416
+ */
1417
+ interface PluginMediaUploadInput {
1418
+ /** File content */
1419
+ content: Buffer;
1420
+ /** Original filename */
1421
+ filename: string;
1422
+ /** MIME type */
1423
+ mimeType: string;
1424
+ /** Is publicly accessible */
1425
+ isPublic?: boolean;
1426
+ /** Alt text for accessibility */
1427
+ alt?: string;
1428
+ /** Title */
1429
+ title?: string;
1430
+ /** Tags for organization */
1431
+ tags?: string[];
1432
+ /** Folder path */
1433
+ folderPath?: string;
1434
+ /** Additional metadata */
1435
+ metadata?: Record<string, unknown>;
1436
+ }
1437
+ /**
1438
+ * Plugin Media Info
1439
+ */
1440
+ interface PluginMediaInfo {
1441
+ id: string;
1442
+ /** Browser-accessible URL resolved by the Admin Host media picker. */
1443
+ url?: string;
1444
+ filename: string;
1445
+ mimeType: string;
1446
+ size: number;
1447
+ isPublic: boolean;
1448
+ alt?: string;
1449
+ title?: string;
1450
+ tags: string[];
1451
+ folderPath?: string;
1452
+ width?: number;
1453
+ height?: number;
1454
+ format?: string;
1455
+ metadata?: Record<string, unknown>;
1456
+ createdAt: Date;
1457
+ updatedAt: Date;
1458
+ }
1459
+ /**
1460
+ * Plugin Media Update Data
1461
+ */
1462
+ interface PluginMediaUpdateData {
1463
+ alt?: string;
1464
+ title?: string;
1465
+ tags?: string[];
1466
+ folderPath?: string;
1467
+ }
1468
+ /**
1469
+ * Plugin Media Variant
1470
+ */
1471
+ interface PluginMediaVariant {
1472
+ name: string;
1473
+ mediaId: string;
1474
+ width?: number;
1475
+ height?: number;
1476
+ format?: string;
1477
+ }
1478
+ /**
1479
+ * Plugin Media Query
1480
+ */
1481
+ interface PluginMediaQuery {
1482
+ /** Filter by MIME type or category (e.g., 'image/*') */
1483
+ mimeType?: string;
1484
+ /** Tag filter */
1485
+ tags?: string[];
1486
+ /** Folder path filter (prefix match) */
1487
+ folderPath?: string;
1488
+ /** Search in filename/alt/title */
1489
+ search?: string;
1490
+ /** Sort field */
1491
+ sortBy?: "createdAt" | "updatedAt" | "filename";
1492
+ /** Sort order */
1493
+ sortOrder?: "asc" | "desc";
1494
+ /** Page number */
1495
+ page?: number;
1496
+ /** Page size */
1497
+ pageSize?: number;
1498
+ }
1499
+ /** @deprecated Use PluginMediaCapability */
1500
+ type PluginFileCapability = {
1501
+ upload(input: PluginFileUploadInput): Promise<PluginFileInfo>;
1502
+ get(fileId: string): Promise<PluginFileInfo | null>;
1503
+ download(fileId: string): Promise<Buffer>;
1504
+ getSignedUrl(fileId: string, options?: {
1505
+ expiresIn?: number;
1506
+ }): Promise<{
1507
+ url: string;
1508
+ expiresIn: number;
1509
+ }>;
1510
+ delete(fileId: string): Promise<void>;
1511
+ list(query?: PluginFileQuery): Promise<PluginPaginatedResult<PluginFileInfo>>;
1512
+ };
1513
+ /** @deprecated Use PluginMediaUploadInput */
1514
+ interface PluginFileUploadInput {
1515
+ content: Buffer;
1516
+ filename: string;
1517
+ mimeType: string;
1518
+ isPublic?: boolean;
1519
+ metadata?: Record<string, unknown>;
1520
+ }
1521
+ /** @deprecated Use PluginMediaInfo */
1522
+ interface PluginFileInfo {
1523
+ id: string;
1524
+ filename: string;
1525
+ mimeType: string;
1526
+ size: number;
1527
+ isPublic: boolean;
1528
+ metadata?: Record<string, unknown>;
1529
+ createdAt: Date;
1530
+ updatedAt: Date;
1531
+ }
1532
+ /** @deprecated Use PluginMediaQuery */
1533
+ interface PluginFileQuery {
1534
+ search?: string;
1535
+ mimeType?: string;
1536
+ page?: number;
1537
+ pageSize?: number;
1538
+ }
1539
+ /** @deprecated Use PluginMediaCapability */
1540
+ type PluginAssetCapability = {
1541
+ create(fileId: string, options?: PluginAssetCreateOptions): Promise<PluginAssetInfo>;
1542
+ get(assetId: string): Promise<PluginAssetInfo | null>;
1543
+ update(assetId: string, data: PluginAssetUpdateData): Promise<PluginAssetInfo>;
1544
+ delete(assetId: string): Promise<void>;
1545
+ list(query?: PluginAssetQuery): Promise<PluginPaginatedResult<PluginAssetInfo>>;
1546
+ getVariantUrl(assetId: string, variant: string): Promise<string>;
1547
+ getVariants(assetId: string): Promise<PluginAssetVariant[]>;
1548
+ };
1549
+ /** @deprecated Use PluginMediaUpdateData */
1550
+ interface PluginAssetCreateOptions {
1551
+ type?: "image" | "video" | "document" | "other";
1552
+ alt?: string;
1553
+ title?: string;
1554
+ tags?: string[];
1555
+ folderPath?: string;
1556
+ }
1557
+ /** @deprecated Use PluginMediaUpdateData */
1558
+ interface PluginAssetUpdateData {
1559
+ alt?: string;
1560
+ title?: string;
1561
+ tags?: string[];
1562
+ folderPath?: string;
1563
+ }
1564
+ /** @deprecated Use PluginMediaInfo */
1565
+ interface PluginAssetInfo {
1566
+ id: string;
1567
+ fileId: string;
1568
+ type: "image" | "video" | "document" | "other";
1569
+ alt?: string;
1570
+ title?: string;
1571
+ tags: string[];
1572
+ folderPath?: string;
1573
+ width?: number;
1574
+ height?: number;
1575
+ format?: string;
1576
+ createdAt: Date;
1577
+ updatedAt: Date;
1578
+ }
1579
+ /** @deprecated Use PluginMediaVariant */
1580
+ interface PluginAssetVariant {
1581
+ name: string;
1582
+ fileId: string;
1583
+ width: number;
1584
+ height: number;
1585
+ format: string;
1586
+ }
1587
+ /** @deprecated Use PluginMediaQuery */
1588
+ interface PluginAssetQuery {
1589
+ type?: "image" | "video" | "document" | "other";
1590
+ tags?: string[];
1591
+ folderPath?: string;
1592
+ search?: string;
1593
+ sortBy?: "createdAt" | "updatedAt" | "title";
1594
+ sortOrder?: "asc" | "desc";
1595
+ page?: number;
1596
+ pageSize?: number;
1597
+ }
1598
+ /**
1599
+ * Plugin Storage Capability - Custom storage provider registration
1600
+ *
1601
+ * Allows plugins to register custom storage providers (e.g., S3, OSS, R2).
1602
+ * Providers registered by plugins are automatically namespaced with plugin ID.
1603
+ */
1604
+ interface PluginStorageCapability {
1605
+ /**
1606
+ * Register a custom storage provider
1607
+ * The provider type will be prefixed: plugin_{pluginId}_{type}
1608
+ * @param config - Provider configuration
1609
+ */
1610
+ registerProvider(config: PluginStorageProviderConfig): Promise<void>;
1611
+ /**
1612
+ * List registered storage providers by this plugin
1613
+ */
1614
+ listProviders(): Promise<PluginStorageProviderInfo[]>;
1615
+ /**
1616
+ * Unregister a storage provider
1617
+ * @param type - Provider type (without plugin prefix)
1618
+ */
1619
+ unregisterProvider(type: string): Promise<void>;
1620
+ }
1621
+ interface PluginArtifactCapability {
1622
+ put(input: {
1623
+ content: Uint8Array;
1624
+ filename: string;
1625
+ mediaType: string;
1626
+ metadata?: Record<string, unknown>;
1627
+ }): Promise<{
1628
+ key: string;
1629
+ size: number;
1630
+ sha256: string;
1631
+ }>;
1632
+ get(key: string): Promise<Uint8Array>;
1633
+ delete(key: string): Promise<void>;
1634
+ }
1635
+ /**
1636
+ * Plugin Storage Provider Config
1637
+ */
1638
+ interface PluginStorageProviderConfig {
1639
+ /** Provider type (will be prefixed with plugin_{pluginId}_) */
1640
+ type: string;
1641
+ /** Display name for admin UI */
1642
+ name: string;
1643
+ /** Description */
1644
+ description?: string;
1645
+ /** Configuration schema (JSON Schema) */
1646
+ configSchema: Record<string, unknown>;
1647
+ /** Provider factory function */
1648
+ factory: (config: Record<string, unknown>) => PluginStorageProvider;
1649
+ }
1650
+ /**
1651
+ * Plugin Storage Provider Info
1652
+ */
1653
+ interface PluginStorageProviderInfo {
1654
+ type: string;
1655
+ name: string;
1656
+ description?: string;
1657
+ pluginId: string;
1658
+ }
1659
+ /**
1660
+ * Plugin Storage Provider Interface
1661
+ * Plugins implementing custom storage must implement this interface.
1662
+ */
1663
+ interface PluginStorageProvider {
1664
+ /** Provider type identifier */
1665
+ readonly type: string;
1666
+ /** Upload a file */
1667
+ upload(input: PluginStorageUploadInput): Promise<PluginStorageUploadResult>;
1668
+ /** Download file content */
1669
+ download(key: string): Promise<Buffer>;
1670
+ /** Delete a file */
1671
+ delete(key: string): Promise<void>;
1672
+ /** Check if file exists */
1673
+ exists(key: string): Promise<boolean>;
1674
+ /** Get signed URL */
1675
+ getSignedUrl(key: string, options: {
1676
+ expiresIn: number;
1677
+ operation: "get" | "put";
1678
+ contentType?: string;
1679
+ }): Promise<string>;
1680
+ /** Initiate multipart upload */
1681
+ initiateMultipartUpload(key: string): Promise<string>;
1682
+ /** Upload a part */
1683
+ uploadPart(uploadId: string, partNumber: number, body: Buffer): Promise<{
1684
+ partNumber: number;
1685
+ etag: string;
1686
+ }>;
1687
+ /** Complete multipart upload */
1688
+ completeMultipartUpload(uploadId: string, parts: Array<{
1689
+ partNumber: number;
1690
+ etag: string;
1691
+ }>): Promise<void>;
1692
+ /** Abort multipart upload */
1693
+ abortMultipartUpload(uploadId: string): Promise<void>;
1694
+ }
1695
+ /**
1696
+ * Plugin Storage Upload Input
1697
+ */
1698
+ interface PluginStorageUploadInput {
1699
+ key: string;
1700
+ body: Buffer;
1701
+ contentType: string;
1702
+ metadata?: Record<string, string>;
1703
+ }
1704
+ /**
1705
+ * Plugin Storage Upload Result
1706
+ */
1707
+ interface PluginStorageUploadResult {
1708
+ key: string;
1709
+ size: number;
1710
+ etag?: string;
1711
+ }
1712
+ /**
1713
+ * Generic paginated result
1714
+ */
1715
+ interface PluginPaginatedResult<T> {
1716
+ items: T[];
1717
+ total: number;
1718
+ page: number;
1719
+ pageSize: number;
1720
+ totalPages: number;
1721
+ }
1722
+ /**
1723
+ * Allowed labels for plugin metrics
1724
+ *
1725
+ * Per OBSERVABILITY_GOVERNANCE §4.1:
1726
+ * Only these labels are allowed to prevent cardinality explosion
1727
+ */
1728
+ type PluginMetricsAllowedLabels = {
1729
+ model?: string;
1730
+ type?: string;
1731
+ status?: "success" | "failure";
1732
+ };
1733
+ /**
1734
+ * Plugin Metrics Capability - Usage metrics recording
1735
+ *
1736
+ * Per OBSERVABILITY_GOVERNANCE §4.1:
1737
+ * - Only increment() for discrete event counters
1738
+ * - No histogram/gauge/observe/set methods
1739
+ * - Labels are restricted to a whitelist
1740
+ */
1741
+ interface PluginMetricsCapability {
1742
+ /**
1743
+ * Increment a counter metric
1744
+ *
1745
+ * @param name - Metric name (will be prefixed with plugin_)
1746
+ * @param labels - Optional labels (whitelist enforced: model, type, status)
1747
+ * @param value - Increment value (default: 1)
1748
+ *
1749
+ * @example
1750
+ * ctx.metrics.increment('content_generated', { model: 'gpt-4', status: 'success' });
1751
+ */
1752
+ increment(name: string, labels?: PluginMetricsAllowedLabels, value?: number): void;
1753
+ }
1754
+ /**
1755
+ * Plugin Trace Capability - Read-only trace context access
1756
+ *
1757
+ * Per OBSERVABILITY_GOVERNANCE §5:
1758
+ * - Plugins can only read trace context
1759
+ * - Plugins cannot create spans or modify trace context
1760
+ */
1761
+ interface PluginTraceCapability {
1762
+ /**
1763
+ * Get the current trace ID (W3C format, 32 hex chars)
1764
+ * @returns The trace ID or undefined if not available
1765
+ */
1766
+ getTraceId(): string | undefined;
1767
+ /**
1768
+ * Get the current span ID (16 hex chars)
1769
+ * @returns The span ID or undefined if not available
1770
+ */
1771
+ getSpanId(): string | undefined;
1772
+ }
1773
+ /**
1774
+ * Hook Priority Enum
1775
+ * Controls execution order within a hook
1776
+ */
1777
+ declare enum HookPriority {
1778
+ EARLIEST = 0,// System-level, plugins should not use
1779
+ EARLY = 25,// Plugins needing early execution
1780
+ NORMAL = 50,// Default priority
1781
+ LATE = 75,// Plugins needing late execution
1782
+ LATEST = 100
1783
+ }
1784
+ /**
1785
+ * Hook Handler Options
1786
+ */
1787
+ interface HookHandlerOptions {
1788
+ /** Handler priority (default: NORMAL) */
1789
+ priority?: HookPriority;
1790
+ /** Handler timeout in ms (default: 5000) */
1791
+ timeout?: number;
1792
+ /**
1793
+ * Let this handler read its owning plugin's current-organization data when
1794
+ * invoked by an allowlisted caller plugin. The caller never receives direct
1795
+ * database access; tenant, deny, ABAC, field and audit policies stay active.
1796
+ */
1797
+ organizationRead?: {
1798
+ callers: readonly string[];
1799
+ };
1800
+ }
1801
+ /**
1802
+ * Plugin Hook Capability - Register hook handlers
1803
+ *
1804
+ * Plugins can register handlers for Core-defined hooks to:
1805
+ * - Actions: Perform async side-effects (logging, notifications, external sync)
1806
+ * - Filters: Transform data in the pipeline (validation, enrichment, masking)
1807
+ *
1808
+ * Per EVENT_HOOK_GOVERNANCE (Frozen v1):
1809
+ * - Plugins CANNOT block Core execution (except via HookAbortError in filters)
1810
+ * - Plugins CANNOT access other plugins' handlers
1811
+ */
1812
+ /**
1813
+ * Hook Event Map — Extensible type registry for TypeScript autocompletion
1814
+ *
1815
+ * Plugins can augment this interface to declare their hooks:
1816
+ *
1817
+ * ```typescript
1818
+ * // plugins/crm/src/shared/hook-types.ts
1819
+ * declare module '@wordrhyme/plugin' {
1820
+ * interface HookEventMap {
1821
+ * 'crm.customer.promoted': { customerId: string; organizationId: string };
1822
+ * 'crm.customer.beforeCreate': { name: string; organizationId: string };
1823
+ * 'crm.createProspect': { name: string; organizationId: string; id?: string; status?: string };
1824
+ * }
1825
+ * }
1826
+ * ```
1827
+ *
1828
+ * This enables:
1829
+ * - Hook ID autocompletion in on() and emit()
1830
+ * - Automatic payload type inference
1831
+ */
1832
+ interface HookEventMap {
1833
+ }
1834
+ interface PluginHookCapability {
1835
+ /**
1836
+ * Register a hook handler
1837
+ *
1838
+ * Subscribes to a hook. When someone calls `emit()` for this hookId,
1839
+ * your handler will be called with the data.
1840
+ *
1841
+ * - Handler can optionally return modified data (for pipe mode)
1842
+ * - Handler can throw HookAbortError to abort the operation
1843
+ * - Returns an unsubscribe function
1844
+ *
1845
+ * @param hookId - The hook ID (e.g., 'crm.customer.afterCreate')
1846
+ * @param handler - Handler function, optionally returns modified data
1847
+ * @param options - Handler options (priority, timeout)
1848
+ * @returns Unsubscribe function
1849
+ *
1850
+ * @example
1851
+ * // Notification handler (no return needed)
1852
+ * ctx.hooks.on('crm.customer.promoted', async (data) => {
1853
+ * await sendWelcomeEmail(data.customerId);
1854
+ * });
1855
+ *
1856
+ * @example
1857
+ * // Service handler (returns result)
1858
+ * ctx.hooks.on('crm.createProspect', async (data) => {
1859
+ * const id = await db.insert(customers).values(data);
1860
+ * return { ...data, id, status: 'prospect' };
1861
+ * });
1862
+ *
1863
+ * @example
1864
+ * // Abort handler (blocks operation)
1865
+ * ctx.hooks.on('crm.customer.beforeCreate', async (data) => {
1866
+ * if (!data.name) throw new HookAbortError('名字不能为空');
1867
+ * });
1868
+ */
1869
+ on<K extends keyof HookEventMap>(hookId: K, handler: (data: HookEventMap[K], context: HookContext) => HookEventMap[K] | void | Promise<HookEventMap[K] | void>, options?: HookHandlerOptions): () => void;
1870
+ on<K extends keyof HookEventMap>(hookId: K[], handler: (data: HookEventMap[K], context: HookContext) => HookEventMap[K] | void | Promise<HookEventMap[K] | void>, options?: HookHandlerOptions): () => void;
1871
+ on<T = unknown>(hookId: string, handler: (data: T, context: HookContext) => T | void | Promise<T | void>, options?: HookHandlerOptions): () => void;
1872
+ on<T = unknown>(hookId: string[], handler: (data: T, context: HookContext) => T | void | Promise<T | void>, options?: HookHandlerOptions): () => void;
1873
+ /**
1874
+ * Emit a hook (trigger all registered handlers)
1875
+ *
1876
+ * Default mode: handlers run in **parallel**, return value from the
1877
+ * first handler that returns something (service call pattern).
1878
+ *
1879
+ * Pipe mode (`{ mode: 'pipe' }` or legacy `{ pipe: true }`): handlers run
1880
+ * **serially**, each receives the previous handler's output (data
1881
+ * transformation / synchronous service-call pattern).
1882
+ *
1883
+ * @param hookId - The hook ID
1884
+ * @param data - Data to pass to handlers
1885
+ * @param options - Emit options
1886
+ * @returns The handler result (or original data if no handler returns)
1887
+ *
1888
+ * @example
1889
+ * // Parallel (default) — notification, no return needed
1890
+ * await ctx.hooks.emit('crm.customer.promoted', { customerId: 'xxx' });
1891
+ *
1892
+ * @example
1893
+ * // Parallel — service call, get return value
1894
+ * const customer = await ctx.hooks.emit('crm.createProspect', { name: 'Acme' });
1895
+ *
1896
+ * @example
1897
+ * // Pipe mode — serial data transformation
1898
+ * const enrichedData = await ctx.hooks.emit('crm.customer.beforeCreate', data, { mode: 'pipe' });
1899
+ */
1900
+ emit<K extends keyof HookEventMap>(hookId: K, data: HookEventMap[K], options?: HookEmitOptions): Promise<HookEventMap[K]>;
1901
+ emit<T = unknown>(hookId: string, data: T, options?: HookEmitOptions): Promise<T>;
1902
+ /**
1903
+ * List all available hooks
1904
+ *
1905
+ * Returns the list of hook definitions that plugins can subscribe to.
1906
+ * Useful for discovery and validation.
1907
+ *
1908
+ * @returns Array of hook definitions
1909
+ */
1910
+ listHooks(): Promise<Array<{
1911
+ id: string;
1912
+ description: string;
1913
+ }>>;
1914
+ /** @deprecated Use `on()` instead */
1915
+ addAction<T = unknown>(hookId: string, handler: (data: T, ctx: PluginContext) => void | Promise<void>, options?: HookHandlerOptions): () => void;
1916
+ /** @deprecated Use `on()` instead */
1917
+ addFilter<T = unknown>(hookId: string, handler: (data: T, ctx: PluginContext) => T | Promise<T>, options?: HookHandlerOptions): () => void;
1918
+ /** @deprecated Use `emit(hookId, data, { pipe: true })` instead */
1919
+ applyFilter<T = unknown>(hookId: string, initialValue: T): Promise<T>;
1920
+ }
1921
+ /**
1922
+ * Hook emit options
1923
+ */
1924
+ interface HookEmitOptions {
1925
+ /**
1926
+ * Emit mode.
1927
+ * - `event` (default): parallel fire-and-forget / first-result-wins
1928
+ * - `pipe`: serial synchronous pipeline, fail-fast on handler error
1929
+ * - `effect`: serial synchronous effects, fail-fast, ignores handler return values
1930
+ */
1931
+ mode?: "event" | "pipe" | "effect";
1932
+ /**
1933
+ * Dispatch intent.
1934
+ * - `auto` (default): command-like bare ids may route to pluginApis.
1935
+ * - `command`: only route to the matching pluginApis procedure.
1936
+ * - `hook`: only notify registered hook listeners.
1937
+ */
1938
+ dispatch?: "auto" | "command" | "hook";
1939
+ /**
1940
+ * Shared database transaction.
1941
+ *
1942
+ * Only valid with `mode: 'pipe'` because event mode is intentionally
1943
+ * fire-and-forget and does not provide transactional guarantees.
1944
+ */
1945
+ tx?: any;
1946
+ /**
1947
+ * Request user id to pass through to synchronous hook handlers.
1948
+ */
1949
+ userId?: string;
1950
+ /** @deprecated Use `mode: 'pipe'` instead. Kept for backward compatibility. */
1951
+ pipe?: boolean;
1952
+ }
1953
+ interface HookTransaction {
1954
+ run<T>(callback: (db: NonNullable<PluginContext["db"]>) => Promise<T>): Promise<T>;
1955
+ }
1956
+ interface HookContext {
1957
+ id: string;
1958
+ hookId: string;
1959
+ traceId?: string;
1960
+ /** Plugin that emitted the current hook. Host supplied and not payload controlled. */
1961
+ sourcePluginId?: string | undefined;
1962
+ pluginId: string;
1963
+ organizationId?: string | undefined;
1964
+ userId?: string | undefined;
1965
+ tx?: HookTransaction | undefined;
1966
+ }
1967
+ /**
1968
+ * Hook Abort Error - Thrown by filters to block operations
1969
+ *
1970
+ * When a filter handler throws this error, the operation is aborted
1971
+ * and the error message is returned to the caller.
1972
+ */
1973
+ declare class HookAbortError extends Error {
1974
+ constructor(message: string);
1975
+ }
1976
+ /**
1977
+ * Plugin Usage Capability - Explicit billing consumption
1978
+ *
1979
+ * Used by plugins that need dynamic consumption amounts per request
1980
+ * (e.g., token count, file size MB). For fixed consumption (1 unit per call),
1981
+ * use manifest `capabilities.billing.procedures` instead (zero-code).
1982
+ */
1983
+ interface PluginUsageCapability {
1984
+ /**
1985
+ * Consume usage for a specific billing subject
1986
+ *
1987
+ * @param subject - Billing capability subject (must use {pluginId}.* prefix)
1988
+ * @param amount - Amount to consume (default: 1)
1989
+ * @throws EntitlementDeniedError if capability not approved or no quota
1990
+ */
1991
+ consume(subject: string, amount?: number): Promise<void>;
1992
+ }
1993
+ type ApiPayload<T> = {
1994
+ [K in keyof T]: T[K] extends Date ? string : T[K] extends Date | null ? string | null : T[K] extends Date | undefined ? string | undefined : T[K];
1995
+ };
1996
+
1997
+ export { type PluginActionInvokerCapability as $, type ActionContractMeta as A, type ApiPayload as B, type EAuthProvider as C, type EAuthRefreshInput as D, type EAuthModel as E, type EAuthRefreshResult as F, type EAuthStatus as G, type HookContext as H, type EAuthTokenResult as I, type EAuthUpsertInput as J, type EAuthUse as K, HookAbortError as L, type HookEmitOptions as M, HookPriority as N, MARKETPLACE_PUBLISH_AUTH_METHODS as O, type PluginMediaInfo as P, type MarketplaceAttestationTargetV1 as Q, type MarketplaceExecutionErrorCode as R, type MarketplaceExecutionFailureCode as S, type MarketplaceOrganizationExecutionV1 as T, type MarketplacePlatformReadAction as U, type MarketplacePublishActor as V, type WebSlotRemoteExtension as W, type MarketplacePublishAuthMethod as X, type MarketplacePublisherAction as Y, type MarketplaceRegistrySigningCapability as Z, type OpaquePublisherCandidateV1 as _, type PluginContext as a, type WebPluginHead as a$, type PluginAgentCapability as a0, type PluginAiCapability as a1, type PluginAiRuntimeCapability as a2, type PluginApisCapability as a3, type PluginArtifactCapability as a4, type PluginAssetCapability as a5, type PluginAssetCreateOptions as a6, type PluginAssetInfo as a7, type PluginAssetQuery as a8, type PluginAssetUpdateData as a9, type PluginNotificationSendResult as aA, type PluginNotificationTarget as aB, type PluginNotificationTemplate as aC, type PluginOrganizationMembersCapability as aD, type PluginOrganizationProvisioningCapability as aE, type PluginPaginatedResult as aF, type PluginPermissionCapability as aG, type PluginPermissionCheckContext as aH, type PluginPermissionDef as aI, type PluginQueueCapability as aJ, type PluginScopedDb as aK, type PluginSettingEntry as aL, type PluginSettingOptions as aM, type PluginSettingsCapability as aN, type PluginStorageCapability as aO, type PluginStorageProvider as aP, type PluginStorageProviderConfig as aQ, type PluginStorageProviderInfo as aR, type PluginStorageUploadInput as aS, type PluginStorageUploadResult as aT, type PluginTraceCapability as aU, type PluginUsageCapability as aV, type PluginWebCapability as aW, type ReadonlyPluginScopedDb as aX, type WebJsonPrimitive as aY, type WebJsonValue as aZ, type WebPluginDocumentMode as a_, type PluginAssetVariant as aa, type PluginCurrencyCapability as ab, type PluginEAuthCapability as ac, type PluginEntityExtensionCapability as ad, type PluginEntityExtensionFilter as ae, type PluginFileCapability as af, type PluginFileInfo as ag, type PluginFileQuery as ah, type PluginFileUploadInput as ai, type PluginHookCapability as aj, type PluginJobOptions as ak, type PluginJobStatus as al, type PluginMediaCapability as am, type PluginMediaQuery as an, type PluginMediaUpdateData as ao, type PluginMediaUploadInput as ap, type PluginMediaVariant as aq, type PluginMetricsAllowedLabels as ar, type PluginMetricsCapability as as, type PluginNotificationActor as at, type PluginNotificationCapability as au, type PluginNotificationChannel as av, type PluginNotificationEvent as aw, type PluginNotificationInput as ax, type PluginNotificationResult as ay, type PluginNotificationSendParams as az, type HookHandlerOptions as b, type WebPluginHeadLink as b0, type WebPluginPresentationSurfaceResult as b1, type WebPluginRouteHandler as b2, type WebPluginRouteRequest as b3, type WebPluginRouteResult as b4, type WebPluginTenantInfo as b5, type WebPresentationAdapterClientDescriptor as b6, type WebResolvedPresentationAdapter as b7, type WebResolvedSitePresentation as b8, type WebResolvedSiteShell as b9, type WebResolvedThemeAsset as ba, type WebSerializableGlobalizationState as bb, type WebSlotExtensionQuery as bc, type WebSlotQueryResult as bd, type WebSlotRenderMode as be, type WebSlotRenderOptions as bf, type WebSlotRenderRequest as bg, type WebSlotRenderResult as bh, type WebSlotRenderer as bi, type WebThemeShellClientDescriptor as bj, type WebThemeShellDocumentModel as bk, type WebThemeShellRenderResult as bl, type WebThemeShellRenderer as bm, type WebThemeShellRouteModel as bn, type HookTransaction as c, type PluginLogger as d, type WebPluginSiteInfo as e, type ActionDescriptor as f, type ActionInvokeRequest as g, type AgentToolDescriptor as h, type AiAliasDescriptor as i, type AiBudget as j, type AiModelCatalog as k, type AiModelHint as l, type AiModelListRequest as m, type AiModelOption as n, type AiObjectRequest as o, type AiObjectResult as p, type AiObjectSchema as q, type AiRuntimeHandler as r, type AiRuntimeHost as s, type AiRuntimeInvocation as t, type AiStreamEvent as u, type AiTextRequest as v, type AiTextResult as w, type AiUsage as x, type AiUsageAuthorization as y, type AiUsageObservation as z };