@wordrhyme/plugin 0.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/index.d.ts +19 -0
- package/dist/admin/index.js +42 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/artifact.d.ts +17 -0
- package/dist/artifact.js +96 -0
- package/dist/artifact.js.map +1 -0
- package/dist/chunk-46KUIGB6.js +230 -0
- package/dist/chunk-46KUIGB6.js.map +1 -0
- package/dist/chunk-6GDCFR67.js +218 -0
- package/dist/chunk-6GDCFR67.js.map +1 -0
- package/dist/chunk-DY44Q4CK.js +188 -0
- package/dist/chunk-DY44Q4CK.js.map +1 -0
- package/dist/chunk-MZOLSLJ7.js +65 -0
- package/dist/chunk-MZOLSLJ7.js.map +1 -0
- package/dist/chunk-QNCOGISF.js +694 -0
- package/dist/chunk-QNCOGISF.js.map +1 -0
- package/dist/chunk-UGMYO6AU.js +37 -0
- package/dist/chunk-UGMYO6AU.js.map +1 -0
- package/dist/chunk-YQDKOEUI.js +242 -0
- package/dist/chunk-YQDKOEUI.js.map +1 -0
- package/dist/chunk-ZUBFLOKU.js +153 -0
- package/dist/chunk-ZUBFLOKU.js.map +1 -0
- package/dist/client-WXWbuuvd.d.ts +100 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +29 -0
- package/dist/client.js.map +1 -0
- package/dist/dev-utils.d.ts +68 -0
- package/dist/dev-utils.js +21 -0
- package/dist/dev-utils.js.map +1 -0
- package/dist/entity-extensions-B5BbZH-m.d.ts +56 -0
- package/dist/globalization.d.ts +80 -0
- package/dist/globalization.js +43 -0
- package/dist/globalization.js.map +1 -0
- package/dist/index.d.ts +316 -0
- package/dist/index.js +354 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest-CPSCN_Ft.d.ts +1471 -0
- package/dist/react.d.ts +145 -0
- package/dist/react.js +94 -0
- package/dist/react.js.map +1 -0
- package/dist/release-CyapqJ3z.d.ts +230 -0
- package/dist/server.d.ts +114 -0
- package/dist/server.js +194 -0
- package/dist/server.js.map +1 -0
- package/dist/time.d.ts +34 -0
- package/dist/time.js +31 -0
- package/dist/time.js.map +1 -0
- package/dist/trpc.d.ts +43 -0
- package/dist/trpc.js +11 -0
- package/dist/trpc.js.map +1 -0
- package/dist/types-8P7XyoyQ.d.ts +1599 -0
- package/package.json +83 -0
|
@@ -0,0 +1,1599 @@
|
|
|
1
|
+
import { GlobalizationState } from './globalization.js';
|
|
2
|
+
import { R as RegistryReleaseEnvelope, a as RegistrySignature, b as RegistryCatalogPageEnvelope } from './release-CyapqJ3z.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
|
+
/** Current organization ID (from request context) */
|
|
18
|
+
organizationId?: string | undefined;
|
|
19
|
+
/** Original organization ID before any infrastructure policy context swap */
|
|
20
|
+
originalOrganizationId?: string | undefined;
|
|
21
|
+
/** Current user ID (from request context) */
|
|
22
|
+
userId?: string | undefined;
|
|
23
|
+
/** Current user profile snapshot from request context */
|
|
24
|
+
user?: {
|
|
25
|
+
id: string;
|
|
26
|
+
name?: string;
|
|
27
|
+
email?: string;
|
|
28
|
+
} | undefined;
|
|
29
|
+
/** Request/correlation ID from the host runtime */
|
|
30
|
+
requestId?: string | undefined;
|
|
31
|
+
/** Current user's primary role and expanded role set */
|
|
32
|
+
userRole?: string | undefined;
|
|
33
|
+
userRoles?: string[] | undefined;
|
|
34
|
+
/** Current team context for team-level permissions */
|
|
35
|
+
currentTeamId?: string | undefined;
|
|
36
|
+
/** Locale/timezone resolved by the host runtime */
|
|
37
|
+
locale?: string | undefined;
|
|
38
|
+
timezone?: string | undefined;
|
|
39
|
+
/** Client-reported timezone; business logic must not treat it as authoritative. */
|
|
40
|
+
clientTimeZone?: string | undefined;
|
|
41
|
+
/** Host-provided calendar-date resolver for shared query infrastructure. */
|
|
42
|
+
resolveDateRange?: DateRangeResolver | undefined;
|
|
43
|
+
/** Host-provided actor metadata; runtime plugin contexts resolve to `plugin`. */
|
|
44
|
+
actorType?: "plugin" | undefined;
|
|
45
|
+
apiTokenId?: string | undefined;
|
|
46
|
+
apiTokenScopes?: string[] | undefined;
|
|
47
|
+
isSystemContext?: false | undefined;
|
|
48
|
+
principal?: {
|
|
49
|
+
kind: "plugin";
|
|
50
|
+
id: string;
|
|
51
|
+
pluginId: string;
|
|
52
|
+
} | undefined;
|
|
53
|
+
invoker?: string | undefined;
|
|
54
|
+
/** Scoped logger */
|
|
55
|
+
logger: PluginLogger;
|
|
56
|
+
/**
|
|
57
|
+
* Drizzle-compatible ScopedDb bound to the plugin's private table prefix.
|
|
58
|
+
* Automatically enforces LBAC, tenant filtering, auditing, and plugin table isolation.
|
|
59
|
+
*/
|
|
60
|
+
db: PluginScopedDb;
|
|
61
|
+
/** Host-only Marketplace execution boundary for platform reads and Publisher callbacks. */
|
|
62
|
+
marketplaceOrganizationExecution?: MarketplaceOrganizationExecutionV1 | undefined;
|
|
63
|
+
/** Authenticated upload actor supplied by the Host; never derived from request payloads. */
|
|
64
|
+
marketplacePublishActor?: MarketplacePublishActor | undefined;
|
|
65
|
+
/** Host-only Registry signing boundary. The private key never enters plugin settings or storage. */
|
|
66
|
+
marketplaceRegistrySigner?: MarketplaceRegistrySigningCapability | undefined;
|
|
67
|
+
/** Host-configured public Marketplace origin; null means production configuration is missing. */
|
|
68
|
+
marketplaceRegistryBaseUrl?: string | null | undefined;
|
|
69
|
+
/** Host-mediated Core organization creation for explicitly trusted plugins. */
|
|
70
|
+
organizationProvisioning?: PluginOrganizationProvisioningCapability | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Shared database transaction for synchronous cross-plugin pipe calls.
|
|
73
|
+
*
|
|
74
|
+
* When present, plugin code may use this transaction to participate in the
|
|
75
|
+
* caller's outer SQL transaction instead of opening an independent one.
|
|
76
|
+
*/
|
|
77
|
+
tx?: any;
|
|
78
|
+
/** Permission capability */
|
|
79
|
+
permissions: PluginPermissionCapability;
|
|
80
|
+
/** Public plugin API caller alias over the host's pluginApis route tree */
|
|
81
|
+
plugins?: PluginApisCapability | undefined;
|
|
82
|
+
/** Queue capability (for async job processing) */
|
|
83
|
+
queue?: PluginQueueCapability | undefined;
|
|
84
|
+
/** Notification capability (for sending notifications) */
|
|
85
|
+
notifications?: PluginNotificationCapability | undefined;
|
|
86
|
+
/** Settings capability (for plugin configuration) */
|
|
87
|
+
settings: PluginSettingsCapability;
|
|
88
|
+
/** Currency capability (for effective organization currency/rate access) */
|
|
89
|
+
currency?: PluginCurrencyCapability | undefined;
|
|
90
|
+
/** Media capability (for unified file and asset management) */
|
|
91
|
+
media?: PluginMediaCapability | undefined;
|
|
92
|
+
/** Storage capability (for registering custom storage providers) */
|
|
93
|
+
storage?: PluginStorageCapability | undefined;
|
|
94
|
+
/** Opaque plugin artifact storage for explicitly approved first-party workflows. */
|
|
95
|
+
artifacts?: PluginArtifactCapability | undefined;
|
|
96
|
+
/** Metrics capability (for recording usage metrics) */
|
|
97
|
+
metrics?: PluginMetricsCapability | undefined;
|
|
98
|
+
/** Trace capability (for accessing trace context) */
|
|
99
|
+
trace?: PluginTraceCapability | undefined;
|
|
100
|
+
/** Hook capability (for registering hook handlers) */
|
|
101
|
+
hooks?: PluginHookCapability | undefined;
|
|
102
|
+
/** Usage capability (for explicit billing consumption in dynamic scenarios) */
|
|
103
|
+
usage?: PluginUsageCapability | undefined;
|
|
104
|
+
/** External authorization capability for tenant platform/API connections */
|
|
105
|
+
eAuth?: PluginEAuthCapability | undefined;
|
|
106
|
+
/** Entity extension capability (Core-mediated extension value persistence) */
|
|
107
|
+
entityExtensions?: PluginEntityExtensionCapability | undefined;
|
|
108
|
+
/** Generic AutoCrud extension provider injected by the host runtime. */
|
|
109
|
+
crudExtensions?: PluginCrudExtensionsCapability | undefined;
|
|
110
|
+
/** Public web surface capability injected for plugin-owned web route handlers. */
|
|
111
|
+
web?: PluginWebCapability | undefined;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Public SDK shape for the Host-provided Drizzle-compatible database.
|
|
115
|
+
*
|
|
116
|
+
* The concrete type deliberately remains structural so plugin packages do not
|
|
117
|
+
* depend on Server internals. Runtime enforcement is provided by ScopedDb.
|
|
118
|
+
*/
|
|
119
|
+
interface PluginScopedDb {
|
|
120
|
+
readonly query: any;
|
|
121
|
+
/** @deprecated Prefer the v2 object-style `query` API. */
|
|
122
|
+
readonly _query: any;
|
|
123
|
+
select(...args: any[]): any;
|
|
124
|
+
selectDistinct(...args: any[]): any;
|
|
125
|
+
selectDistinctOn(...args: any[]): any;
|
|
126
|
+
insert(table: any): any;
|
|
127
|
+
update(table: any): any;
|
|
128
|
+
delete(table: any, options?: {
|
|
129
|
+
softDelete?: false;
|
|
130
|
+
}): any;
|
|
131
|
+
$count(source: any, filters?: any): PromiseLike<number> & {
|
|
132
|
+
execute(placeholderValues?: Record<string, unknown>): Promise<number>;
|
|
133
|
+
};
|
|
134
|
+
transaction<T>(callback: (tx: PluginScopedDb) => Promise<T>, options?: unknown): Promise<T>;
|
|
135
|
+
forOrganization<T>(organizationId: string, callback: (db: PluginScopedDb) => Promise<T> | T): Promise<T>;
|
|
136
|
+
}
|
|
137
|
+
interface ReadonlyPluginScopedDb {
|
|
138
|
+
readonly query: any;
|
|
139
|
+
/** @deprecated Prefer the v2 object-style `query` API. */
|
|
140
|
+
readonly _query: any;
|
|
141
|
+
select(...args: any[]): any;
|
|
142
|
+
selectDistinct(...args: any[]): any;
|
|
143
|
+
selectDistinctOn(...args: any[]): any;
|
|
144
|
+
$count(source: any, filters?: any): PromiseLike<number> & {
|
|
145
|
+
execute(placeholderValues?: Record<string, unknown>): Promise<number>;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
type MarketplacePlatformReadAction = "route" | "review-list" | "attestation-target" | "catalog";
|
|
149
|
+
type MarketplacePublisherAction = "publish" | "review-command" | "release-attest" | "profile-manage";
|
|
150
|
+
type MarketplaceExecutionErrorCode = "MARKETPLACE_EXECUTION_ACTION_DENIED" | "MARKETPLACE_PUBLISHER_UNAVAILABLE";
|
|
151
|
+
type MarketplaceExecutionFailureCode = MarketplaceExecutionErrorCode | "PLUGIN_DB_SCOPE_EXPIRED";
|
|
152
|
+
declare const MARKETPLACE_PUBLISH_AUTH_METHODS: readonly ["portal-session", "scoped-api-key"];
|
|
153
|
+
type MarketplacePublishAuthMethod = (typeof MARKETPLACE_PUBLISH_AUTH_METHODS)[number];
|
|
154
|
+
interface MarketplacePublishActor {
|
|
155
|
+
actorId: string;
|
|
156
|
+
authenticationMethod: MarketplacePublishAuthMethod;
|
|
157
|
+
authenticatedAt: string;
|
|
158
|
+
credentialId?: string | undefined;
|
|
159
|
+
}
|
|
160
|
+
interface MarketplaceRegistrySigningCapability {
|
|
161
|
+
/** Serialize Catalog generations and Release projection changes on the Registry database clock. */
|
|
162
|
+
withCatalogGeneration<T>(run: (generatedAt: string) => Promise<T>): Promise<T>;
|
|
163
|
+
sign(targetId: string, envelope: RegistryReleaseEnvelope): Promise<RegistrySignature>;
|
|
164
|
+
signCatalog(envelope: RegistryCatalogPageEnvelope): Promise<RegistrySignature>;
|
|
165
|
+
}
|
|
166
|
+
interface MarketplaceAttestationTargetV1 {
|
|
167
|
+
organizationId: string;
|
|
168
|
+
targetId: string;
|
|
169
|
+
envelopeSha256: string;
|
|
170
|
+
}
|
|
171
|
+
declare const publisherCandidateBrand: unique symbol;
|
|
172
|
+
interface OpaquePublisherCandidateV1 {
|
|
173
|
+
readonly [publisherCandidateBrand]: true;
|
|
174
|
+
}
|
|
175
|
+
interface MarketplaceOrganizationExecutionV1 {
|
|
176
|
+
withPlatformRead(ctx: PluginContext, action: "route", run: (db: ReadonlyPluginScopedDb) => Promise<string | undefined>): Promise<OpaquePublisherCandidateV1 | undefined>;
|
|
177
|
+
withPlatformRead(ctx: PluginContext, action: "review-list", run: (db: ReadonlyPluginScopedDb) => Promise<string | undefined>): Promise<OpaquePublisherCandidateV1 | undefined>;
|
|
178
|
+
withPlatformRead(ctx: PluginContext, action: "attestation-target", run: (db: ReadonlyPluginScopedDb) => Promise<MarketplaceAttestationTargetV1 | undefined>): Promise<OpaquePublisherCandidateV1 | undefined>;
|
|
179
|
+
withPlatformRead<T>(ctx: PluginContext, action: Exclude<MarketplacePlatformReadAction, "route" | "attestation-target">, run: (db: ReadonlyPluginScopedDb) => Promise<T>): Promise<T>;
|
|
180
|
+
withPublisher<T>(ctx: PluginContext, binding: "current" | OpaquePublisherCandidateV1, action: MarketplacePublisherAction, run: (db: PluginScopedDb) => Promise<T>): Promise<T>;
|
|
181
|
+
}
|
|
182
|
+
interface PluginOrganizationProvisioningCapability {
|
|
183
|
+
provision(input: {
|
|
184
|
+
name: string;
|
|
185
|
+
idempotencyKey: string;
|
|
186
|
+
transaction: PluginScopedDb;
|
|
187
|
+
metadata?: Record<string, string | number | boolean | null> | undefined;
|
|
188
|
+
}): Promise<{
|
|
189
|
+
id: string;
|
|
190
|
+
name: string;
|
|
191
|
+
slug: string;
|
|
192
|
+
status: "created" | "existing";
|
|
193
|
+
}>;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Framework-neutral request envelope for plugin-owned public web routes.
|
|
197
|
+
*
|
|
198
|
+
* This contract intentionally avoids Next.js, Pages Router, App Router, RSC,
|
|
199
|
+
* TanStack Router, or any other host-specific request type. Host adapters
|
|
200
|
+
* translate their native request shape into this envelope before invoking a
|
|
201
|
+
* plugin web handler.
|
|
202
|
+
*/
|
|
203
|
+
interface WebPluginRouteRequest {
|
|
204
|
+
url: string;
|
|
205
|
+
method: string;
|
|
206
|
+
headers: Record<string, string>;
|
|
207
|
+
cookies: Record<string, string>;
|
|
208
|
+
path: string;
|
|
209
|
+
query: Record<string, string | string[]>;
|
|
210
|
+
organizationId: string;
|
|
211
|
+
locale?: string | undefined;
|
|
212
|
+
direction?: GlobalizationState["direction"] | undefined;
|
|
213
|
+
currency?: string | undefined;
|
|
214
|
+
timezone?: string | undefined;
|
|
215
|
+
globalization?: GlobalizationState | undefined;
|
|
216
|
+
tenant?: WebPluginTenantInfo | undefined;
|
|
217
|
+
site?: WebPluginSiteInfo | undefined;
|
|
218
|
+
renderSlot?: WebSlotRenderer | undefined;
|
|
219
|
+
}
|
|
220
|
+
interface WebSlotRenderRequest {
|
|
221
|
+
slot: string;
|
|
222
|
+
props?: Record<string, unknown> | undefined;
|
|
223
|
+
targetPluginId?: string | undefined;
|
|
224
|
+
routeId?: string | undefined;
|
|
225
|
+
}
|
|
226
|
+
interface WebSlotRenderOptions {
|
|
227
|
+
slot: string;
|
|
228
|
+
props?: Record<string, unknown> | undefined;
|
|
229
|
+
ownerPluginId?: string | undefined;
|
|
230
|
+
routeId?: string | undefined;
|
|
231
|
+
}
|
|
232
|
+
interface WebSlotExtensionQuery {
|
|
233
|
+
id: string;
|
|
234
|
+
procedure: string;
|
|
235
|
+
inputFrom?: "slotProps" | "static" | undefined;
|
|
236
|
+
staticInput?: Record<string, unknown> | undefined;
|
|
237
|
+
}
|
|
238
|
+
interface WebSlotQueryResult {
|
|
239
|
+
id: string;
|
|
240
|
+
procedure: string;
|
|
241
|
+
data?: unknown;
|
|
242
|
+
error?: string | undefined;
|
|
243
|
+
}
|
|
244
|
+
interface WebSlotRemoteExtension {
|
|
245
|
+
id: string;
|
|
246
|
+
pluginId: string;
|
|
247
|
+
label?: string | undefined;
|
|
248
|
+
component: string;
|
|
249
|
+
slot: string;
|
|
250
|
+
targetPluginId: string;
|
|
251
|
+
props: Record<string, unknown>;
|
|
252
|
+
remoteEntry: string;
|
|
253
|
+
devRemoteEntry?: string | undefined;
|
|
254
|
+
moduleName?: string | undefined;
|
|
255
|
+
expose?: string | undefined;
|
|
256
|
+
order?: number | undefined;
|
|
257
|
+
queries?: WebSlotExtensionQuery[] | undefined;
|
|
258
|
+
queryResults?: WebSlotQueryResult[] | undefined;
|
|
259
|
+
}
|
|
260
|
+
interface WebSlotRenderResult {
|
|
261
|
+
html: string;
|
|
262
|
+
extensions?: WebSlotRemoteExtension[] | undefined;
|
|
263
|
+
head?: WebPluginHead | undefined;
|
|
264
|
+
initialData?: Record<string, unknown> | undefined;
|
|
265
|
+
clientEntries?: string[] | undefined;
|
|
266
|
+
}
|
|
267
|
+
type WebSlotRenderer = (request: WebSlotRenderRequest) => WebSlotRenderResult | Promise<WebSlotRenderResult>;
|
|
268
|
+
interface PluginWebCapability {
|
|
269
|
+
renderSlot(options: WebSlotRenderOptions): WebSlotRenderResult | Promise<WebSlotRenderResult>;
|
|
270
|
+
}
|
|
271
|
+
interface WebPluginTenantInfo {
|
|
272
|
+
organizationId: string;
|
|
273
|
+
name: string;
|
|
274
|
+
slug?: string | undefined;
|
|
275
|
+
logo?: string | null | undefined;
|
|
276
|
+
}
|
|
277
|
+
interface WebPluginSiteInfo {
|
|
278
|
+
mode: "custom-domain" | "platform-subdomain" | "platform-path" | "internal-override";
|
|
279
|
+
basePath: string;
|
|
280
|
+
publicOrigin?: string | undefined;
|
|
281
|
+
host?: string | undefined;
|
|
282
|
+
}
|
|
283
|
+
interface WebPluginHeadLink {
|
|
284
|
+
rel: string;
|
|
285
|
+
href: string;
|
|
286
|
+
as?: string | undefined;
|
|
287
|
+
type?: string | undefined;
|
|
288
|
+
}
|
|
289
|
+
interface WebPluginHead {
|
|
290
|
+
title?: string | undefined;
|
|
291
|
+
description?: string | undefined;
|
|
292
|
+
meta?: Record<string, string> | undefined;
|
|
293
|
+
links?: WebPluginHeadLink[] | undefined;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Framework-neutral SSR result returned by a plugin web handler.
|
|
297
|
+
*
|
|
298
|
+
* Redirects are represented as a 3xx status plus a `location` header so every
|
|
299
|
+
* host adapter can map them into its own redirect primitive.
|
|
300
|
+
*/
|
|
301
|
+
interface WebPluginRouteResult {
|
|
302
|
+
status: number;
|
|
303
|
+
headers?: Record<string, string> | undefined;
|
|
304
|
+
head?: WebPluginHead | undefined;
|
|
305
|
+
html?: string | undefined;
|
|
306
|
+
initialData?: unknown;
|
|
307
|
+
clientEntry?: string | undefined;
|
|
308
|
+
clientEntries?: string[] | undefined;
|
|
309
|
+
slotExtensions?: WebSlotRemoteExtension[] | undefined;
|
|
310
|
+
routeId?: string | undefined;
|
|
311
|
+
globalization?: GlobalizationState | undefined;
|
|
312
|
+
site?: WebPluginSiteInfo | undefined;
|
|
313
|
+
}
|
|
314
|
+
type WebPluginRouteHandler<TContext extends PluginContext = PluginContext> = (request: WebPluginRouteRequest, context: TContext) => WebPluginRouteResult | Promise<WebPluginRouteResult>;
|
|
315
|
+
/**
|
|
316
|
+
* Plugin Permission Definition (CASL format)
|
|
317
|
+
*
|
|
318
|
+
* Defines a permission that a plugin registers for use in the CASL permission system.
|
|
319
|
+
* Plugins use this to declare what permissions they provide.
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* // Simple permission (manage is default action)
|
|
323
|
+
* { subject: 'settings' }
|
|
324
|
+
*
|
|
325
|
+
* // Permission with specific actions
|
|
326
|
+
* { subject: 'analytics', actions: ['read', 'export'] }
|
|
327
|
+
*
|
|
328
|
+
* // Permission with field-level access
|
|
329
|
+
* { subject: 'report', actions: ['read'], fields: ['summary', 'chart'] }
|
|
330
|
+
*/
|
|
331
|
+
interface PluginPermissionDef {
|
|
332
|
+
/** Subject name (will be prefixed with plugin:{pluginId}:) */
|
|
333
|
+
subject: string;
|
|
334
|
+
/** Actions supported (default: ['manage']) */
|
|
335
|
+
actions?: string[];
|
|
336
|
+
/** Field-level restrictions (default: null = all fields) */
|
|
337
|
+
fields?: string[] | null;
|
|
338
|
+
/** Human-readable description for Admin UI */
|
|
339
|
+
description?: string;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Plugin Logger - Scoped logging interface
|
|
343
|
+
*
|
|
344
|
+
* Per OBSERVABILITY_GOVERNANCE §3.3:
|
|
345
|
+
* - info, warn, error: Always available
|
|
346
|
+
* - debug: Optional, only available when explicitly enabled by tenant admin
|
|
347
|
+
*/
|
|
348
|
+
interface PluginLogger {
|
|
349
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
350
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
351
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
352
|
+
/**
|
|
353
|
+
* Debug logging - only available when debug mode is enabled by tenant admin.
|
|
354
|
+
* Calls are silently ignored when debug mode is disabled.
|
|
355
|
+
*/
|
|
356
|
+
debug?(message: string, meta?: Record<string, unknown>): void;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Plugin Permission Capability - Permission checking interface
|
|
360
|
+
*
|
|
361
|
+
* All permission checks are scoped to:
|
|
362
|
+
* - Permissions declared in the plugin manifest
|
|
363
|
+
* - Permissions granted to the current user
|
|
364
|
+
*/
|
|
365
|
+
interface PluginPermissionCapability {
|
|
366
|
+
/**
|
|
367
|
+
* Check if current user has a capability
|
|
368
|
+
* @param capability - Capability in format `resource:action:scope`
|
|
369
|
+
* @param context - Optional context override for checks that resolve tenant or role after request setup
|
|
370
|
+
* @returns true if allowed, false if denied
|
|
371
|
+
*/
|
|
372
|
+
can(capability: string, context?: PluginPermissionCheckContext): Promise<boolean>;
|
|
373
|
+
/**
|
|
374
|
+
* Require a capability - throws if denied
|
|
375
|
+
* @param capability - Capability to require
|
|
376
|
+
* @param context - Optional context override for checks that resolve tenant or role after request setup
|
|
377
|
+
* @throws PermissionDeniedError if permission denied
|
|
378
|
+
*/
|
|
379
|
+
require(capability: string, context?: PluginPermissionCheckContext): Promise<void>;
|
|
380
|
+
/**
|
|
381
|
+
* Check if plugin has access to a capability
|
|
382
|
+
* (Plugin must have declared this capability in manifest)
|
|
383
|
+
* @param capability - Capability to check
|
|
384
|
+
*/
|
|
385
|
+
hasDeclared(capability: string): boolean;
|
|
386
|
+
}
|
|
387
|
+
interface PluginPermissionCheckContext {
|
|
388
|
+
requestId?: string | undefined;
|
|
389
|
+
organizationId?: string | undefined;
|
|
390
|
+
userId?: string | undefined;
|
|
391
|
+
userRole?: string | undefined;
|
|
392
|
+
userRoles?: string[] | undefined;
|
|
393
|
+
currentTeamId?: string | undefined;
|
|
394
|
+
actorType?: PluginContext["actorType"] | undefined;
|
|
395
|
+
apiTokenId?: string | undefined;
|
|
396
|
+
apiTokenScopes?: string[] | undefined;
|
|
397
|
+
}
|
|
398
|
+
type PluginApisCapability = Record<string, any>;
|
|
399
|
+
type EAuthModel = "oauth_refresh" | "api_key" | "hmac" | "token" | "amazon_spapi";
|
|
400
|
+
type EAuthStatus = "ok" | "reauth" | "retry";
|
|
401
|
+
type EAuthUse = "products" | "orders" | "fulfillment" | "test" | string;
|
|
402
|
+
type EAuthTokenResult = {
|
|
403
|
+
status: "ok";
|
|
404
|
+
accessToken: string;
|
|
405
|
+
accessTokenExpiresAt?: Date | undefined;
|
|
406
|
+
} | {
|
|
407
|
+
status: "reauth";
|
|
408
|
+
code: string;
|
|
409
|
+
message: string;
|
|
410
|
+
} | {
|
|
411
|
+
status: "retry";
|
|
412
|
+
code: string;
|
|
413
|
+
message: string;
|
|
414
|
+
retryAt?: Date | undefined;
|
|
415
|
+
};
|
|
416
|
+
interface EAuthRefreshInput {
|
|
417
|
+
refreshToken: string;
|
|
418
|
+
accountId: string;
|
|
419
|
+
meta?: Record<string, unknown> | undefined;
|
|
420
|
+
}
|
|
421
|
+
interface EAuthRefreshResult {
|
|
422
|
+
accessToken: string;
|
|
423
|
+
refreshToken?: string | undefined;
|
|
424
|
+
accessTokenExpiresAt?: Date | undefined;
|
|
425
|
+
refreshTokenExpiresAt?: Date | undefined;
|
|
426
|
+
scope?: string | undefined;
|
|
427
|
+
meta?: Record<string, unknown> | undefined;
|
|
428
|
+
}
|
|
429
|
+
interface EAuthProvider {
|
|
430
|
+
refresh(input: EAuthRefreshInput): Promise<EAuthRefreshResult>;
|
|
431
|
+
}
|
|
432
|
+
interface EAuthUpsertInput {
|
|
433
|
+
id?: string | undefined;
|
|
434
|
+
model: EAuthModel;
|
|
435
|
+
connectionId: string;
|
|
436
|
+
accountId: string;
|
|
437
|
+
accessToken?: string | undefined;
|
|
438
|
+
refreshToken?: string | undefined;
|
|
439
|
+
accessTokenExpiresAt?: Date | undefined;
|
|
440
|
+
refreshTokenExpiresAt?: Date | undefined;
|
|
441
|
+
scope?: string | undefined;
|
|
442
|
+
status?: EAuthStatus | undefined;
|
|
443
|
+
meta?: Record<string, unknown> | undefined;
|
|
444
|
+
}
|
|
445
|
+
interface PluginEAuthCapability {
|
|
446
|
+
registerProvider(provider: EAuthProvider): void;
|
|
447
|
+
upsert(input: EAuthUpsertInput): Promise<{
|
|
448
|
+
id: string;
|
|
449
|
+
}>;
|
|
450
|
+
token(input: {
|
|
451
|
+
eauthId: string;
|
|
452
|
+
use?: EAuthUse | undefined;
|
|
453
|
+
}): Promise<EAuthTokenResult>;
|
|
454
|
+
}
|
|
455
|
+
interface PluginCurrencyCapability {
|
|
456
|
+
/**
|
|
457
|
+
* Get enabled currencies with effective current rates in the current tenant context.
|
|
458
|
+
*
|
|
459
|
+
* The host resolves platform-vs-tenant ownership according to infra policy.
|
|
460
|
+
*/
|
|
461
|
+
getEffectiveEnabledCurrencies(options?: {
|
|
462
|
+
organizationId?: string | undefined;
|
|
463
|
+
}): Promise<Array<{
|
|
464
|
+
code: string;
|
|
465
|
+
nameI18n?: Record<string, string> | null;
|
|
466
|
+
symbol?: string | null;
|
|
467
|
+
decimalDigits?: number | null;
|
|
468
|
+
isBase?: boolean;
|
|
469
|
+
currentRate?: string | null;
|
|
470
|
+
}>>;
|
|
471
|
+
/**
|
|
472
|
+
* Get the effective current rate for a currency code in the current tenant context.
|
|
473
|
+
*
|
|
474
|
+
* The host resolves platform-vs-tenant ownership according to infra policy.
|
|
475
|
+
*/
|
|
476
|
+
getEffectiveCurrentRate(code: string, options?: {
|
|
477
|
+
organizationId?: string | undefined;
|
|
478
|
+
}): Promise<string | null>;
|
|
479
|
+
/**
|
|
480
|
+
* Convenience helper for CNY to USD conversions.
|
|
481
|
+
* Returns the effective CNY → USD rate, or null when not configured.
|
|
482
|
+
*/
|
|
483
|
+
getEffectiveCnyToUsdRate(options?: {
|
|
484
|
+
organizationId?: string | undefined;
|
|
485
|
+
}): Promise<number | null>;
|
|
486
|
+
}
|
|
487
|
+
interface PluginEntityExtensionFilter {
|
|
488
|
+
id: string;
|
|
489
|
+
value: string | string[];
|
|
490
|
+
variant: string;
|
|
491
|
+
operator: string;
|
|
492
|
+
filterId?: string | undefined;
|
|
493
|
+
}
|
|
494
|
+
interface PluginEntityExtensionCapability {
|
|
495
|
+
/**
|
|
496
|
+
* Save extension values for a target plugin CRUD row through the platform contract.
|
|
497
|
+
*
|
|
498
|
+
* Values are keyed by manifest field name. The platform resolves each
|
|
499
|
+
* field owner from enabled plugin manifests, invokes owner save handlers,
|
|
500
|
+
* and refreshes Core's query projection.
|
|
501
|
+
*/
|
|
502
|
+
saveValues(options: {
|
|
503
|
+
/** Globally unique extension target id, e.g. "com.example.shop.stores". */
|
|
504
|
+
id: string;
|
|
505
|
+
entityId: string;
|
|
506
|
+
ext?: Record<string, unknown> | null | undefined;
|
|
507
|
+
tx?: unknown;
|
|
508
|
+
}): Promise<void>;
|
|
509
|
+
/**
|
|
510
|
+
* Match target CRUD row ids from Core's query projection for extension-field filters.
|
|
511
|
+
*
|
|
512
|
+
* This is a Core-mediated read model query. Plugins receive row ids only;
|
|
513
|
+
* plugin-owned semantic extension values stay in the owner plugin's private
|
|
514
|
+
* storage and are not exposed through this capability.
|
|
515
|
+
*/
|
|
516
|
+
matchEntityIds(options: {
|
|
517
|
+
/** Globally unique extension target id, e.g. "com.example.shop.stores". */
|
|
518
|
+
id: string;
|
|
519
|
+
filters: PluginEntityExtensionFilter[];
|
|
520
|
+
joinOperator?: "and" | "or" | undefined;
|
|
521
|
+
limit?: number | undefined;
|
|
522
|
+
}): Promise<string[]>;
|
|
523
|
+
/**
|
|
524
|
+
* Match target CRUD row ids by global search over fields whose manifest
|
|
525
|
+
* declaration has `search: true`.
|
|
526
|
+
*/
|
|
527
|
+
searchEntityIds(options: {
|
|
528
|
+
/** Globally unique extension target id, e.g. "com.example.shop.stores". */
|
|
529
|
+
id: string;
|
|
530
|
+
search: string;
|
|
531
|
+
limit?: number | undefined;
|
|
532
|
+
}): Promise<string[]>;
|
|
533
|
+
}
|
|
534
|
+
interface PluginCrudExtensionFilter {
|
|
535
|
+
id: string;
|
|
536
|
+
value: string | string[];
|
|
537
|
+
variant: string;
|
|
538
|
+
operator: string;
|
|
539
|
+
filterId?: string | undefined;
|
|
540
|
+
}
|
|
541
|
+
interface PluginCrudExtensionMetadata {
|
|
542
|
+
schema?: unknown;
|
|
543
|
+
fields?: Record<string, unknown>;
|
|
544
|
+
errors?: string[] | undefined;
|
|
545
|
+
}
|
|
546
|
+
interface PluginCrudExtensionsCapability {
|
|
547
|
+
getMetadata?(options: {
|
|
548
|
+
/** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
|
|
549
|
+
id: string;
|
|
550
|
+
}): Promise<PluginCrudExtensionMetadata>;
|
|
551
|
+
saveExtraValues(options: {
|
|
552
|
+
/** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
|
|
553
|
+
id: string;
|
|
554
|
+
entityId: string;
|
|
555
|
+
rawValues: Record<string, unknown>;
|
|
556
|
+
baseValues: Record<string, unknown>;
|
|
557
|
+
extraValues: Record<string, unknown>;
|
|
558
|
+
tx?: unknown;
|
|
559
|
+
}): Promise<void>;
|
|
560
|
+
readProjection(options: {
|
|
561
|
+
/** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
|
|
562
|
+
id: string;
|
|
563
|
+
entityIds: string[];
|
|
564
|
+
fields?: string[] | undefined;
|
|
565
|
+
}): Promise<Record<string, Record<string, unknown>>>;
|
|
566
|
+
matchEntityIds(options: {
|
|
567
|
+
/** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
|
|
568
|
+
id: string;
|
|
569
|
+
filters: PluginCrudExtensionFilter[];
|
|
570
|
+
joinOperator?: "and" | "or" | undefined;
|
|
571
|
+
limit?: number | undefined;
|
|
572
|
+
}): Promise<string[]>;
|
|
573
|
+
searchEntityIds(options: {
|
|
574
|
+
/** Globally unique CRUD target id, e.g. "com.example.shop.stores". */
|
|
575
|
+
id: string;
|
|
576
|
+
search: string;
|
|
577
|
+
limit?: number | undefined;
|
|
578
|
+
}): Promise<string[]>;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Plugin Queue Capability - Async job processing
|
|
582
|
+
*
|
|
583
|
+
* All jobs are namespaced with plugin_{pluginId}_{jobName}
|
|
584
|
+
* Subject to rate limits and payload size restrictions.
|
|
585
|
+
*/
|
|
586
|
+
interface PluginQueueCapability {
|
|
587
|
+
/**
|
|
588
|
+
* Add a job to the queue
|
|
589
|
+
* @param jobName - Job name (will be prefixed with plugin_{pluginId}_)
|
|
590
|
+
* @param data - Job payload (must be JSON-serializable, max 64KB)
|
|
591
|
+
* @param options - Job options
|
|
592
|
+
*/
|
|
593
|
+
addJob<T = unknown>(jobName: string, data: T, options?: PluginJobOptions): Promise<{
|
|
594
|
+
jobId: string;
|
|
595
|
+
}>;
|
|
596
|
+
/**
|
|
597
|
+
* Get job status
|
|
598
|
+
* @param jobId - Job ID returned from addJob
|
|
599
|
+
*/
|
|
600
|
+
getJobStatus(jobId: string): Promise<PluginJobStatus>;
|
|
601
|
+
/**
|
|
602
|
+
* Cancel a pending job
|
|
603
|
+
* @param jobId - Job ID to cancel
|
|
604
|
+
*/
|
|
605
|
+
cancelJob(jobId: string): Promise<boolean>;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Plugin Job Options
|
|
609
|
+
*/
|
|
610
|
+
interface PluginJobOptions {
|
|
611
|
+
/** Job priority: 'low' | 'normal' | 'high' | 'critical' */
|
|
612
|
+
priority?: "low" | "normal" | "high" | "critical";
|
|
613
|
+
/** Stable job id for idempotent queueing */
|
|
614
|
+
jobId?: string;
|
|
615
|
+
/** Delay in milliseconds before processing */
|
|
616
|
+
delay?: number;
|
|
617
|
+
/** Number of retry attempts on failure */
|
|
618
|
+
attempts?: number;
|
|
619
|
+
/** Backoff strategy for retries */
|
|
620
|
+
backoff?: {
|
|
621
|
+
type: "fixed" | "exponential";
|
|
622
|
+
delay: number;
|
|
623
|
+
};
|
|
624
|
+
/** Remove job after completion */
|
|
625
|
+
removeOnComplete?: boolean;
|
|
626
|
+
/** Remove job after failure */
|
|
627
|
+
removeOnFail?: boolean;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Plugin Job Status
|
|
631
|
+
*/
|
|
632
|
+
interface PluginJobStatus {
|
|
633
|
+
id: string;
|
|
634
|
+
name: string;
|
|
635
|
+
state: "waiting" | "active" | "completed" | "failed" | "delayed";
|
|
636
|
+
progress?: number;
|
|
637
|
+
returnValue?: unknown;
|
|
638
|
+
failedReason?: string;
|
|
639
|
+
timestamp: number;
|
|
640
|
+
processedOn?: number;
|
|
641
|
+
finishedOn?: number;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Plugin Notification Capability - Send notifications (Unified Contract v2)
|
|
645
|
+
*
|
|
646
|
+
* Plugins can send notifications to users via Core's notification system.
|
|
647
|
+
* All notifications are tagged with sourcePluginId and validated against manifest.
|
|
648
|
+
*
|
|
649
|
+
* Key features:
|
|
650
|
+
* - Type validation: notification type must be declared in manifest
|
|
651
|
+
* - Rate limiting: plugin-level and user-level limits enforced
|
|
652
|
+
* - Aggregation: automatic grouping based on manifest-declared strategy
|
|
653
|
+
* - Webhooks: async callbacks for click/archive events
|
|
654
|
+
*/
|
|
655
|
+
interface PluginNotificationCapability {
|
|
656
|
+
/**
|
|
657
|
+
* Send a notification using the unified contract
|
|
658
|
+
*
|
|
659
|
+
* The notification type must be declared in the plugin's manifest.
|
|
660
|
+
* Rate limits are enforced (plugin: 100/min, 1000/hr, 10000/day; user: 10/min, 50/hr).
|
|
661
|
+
*
|
|
662
|
+
* @param params - Notification parameters
|
|
663
|
+
* @returns Promise resolving to notification ID
|
|
664
|
+
* @throws PluginNotificationValidationError if type not declared in manifest
|
|
665
|
+
* @throws RateLimitExceededError if rate limit exceeded
|
|
666
|
+
* @throws PermissionDeniedError if notification:send not declared
|
|
667
|
+
*/
|
|
668
|
+
send(params: PluginNotificationSendParams): Promise<PluginNotificationSendResult>;
|
|
669
|
+
/**
|
|
670
|
+
* Register a notification template (legacy, still supported)
|
|
671
|
+
* Templates are namespaced: plugin_{pluginId}_{templateKey}
|
|
672
|
+
*/
|
|
673
|
+
registerTemplate(template: PluginNotificationTemplate): Promise<void>;
|
|
674
|
+
/**
|
|
675
|
+
* Register a notification channel (legacy, still supported)
|
|
676
|
+
* Channels are namespaced: plugin_{pluginId}_{channelKey}
|
|
677
|
+
*/
|
|
678
|
+
registerChannel(channel: PluginNotificationChannel): Promise<void>;
|
|
679
|
+
/**
|
|
680
|
+
* Subscribe to notification.created events
|
|
681
|
+
* Allows plugins to enhance notifications (e.g., send to external services)
|
|
682
|
+
*/
|
|
683
|
+
onNotificationCreated(handler: (event: PluginNotificationEvent) => void | Promise<void>): () => void;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Plugin Notification Send Parameters (Unified Contract v2)
|
|
687
|
+
*
|
|
688
|
+
* Simplified API where plugins declare "intent", platform handles "execution".
|
|
689
|
+
*/
|
|
690
|
+
interface PluginNotificationSendParams {
|
|
691
|
+
/**
|
|
692
|
+
* Notification type ID - must match a type declared in manifest.notifications.types
|
|
693
|
+
* @example "task_reminder", "content_liked"
|
|
694
|
+
*/
|
|
695
|
+
type: string;
|
|
696
|
+
/**
|
|
697
|
+
* Target user ID to receive the notification
|
|
698
|
+
*/
|
|
699
|
+
userId: string;
|
|
700
|
+
/**
|
|
701
|
+
* Actor who triggered the notification (optional)
|
|
702
|
+
* If not provided, the plugin itself is treated as the actor
|
|
703
|
+
*/
|
|
704
|
+
actor?: PluginNotificationActor;
|
|
705
|
+
/**
|
|
706
|
+
* Target object the notification is about
|
|
707
|
+
*/
|
|
708
|
+
target: PluginNotificationTarget;
|
|
709
|
+
/**
|
|
710
|
+
* Custom data for template rendering
|
|
711
|
+
* These values are passed to i18n templates as variables
|
|
712
|
+
*/
|
|
713
|
+
data?: Record<string, unknown>;
|
|
714
|
+
/**
|
|
715
|
+
* Locale for i18n (e.g., 'en-US', 'zh-CN')
|
|
716
|
+
* Falls back to user preference or 'en-US'
|
|
717
|
+
*/
|
|
718
|
+
locale?: string;
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Notification Actor - who triggered the notification
|
|
722
|
+
*/
|
|
723
|
+
interface PluginNotificationActor {
|
|
724
|
+
/** Actor ID (user ID or plugin ID) */
|
|
725
|
+
id: string;
|
|
726
|
+
/** Actor type */
|
|
727
|
+
type: "user" | "plugin";
|
|
728
|
+
/** Display name */
|
|
729
|
+
name: string;
|
|
730
|
+
/** Avatar URL (optional) */
|
|
731
|
+
avatarUrl?: string;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Notification Target - what the notification is about
|
|
735
|
+
*/
|
|
736
|
+
interface PluginNotificationTarget {
|
|
737
|
+
/** Target type (e.g., 'post', 'comment', 'task') */
|
|
738
|
+
type: string;
|
|
739
|
+
/** Target ID */
|
|
740
|
+
id: string;
|
|
741
|
+
/** URL to navigate when notification is clicked */
|
|
742
|
+
url: string;
|
|
743
|
+
/** Preview image URL (optional, for rich notifications) */
|
|
744
|
+
previewImage?: string;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Plugin Notification Send Result
|
|
748
|
+
*/
|
|
749
|
+
interface PluginNotificationSendResult {
|
|
750
|
+
/** The created notification ID */
|
|
751
|
+
notificationId: string;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Plugin Notification Input (Legacy - use PluginNotificationSendParams instead)
|
|
755
|
+
* @deprecated Use PluginNotificationSendParams for new implementations
|
|
756
|
+
*/
|
|
757
|
+
interface PluginNotificationInput {
|
|
758
|
+
/** Target user ID */
|
|
759
|
+
userId: string;
|
|
760
|
+
/** Template key (will be prefixed with plugin_{pluginId}_ if not already) */
|
|
761
|
+
templateKey: string;
|
|
762
|
+
/** Variables for template interpolation */
|
|
763
|
+
variables: Record<string, unknown>;
|
|
764
|
+
/** Notification type */
|
|
765
|
+
type?: "info" | "success" | "warning" | "error";
|
|
766
|
+
/** Link to navigate when clicked */
|
|
767
|
+
link?: string;
|
|
768
|
+
/** Actor ID (who triggered the notification) */
|
|
769
|
+
actorId?: string;
|
|
770
|
+
/** Entity reference */
|
|
771
|
+
entityId?: string;
|
|
772
|
+
entityType?: string;
|
|
773
|
+
/** Grouping key for bundling */
|
|
774
|
+
groupKey?: string;
|
|
775
|
+
/** Idempotency key to prevent duplicates */
|
|
776
|
+
idempotencyKey?: string;
|
|
777
|
+
/** Priority override */
|
|
778
|
+
priority?: "low" | "normal" | "high" | "urgent";
|
|
779
|
+
/** Channel overrides */
|
|
780
|
+
channels?: string[];
|
|
781
|
+
/** Locale for i18n */
|
|
782
|
+
locale?: string;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Plugin Notification Result (Legacy)
|
|
786
|
+
* @deprecated Use PluginNotificationSendResult for new implementations
|
|
787
|
+
*/
|
|
788
|
+
interface PluginNotificationResult {
|
|
789
|
+
notificationId: string;
|
|
790
|
+
channels: string[];
|
|
791
|
+
decisionTrace: Array<{
|
|
792
|
+
channel: string;
|
|
793
|
+
included: boolean;
|
|
794
|
+
reason: string;
|
|
795
|
+
}>;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Plugin Notification Template
|
|
799
|
+
*/
|
|
800
|
+
interface PluginNotificationTemplate {
|
|
801
|
+
/** Template key (will be prefixed with plugin_{pluginId}_) */
|
|
802
|
+
key: string;
|
|
803
|
+
/** Display name */
|
|
804
|
+
name: string;
|
|
805
|
+
/** Description */
|
|
806
|
+
description?: string;
|
|
807
|
+
/** i18n title templates */
|
|
808
|
+
title: Record<string, string>;
|
|
809
|
+
/** i18n message templates */
|
|
810
|
+
message: Record<string, string>;
|
|
811
|
+
/** Variables that can be interpolated */
|
|
812
|
+
variables?: string[];
|
|
813
|
+
/** Default channels */
|
|
814
|
+
defaultChannels?: string[];
|
|
815
|
+
/** Default priority */
|
|
816
|
+
priority?: "low" | "normal" | "high" | "urgent";
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Plugin Notification Channel
|
|
820
|
+
*/
|
|
821
|
+
interface PluginNotificationChannel {
|
|
822
|
+
/** Channel key (will be prefixed with plugin_{pluginId}_) */
|
|
823
|
+
key: string;
|
|
824
|
+
/** i18n display name */
|
|
825
|
+
name: Record<string, string>;
|
|
826
|
+
/** i18n description */
|
|
827
|
+
description?: Record<string, string>;
|
|
828
|
+
/** Icon name */
|
|
829
|
+
icon?: string;
|
|
830
|
+
/** User configuration schema (JSON Schema) */
|
|
831
|
+
configSchema?: Record<string, unknown>;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Plugin Notification Event (for onNotificationCreated)
|
|
835
|
+
*/
|
|
836
|
+
interface PluginNotificationEvent {
|
|
837
|
+
notification: {
|
|
838
|
+
id: string;
|
|
839
|
+
userId: string;
|
|
840
|
+
organizationId: string;
|
|
841
|
+
templateKey?: string;
|
|
842
|
+
type: string;
|
|
843
|
+
title: string;
|
|
844
|
+
message: string;
|
|
845
|
+
html?: string;
|
|
846
|
+
link?: string;
|
|
847
|
+
priority: "low" | "normal" | "high" | "urgent";
|
|
848
|
+
actorId?: string;
|
|
849
|
+
entityId?: string;
|
|
850
|
+
entityType?: string;
|
|
851
|
+
groupKey?: string;
|
|
852
|
+
sourcePluginId?: string;
|
|
853
|
+
};
|
|
854
|
+
user: {
|
|
855
|
+
id: string;
|
|
856
|
+
email?: string;
|
|
857
|
+
preferences: {
|
|
858
|
+
enabledChannels: string[];
|
|
859
|
+
emailFrequency: "instant" | "hourly" | "daily";
|
|
860
|
+
};
|
|
861
|
+
};
|
|
862
|
+
channels: string[];
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Plugin Settings Capability - Configuration management for plugins
|
|
866
|
+
*
|
|
867
|
+
* All settings are automatically scoped to the plugin's namespace:
|
|
868
|
+
* - plugin_global: Plugin-wide settings (shared across all tenants)
|
|
869
|
+
* - plugin_tenant: Per-tenant plugin settings
|
|
870
|
+
*
|
|
871
|
+
* Plugins cannot access Core settings or other plugins' settings.
|
|
872
|
+
*/
|
|
873
|
+
interface PluginSettingsCapability {
|
|
874
|
+
/**
|
|
875
|
+
* Get a setting value
|
|
876
|
+
* Resolution order: plugin_tenant → plugin_global → defaultValue
|
|
877
|
+
*
|
|
878
|
+
* @param key - Setting key (without plugin prefix)
|
|
879
|
+
* @param defaultValue - Default value if not found
|
|
880
|
+
* @returns The setting value or default
|
|
881
|
+
*/
|
|
882
|
+
get<T = unknown>(key: string, defaultValue?: T): Promise<T | null>;
|
|
883
|
+
/**
|
|
884
|
+
* Set a setting value
|
|
885
|
+
*
|
|
886
|
+
* @param key - Setting key (without plugin prefix)
|
|
887
|
+
* @param value - Value to store
|
|
888
|
+
* @param options - Additional options
|
|
889
|
+
*/
|
|
890
|
+
set(key: string, value: unknown, options?: PluginSettingOptions): Promise<void>;
|
|
891
|
+
/**
|
|
892
|
+
* Delete a setting
|
|
893
|
+
*
|
|
894
|
+
* @param key - Setting key to delete
|
|
895
|
+
* @param options - Scope options
|
|
896
|
+
*/
|
|
897
|
+
delete(key: string, options?: {
|
|
898
|
+
global?: boolean;
|
|
899
|
+
}): Promise<boolean>;
|
|
900
|
+
/**
|
|
901
|
+
* List all settings for the plugin
|
|
902
|
+
*
|
|
903
|
+
* @param options - Filter options
|
|
904
|
+
* @returns Array of settings
|
|
905
|
+
*/
|
|
906
|
+
list(options?: {
|
|
907
|
+
global?: boolean;
|
|
908
|
+
keyPrefix?: string;
|
|
909
|
+
}): Promise<PluginSettingEntry[]>;
|
|
910
|
+
/**
|
|
911
|
+
* Check if a feature flag is enabled for the current context
|
|
912
|
+
*
|
|
913
|
+
* @param flagKey - Feature flag key
|
|
914
|
+
* @returns true if enabled, false otherwise
|
|
915
|
+
*/
|
|
916
|
+
isFeatureEnabled(flagKey: string): Promise<boolean>;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Plugin Setting Options
|
|
920
|
+
*/
|
|
921
|
+
interface PluginSettingOptions {
|
|
922
|
+
/** Store as global (plugin_global) instead of tenant-scoped (plugin_tenant) */
|
|
923
|
+
global?: boolean;
|
|
924
|
+
/** Encrypt the value (for sensitive data like API keys) */
|
|
925
|
+
encrypted?: boolean;
|
|
926
|
+
/** Description for admin UI */
|
|
927
|
+
description?: string;
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Plugin Setting Entry (for list operation)
|
|
931
|
+
*/
|
|
932
|
+
interface PluginSettingEntry {
|
|
933
|
+
key: string;
|
|
934
|
+
value: unknown;
|
|
935
|
+
scope: "plugin_global" | "plugin_tenant";
|
|
936
|
+
encrypted: boolean;
|
|
937
|
+
description?: string | undefined;
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Plugin Media Capability - Unified file and asset management
|
|
941
|
+
*
|
|
942
|
+
* Provides plugins with the ability to upload, manage, and organize media.
|
|
943
|
+
* Replaces the separate File and Asset capabilities.
|
|
944
|
+
* All operations are scoped to the current tenant.
|
|
945
|
+
*/
|
|
946
|
+
interface PluginMediaCapability {
|
|
947
|
+
/**
|
|
948
|
+
* Upload a media file
|
|
949
|
+
* @param input - Media upload input
|
|
950
|
+
* @returns Uploaded media info
|
|
951
|
+
*/
|
|
952
|
+
upload(input: PluginMediaUploadInput): Promise<PluginMediaInfo>;
|
|
953
|
+
/**
|
|
954
|
+
* Get media info by ID
|
|
955
|
+
* @param mediaId - Media ID
|
|
956
|
+
* @returns Media info or null if not found
|
|
957
|
+
*/
|
|
958
|
+
get(mediaId: string): Promise<PluginMediaInfo | null>;
|
|
959
|
+
/**
|
|
960
|
+
* Update media metadata
|
|
961
|
+
* @param mediaId - Media ID
|
|
962
|
+
* @param data - Update data
|
|
963
|
+
*/
|
|
964
|
+
update(mediaId: string, data: PluginMediaUpdateData): Promise<PluginMediaInfo>;
|
|
965
|
+
/**
|
|
966
|
+
* Download media content
|
|
967
|
+
* @param mediaId - Media ID
|
|
968
|
+
* @returns Media content as Buffer
|
|
969
|
+
*/
|
|
970
|
+
download(mediaId: string): Promise<Buffer>;
|
|
971
|
+
/**
|
|
972
|
+
* Get signed URL for media access
|
|
973
|
+
* @param mediaId - Media ID
|
|
974
|
+
* @param options - URL options
|
|
975
|
+
* @returns Signed URL with expiration
|
|
976
|
+
*/
|
|
977
|
+
getSignedUrl(mediaId: string, options?: {
|
|
978
|
+
expiresIn?: number;
|
|
979
|
+
}): Promise<{
|
|
980
|
+
url: string;
|
|
981
|
+
expiresIn: number;
|
|
982
|
+
}>;
|
|
983
|
+
/**
|
|
984
|
+
* Get fixed display URL for media access
|
|
985
|
+
* @param mediaId - Media ID
|
|
986
|
+
* @param options - Display URL options
|
|
987
|
+
* @returns Stable application-controlled display URL
|
|
988
|
+
*/
|
|
989
|
+
getDisplayUrl(mediaId: string, options?: {
|
|
990
|
+
variant?: string;
|
|
991
|
+
}): Promise<{
|
|
992
|
+
url: string;
|
|
993
|
+
variant: string;
|
|
994
|
+
}>;
|
|
995
|
+
/**
|
|
996
|
+
* Resolve a media reference or legacy signed file URL to a display URL
|
|
997
|
+
* @param value - Media ID, signed file URL, display URL, or external URL
|
|
998
|
+
* @param options - Display URL options
|
|
999
|
+
* @returns Application-controlled display URL when resolvable
|
|
1000
|
+
*/
|
|
1001
|
+
resolveAccessUrl(value: string, options?: {
|
|
1002
|
+
variant?: string;
|
|
1003
|
+
}): Promise<{
|
|
1004
|
+
url: string;
|
|
1005
|
+
}>;
|
|
1006
|
+
/**
|
|
1007
|
+
* Delete a media (soft delete)
|
|
1008
|
+
* @param mediaId - Media ID
|
|
1009
|
+
*/
|
|
1010
|
+
delete(mediaId: string): Promise<void>;
|
|
1011
|
+
/**
|
|
1012
|
+
* List media with filtering and pagination
|
|
1013
|
+
* @param query - Query options
|
|
1014
|
+
*/
|
|
1015
|
+
list(query?: PluginMediaQuery): Promise<PluginPaginatedResult<PluginMediaInfo>>;
|
|
1016
|
+
/**
|
|
1017
|
+
* Get URL for a media variant
|
|
1018
|
+
* @param mediaId - Media ID
|
|
1019
|
+
* @param variant - Variant name (e.g., 'thumbnail', 'medium')
|
|
1020
|
+
*/
|
|
1021
|
+
getVariantUrl(mediaId: string, variant: string): Promise<string>;
|
|
1022
|
+
/**
|
|
1023
|
+
* Get all variants for a media
|
|
1024
|
+
* @param mediaId - Media ID
|
|
1025
|
+
*/
|
|
1026
|
+
getVariants(mediaId: string): Promise<PluginMediaVariant[]>;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Plugin Media Upload Input
|
|
1030
|
+
*/
|
|
1031
|
+
interface PluginMediaUploadInput {
|
|
1032
|
+
/** File content */
|
|
1033
|
+
content: Buffer;
|
|
1034
|
+
/** Original filename */
|
|
1035
|
+
filename: string;
|
|
1036
|
+
/** MIME type */
|
|
1037
|
+
mimeType: string;
|
|
1038
|
+
/** Is publicly accessible */
|
|
1039
|
+
isPublic?: boolean;
|
|
1040
|
+
/** Alt text for accessibility */
|
|
1041
|
+
alt?: string;
|
|
1042
|
+
/** Title */
|
|
1043
|
+
title?: string;
|
|
1044
|
+
/** Tags for organization */
|
|
1045
|
+
tags?: string[];
|
|
1046
|
+
/** Folder path */
|
|
1047
|
+
folderPath?: string;
|
|
1048
|
+
/** Additional metadata */
|
|
1049
|
+
metadata?: Record<string, unknown>;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Plugin Media Info
|
|
1053
|
+
*/
|
|
1054
|
+
interface PluginMediaInfo {
|
|
1055
|
+
id: string;
|
|
1056
|
+
filename: string;
|
|
1057
|
+
mimeType: string;
|
|
1058
|
+
size: number;
|
|
1059
|
+
isPublic: boolean;
|
|
1060
|
+
alt?: string;
|
|
1061
|
+
title?: string;
|
|
1062
|
+
tags: string[];
|
|
1063
|
+
folderPath?: string;
|
|
1064
|
+
width?: number;
|
|
1065
|
+
height?: number;
|
|
1066
|
+
format?: string;
|
|
1067
|
+
metadata?: Record<string, unknown>;
|
|
1068
|
+
createdAt: Date;
|
|
1069
|
+
updatedAt: Date;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Plugin Media Update Data
|
|
1073
|
+
*/
|
|
1074
|
+
interface PluginMediaUpdateData {
|
|
1075
|
+
alt?: string;
|
|
1076
|
+
title?: string;
|
|
1077
|
+
tags?: string[];
|
|
1078
|
+
folderPath?: string;
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Plugin Media Variant
|
|
1082
|
+
*/
|
|
1083
|
+
interface PluginMediaVariant {
|
|
1084
|
+
name: string;
|
|
1085
|
+
mediaId: string;
|
|
1086
|
+
width?: number;
|
|
1087
|
+
height?: number;
|
|
1088
|
+
format?: string;
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Plugin Media Query
|
|
1092
|
+
*/
|
|
1093
|
+
interface PluginMediaQuery {
|
|
1094
|
+
/** Filter by MIME type or category (e.g., 'image/*') */
|
|
1095
|
+
mimeType?: string;
|
|
1096
|
+
/** Tag filter */
|
|
1097
|
+
tags?: string[];
|
|
1098
|
+
/** Folder path filter (prefix match) */
|
|
1099
|
+
folderPath?: string;
|
|
1100
|
+
/** Search in filename/alt/title */
|
|
1101
|
+
search?: string;
|
|
1102
|
+
/** Sort field */
|
|
1103
|
+
sortBy?: "createdAt" | "updatedAt" | "filename";
|
|
1104
|
+
/** Sort order */
|
|
1105
|
+
sortOrder?: "asc" | "desc";
|
|
1106
|
+
/** Page number */
|
|
1107
|
+
page?: number;
|
|
1108
|
+
/** Page size */
|
|
1109
|
+
pageSize?: number;
|
|
1110
|
+
}
|
|
1111
|
+
/** @deprecated Use PluginMediaCapability */
|
|
1112
|
+
type PluginFileCapability = {
|
|
1113
|
+
upload(input: PluginFileUploadInput): Promise<PluginFileInfo>;
|
|
1114
|
+
get(fileId: string): Promise<PluginFileInfo | null>;
|
|
1115
|
+
download(fileId: string): Promise<Buffer>;
|
|
1116
|
+
getSignedUrl(fileId: string, options?: {
|
|
1117
|
+
expiresIn?: number;
|
|
1118
|
+
}): Promise<{
|
|
1119
|
+
url: string;
|
|
1120
|
+
expiresIn: number;
|
|
1121
|
+
}>;
|
|
1122
|
+
delete(fileId: string): Promise<void>;
|
|
1123
|
+
list(query?: PluginFileQuery): Promise<PluginPaginatedResult<PluginFileInfo>>;
|
|
1124
|
+
};
|
|
1125
|
+
/** @deprecated Use PluginMediaUploadInput */
|
|
1126
|
+
interface PluginFileUploadInput {
|
|
1127
|
+
content: Buffer;
|
|
1128
|
+
filename: string;
|
|
1129
|
+
mimeType: string;
|
|
1130
|
+
isPublic?: boolean;
|
|
1131
|
+
metadata?: Record<string, unknown>;
|
|
1132
|
+
}
|
|
1133
|
+
/** @deprecated Use PluginMediaInfo */
|
|
1134
|
+
interface PluginFileInfo {
|
|
1135
|
+
id: string;
|
|
1136
|
+
filename: string;
|
|
1137
|
+
mimeType: string;
|
|
1138
|
+
size: number;
|
|
1139
|
+
isPublic: boolean;
|
|
1140
|
+
metadata?: Record<string, unknown>;
|
|
1141
|
+
createdAt: Date;
|
|
1142
|
+
updatedAt: Date;
|
|
1143
|
+
}
|
|
1144
|
+
/** @deprecated Use PluginMediaQuery */
|
|
1145
|
+
interface PluginFileQuery {
|
|
1146
|
+
search?: string;
|
|
1147
|
+
mimeType?: string;
|
|
1148
|
+
page?: number;
|
|
1149
|
+
pageSize?: number;
|
|
1150
|
+
}
|
|
1151
|
+
/** @deprecated Use PluginMediaCapability */
|
|
1152
|
+
type PluginAssetCapability = {
|
|
1153
|
+
create(fileId: string, options?: PluginAssetCreateOptions): Promise<PluginAssetInfo>;
|
|
1154
|
+
get(assetId: string): Promise<PluginAssetInfo | null>;
|
|
1155
|
+
update(assetId: string, data: PluginAssetUpdateData): Promise<PluginAssetInfo>;
|
|
1156
|
+
delete(assetId: string): Promise<void>;
|
|
1157
|
+
list(query?: PluginAssetQuery): Promise<PluginPaginatedResult<PluginAssetInfo>>;
|
|
1158
|
+
getVariantUrl(assetId: string, variant: string): Promise<string>;
|
|
1159
|
+
getVariants(assetId: string): Promise<PluginAssetVariant[]>;
|
|
1160
|
+
};
|
|
1161
|
+
/** @deprecated Use PluginMediaUpdateData */
|
|
1162
|
+
interface PluginAssetCreateOptions {
|
|
1163
|
+
type?: "image" | "video" | "document" | "other";
|
|
1164
|
+
alt?: string;
|
|
1165
|
+
title?: string;
|
|
1166
|
+
tags?: string[];
|
|
1167
|
+
folderPath?: string;
|
|
1168
|
+
}
|
|
1169
|
+
/** @deprecated Use PluginMediaUpdateData */
|
|
1170
|
+
interface PluginAssetUpdateData {
|
|
1171
|
+
alt?: string;
|
|
1172
|
+
title?: string;
|
|
1173
|
+
tags?: string[];
|
|
1174
|
+
folderPath?: string;
|
|
1175
|
+
}
|
|
1176
|
+
/** @deprecated Use PluginMediaInfo */
|
|
1177
|
+
interface PluginAssetInfo {
|
|
1178
|
+
id: string;
|
|
1179
|
+
fileId: string;
|
|
1180
|
+
type: "image" | "video" | "document" | "other";
|
|
1181
|
+
alt?: string;
|
|
1182
|
+
title?: string;
|
|
1183
|
+
tags: string[];
|
|
1184
|
+
folderPath?: string;
|
|
1185
|
+
width?: number;
|
|
1186
|
+
height?: number;
|
|
1187
|
+
format?: string;
|
|
1188
|
+
createdAt: Date;
|
|
1189
|
+
updatedAt: Date;
|
|
1190
|
+
}
|
|
1191
|
+
/** @deprecated Use PluginMediaVariant */
|
|
1192
|
+
interface PluginAssetVariant {
|
|
1193
|
+
name: string;
|
|
1194
|
+
fileId: string;
|
|
1195
|
+
width: number;
|
|
1196
|
+
height: number;
|
|
1197
|
+
format: string;
|
|
1198
|
+
}
|
|
1199
|
+
/** @deprecated Use PluginMediaQuery */
|
|
1200
|
+
interface PluginAssetQuery {
|
|
1201
|
+
type?: "image" | "video" | "document" | "other";
|
|
1202
|
+
tags?: string[];
|
|
1203
|
+
folderPath?: string;
|
|
1204
|
+
search?: string;
|
|
1205
|
+
sortBy?: "createdAt" | "updatedAt" | "title";
|
|
1206
|
+
sortOrder?: "asc" | "desc";
|
|
1207
|
+
page?: number;
|
|
1208
|
+
pageSize?: number;
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Plugin Storage Capability - Custom storage provider registration
|
|
1212
|
+
*
|
|
1213
|
+
* Allows plugins to register custom storage providers (e.g., S3, OSS, R2).
|
|
1214
|
+
* Providers registered by plugins are automatically namespaced with plugin ID.
|
|
1215
|
+
*/
|
|
1216
|
+
interface PluginStorageCapability {
|
|
1217
|
+
/**
|
|
1218
|
+
* Register a custom storage provider
|
|
1219
|
+
* The provider type will be prefixed: plugin_{pluginId}_{type}
|
|
1220
|
+
* @param config - Provider configuration
|
|
1221
|
+
*/
|
|
1222
|
+
registerProvider(config: PluginStorageProviderConfig): Promise<void>;
|
|
1223
|
+
/**
|
|
1224
|
+
* List registered storage providers by this plugin
|
|
1225
|
+
*/
|
|
1226
|
+
listProviders(): Promise<PluginStorageProviderInfo[]>;
|
|
1227
|
+
/**
|
|
1228
|
+
* Unregister a storage provider
|
|
1229
|
+
* @param type - Provider type (without plugin prefix)
|
|
1230
|
+
*/
|
|
1231
|
+
unregisterProvider(type: string): Promise<void>;
|
|
1232
|
+
}
|
|
1233
|
+
interface PluginArtifactCapability {
|
|
1234
|
+
put(input: {
|
|
1235
|
+
content: Uint8Array;
|
|
1236
|
+
filename: string;
|
|
1237
|
+
mediaType: string;
|
|
1238
|
+
metadata?: Record<string, unknown>;
|
|
1239
|
+
}): Promise<{
|
|
1240
|
+
key: string;
|
|
1241
|
+
size: number;
|
|
1242
|
+
sha256: string;
|
|
1243
|
+
}>;
|
|
1244
|
+
get(key: string): Promise<Uint8Array>;
|
|
1245
|
+
delete(key: string): Promise<void>;
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Plugin Storage Provider Config
|
|
1249
|
+
*/
|
|
1250
|
+
interface PluginStorageProviderConfig {
|
|
1251
|
+
/** Provider type (will be prefixed with plugin_{pluginId}_) */
|
|
1252
|
+
type: string;
|
|
1253
|
+
/** Display name for admin UI */
|
|
1254
|
+
name: string;
|
|
1255
|
+
/** Description */
|
|
1256
|
+
description?: string;
|
|
1257
|
+
/** Configuration schema (JSON Schema) */
|
|
1258
|
+
configSchema: Record<string, unknown>;
|
|
1259
|
+
/** Provider factory function */
|
|
1260
|
+
factory: (config: Record<string, unknown>) => PluginStorageProvider;
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Plugin Storage Provider Info
|
|
1264
|
+
*/
|
|
1265
|
+
interface PluginStorageProviderInfo {
|
|
1266
|
+
type: string;
|
|
1267
|
+
name: string;
|
|
1268
|
+
description?: string;
|
|
1269
|
+
pluginId: string;
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Plugin Storage Provider Interface
|
|
1273
|
+
* Plugins implementing custom storage must implement this interface.
|
|
1274
|
+
*/
|
|
1275
|
+
interface PluginStorageProvider {
|
|
1276
|
+
/** Provider type identifier */
|
|
1277
|
+
readonly type: string;
|
|
1278
|
+
/** Upload a file */
|
|
1279
|
+
upload(input: PluginStorageUploadInput): Promise<PluginStorageUploadResult>;
|
|
1280
|
+
/** Download file content */
|
|
1281
|
+
download(key: string): Promise<Buffer>;
|
|
1282
|
+
/** Delete a file */
|
|
1283
|
+
delete(key: string): Promise<void>;
|
|
1284
|
+
/** Check if file exists */
|
|
1285
|
+
exists(key: string): Promise<boolean>;
|
|
1286
|
+
/** Get signed URL */
|
|
1287
|
+
getSignedUrl(key: string, options: {
|
|
1288
|
+
expiresIn: number;
|
|
1289
|
+
operation: "get" | "put";
|
|
1290
|
+
contentType?: string;
|
|
1291
|
+
}): Promise<string>;
|
|
1292
|
+
/** Initiate multipart upload */
|
|
1293
|
+
initiateMultipartUpload(key: string): Promise<string>;
|
|
1294
|
+
/** Upload a part */
|
|
1295
|
+
uploadPart(uploadId: string, partNumber: number, body: Buffer): Promise<{
|
|
1296
|
+
partNumber: number;
|
|
1297
|
+
etag: string;
|
|
1298
|
+
}>;
|
|
1299
|
+
/** Complete multipart upload */
|
|
1300
|
+
completeMultipartUpload(uploadId: string, parts: Array<{
|
|
1301
|
+
partNumber: number;
|
|
1302
|
+
etag: string;
|
|
1303
|
+
}>): Promise<void>;
|
|
1304
|
+
/** Abort multipart upload */
|
|
1305
|
+
abortMultipartUpload(uploadId: string): Promise<void>;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Plugin Storage Upload Input
|
|
1309
|
+
*/
|
|
1310
|
+
interface PluginStorageUploadInput {
|
|
1311
|
+
key: string;
|
|
1312
|
+
body: Buffer;
|
|
1313
|
+
contentType: string;
|
|
1314
|
+
metadata?: Record<string, string>;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Plugin Storage Upload Result
|
|
1318
|
+
*/
|
|
1319
|
+
interface PluginStorageUploadResult {
|
|
1320
|
+
key: string;
|
|
1321
|
+
size: number;
|
|
1322
|
+
etag?: string;
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Generic paginated result
|
|
1326
|
+
*/
|
|
1327
|
+
interface PluginPaginatedResult<T> {
|
|
1328
|
+
items: T[];
|
|
1329
|
+
total: number;
|
|
1330
|
+
page: number;
|
|
1331
|
+
pageSize: number;
|
|
1332
|
+
totalPages: number;
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Allowed labels for plugin metrics
|
|
1336
|
+
*
|
|
1337
|
+
* Per OBSERVABILITY_GOVERNANCE §4.1:
|
|
1338
|
+
* Only these labels are allowed to prevent cardinality explosion
|
|
1339
|
+
*/
|
|
1340
|
+
type PluginMetricsAllowedLabels = {
|
|
1341
|
+
model?: string;
|
|
1342
|
+
type?: string;
|
|
1343
|
+
status?: "success" | "failure";
|
|
1344
|
+
};
|
|
1345
|
+
/**
|
|
1346
|
+
* Plugin Metrics Capability - Usage metrics recording
|
|
1347
|
+
*
|
|
1348
|
+
* Per OBSERVABILITY_GOVERNANCE §4.1:
|
|
1349
|
+
* - Only increment() for discrete event counters
|
|
1350
|
+
* - No histogram/gauge/observe/set methods
|
|
1351
|
+
* - Labels are restricted to a whitelist
|
|
1352
|
+
*/
|
|
1353
|
+
interface PluginMetricsCapability {
|
|
1354
|
+
/**
|
|
1355
|
+
* Increment a counter metric
|
|
1356
|
+
*
|
|
1357
|
+
* @param name - Metric name (will be prefixed with plugin_)
|
|
1358
|
+
* @param labels - Optional labels (whitelist enforced: model, type, status)
|
|
1359
|
+
* @param value - Increment value (default: 1)
|
|
1360
|
+
*
|
|
1361
|
+
* @example
|
|
1362
|
+
* ctx.metrics.increment('content_generated', { model: 'gpt-4', status: 'success' });
|
|
1363
|
+
*/
|
|
1364
|
+
increment(name: string, labels?: PluginMetricsAllowedLabels, value?: number): void;
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Plugin Trace Capability - Read-only trace context access
|
|
1368
|
+
*
|
|
1369
|
+
* Per OBSERVABILITY_GOVERNANCE §5:
|
|
1370
|
+
* - Plugins can only read trace context
|
|
1371
|
+
* - Plugins cannot create spans or modify trace context
|
|
1372
|
+
*/
|
|
1373
|
+
interface PluginTraceCapability {
|
|
1374
|
+
/**
|
|
1375
|
+
* Get the current trace ID (W3C format, 32 hex chars)
|
|
1376
|
+
* @returns The trace ID or undefined if not available
|
|
1377
|
+
*/
|
|
1378
|
+
getTraceId(): string | undefined;
|
|
1379
|
+
/**
|
|
1380
|
+
* Get the current span ID (16 hex chars)
|
|
1381
|
+
* @returns The span ID or undefined if not available
|
|
1382
|
+
*/
|
|
1383
|
+
getSpanId(): string | undefined;
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Hook Priority Enum
|
|
1387
|
+
* Controls execution order within a hook
|
|
1388
|
+
*/
|
|
1389
|
+
declare enum HookPriority {
|
|
1390
|
+
EARLIEST = 0,// System-level, plugins should not use
|
|
1391
|
+
EARLY = 25,// Plugins needing early execution
|
|
1392
|
+
NORMAL = 50,// Default priority
|
|
1393
|
+
LATE = 75,// Plugins needing late execution
|
|
1394
|
+
LATEST = 100
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Hook Handler Options
|
|
1398
|
+
*/
|
|
1399
|
+
interface HookHandlerOptions {
|
|
1400
|
+
/** Handler priority (default: NORMAL) */
|
|
1401
|
+
priority?: HookPriority;
|
|
1402
|
+
/** Handler timeout in ms (default: 5000) */
|
|
1403
|
+
timeout?: number;
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Plugin Hook Capability - Register hook handlers
|
|
1407
|
+
*
|
|
1408
|
+
* Plugins can register handlers for Core-defined hooks to:
|
|
1409
|
+
* - Actions: Perform async side-effects (logging, notifications, external sync)
|
|
1410
|
+
* - Filters: Transform data in the pipeline (validation, enrichment, masking)
|
|
1411
|
+
*
|
|
1412
|
+
* Per EVENT_HOOK_GOVERNANCE (Frozen v1):
|
|
1413
|
+
* - Plugins CANNOT block Core execution (except via HookAbortError in filters)
|
|
1414
|
+
* - Plugins CANNOT access other plugins' handlers
|
|
1415
|
+
*/
|
|
1416
|
+
/**
|
|
1417
|
+
* Hook Event Map — Extensible type registry for TypeScript autocompletion
|
|
1418
|
+
*
|
|
1419
|
+
* Plugins can augment this interface to declare their hooks:
|
|
1420
|
+
*
|
|
1421
|
+
* ```typescript
|
|
1422
|
+
* // plugins/crm/src/shared/hook-types.ts
|
|
1423
|
+
* declare module '@wordrhyme/plugin' {
|
|
1424
|
+
* interface HookEventMap {
|
|
1425
|
+
* 'crm.customer.promoted': { customerId: string; organizationId: string };
|
|
1426
|
+
* 'crm.customer.beforeCreate': { name: string; organizationId: string };
|
|
1427
|
+
* 'crm.createProspect': { name: string; organizationId: string; id?: string; status?: string };
|
|
1428
|
+
* }
|
|
1429
|
+
* }
|
|
1430
|
+
* ```
|
|
1431
|
+
*
|
|
1432
|
+
* This enables:
|
|
1433
|
+
* - Hook ID autocompletion in on() and emit()
|
|
1434
|
+
* - Automatic payload type inference
|
|
1435
|
+
*/
|
|
1436
|
+
interface HookEventMap {
|
|
1437
|
+
}
|
|
1438
|
+
interface PluginHookCapability {
|
|
1439
|
+
/**
|
|
1440
|
+
* Register a hook handler
|
|
1441
|
+
*
|
|
1442
|
+
* Subscribes to a hook. When someone calls `emit()` for this hookId,
|
|
1443
|
+
* your handler will be called with the data.
|
|
1444
|
+
*
|
|
1445
|
+
* - Handler can optionally return modified data (for pipe mode)
|
|
1446
|
+
* - Handler can throw HookAbortError to abort the operation
|
|
1447
|
+
* - Returns an unsubscribe function
|
|
1448
|
+
*
|
|
1449
|
+
* @param hookId - The hook ID (e.g., 'crm.customer.afterCreate')
|
|
1450
|
+
* @param handler - Handler function, optionally returns modified data
|
|
1451
|
+
* @param options - Handler options (priority, timeout)
|
|
1452
|
+
* @returns Unsubscribe function
|
|
1453
|
+
*
|
|
1454
|
+
* @example
|
|
1455
|
+
* // Notification handler (no return needed)
|
|
1456
|
+
* ctx.hooks.on('crm.customer.promoted', async (data) => {
|
|
1457
|
+
* await sendWelcomeEmail(data.customerId);
|
|
1458
|
+
* });
|
|
1459
|
+
*
|
|
1460
|
+
* @example
|
|
1461
|
+
* // Service handler (returns result)
|
|
1462
|
+
* ctx.hooks.on('crm.createProspect', async (data) => {
|
|
1463
|
+
* const id = await db.insert(customers).values(data);
|
|
1464
|
+
* return { ...data, id, status: 'prospect' };
|
|
1465
|
+
* });
|
|
1466
|
+
*
|
|
1467
|
+
* @example
|
|
1468
|
+
* // Abort handler (blocks operation)
|
|
1469
|
+
* ctx.hooks.on('crm.customer.beforeCreate', async (data) => {
|
|
1470
|
+
* if (!data.name) throw new HookAbortError('名字不能为空');
|
|
1471
|
+
* });
|
|
1472
|
+
*/
|
|
1473
|
+
on<K extends keyof HookEventMap>(hookId: K, handler: (data: HookEventMap[K], context: HookContext) => HookEventMap[K] | void | Promise<HookEventMap[K] | void>, options?: HookHandlerOptions): () => void;
|
|
1474
|
+
on<K extends keyof HookEventMap>(hookId: K[], handler: (data: HookEventMap[K], context: HookContext) => HookEventMap[K] | void | Promise<HookEventMap[K] | void>, options?: HookHandlerOptions): () => void;
|
|
1475
|
+
on<T = unknown>(hookId: string, handler: (data: T, context: HookContext) => T | void | Promise<T | void>, options?: HookHandlerOptions): () => void;
|
|
1476
|
+
on<T = unknown>(hookId: string[], handler: (data: T, context: HookContext) => T | void | Promise<T | void>, options?: HookHandlerOptions): () => void;
|
|
1477
|
+
/**
|
|
1478
|
+
* Emit a hook (trigger all registered handlers)
|
|
1479
|
+
*
|
|
1480
|
+
* Default mode: handlers run in **parallel**, return value from the
|
|
1481
|
+
* first handler that returns something (service call pattern).
|
|
1482
|
+
*
|
|
1483
|
+
* Pipe mode (`{ mode: 'pipe' }` or legacy `{ pipe: true }`): handlers run
|
|
1484
|
+
* **serially**, each receives the previous handler's output (data
|
|
1485
|
+
* transformation / synchronous service-call pattern).
|
|
1486
|
+
*
|
|
1487
|
+
* @param hookId - The hook ID
|
|
1488
|
+
* @param data - Data to pass to handlers
|
|
1489
|
+
* @param options - Emit options
|
|
1490
|
+
* @returns The handler result (or original data if no handler returns)
|
|
1491
|
+
*
|
|
1492
|
+
* @example
|
|
1493
|
+
* // Parallel (default) — notification, no return needed
|
|
1494
|
+
* await ctx.hooks.emit('crm.customer.promoted', { customerId: 'xxx' });
|
|
1495
|
+
*
|
|
1496
|
+
* @example
|
|
1497
|
+
* // Parallel — service call, get return value
|
|
1498
|
+
* const customer = await ctx.hooks.emit('crm.createProspect', { name: 'Acme' });
|
|
1499
|
+
*
|
|
1500
|
+
* @example
|
|
1501
|
+
* // Pipe mode — serial data transformation
|
|
1502
|
+
* const enrichedData = await ctx.hooks.emit('crm.customer.beforeCreate', data, { mode: 'pipe' });
|
|
1503
|
+
*/
|
|
1504
|
+
emit<K extends keyof HookEventMap>(hookId: K, data: HookEventMap[K], options?: HookEmitOptions): Promise<HookEventMap[K]>;
|
|
1505
|
+
emit<T = unknown>(hookId: string, data: T, options?: HookEmitOptions): Promise<T>;
|
|
1506
|
+
/**
|
|
1507
|
+
* List all available hooks
|
|
1508
|
+
*
|
|
1509
|
+
* Returns the list of hook definitions that plugins can subscribe to.
|
|
1510
|
+
* Useful for discovery and validation.
|
|
1511
|
+
*
|
|
1512
|
+
* @returns Array of hook definitions
|
|
1513
|
+
*/
|
|
1514
|
+
listHooks(): Promise<Array<{
|
|
1515
|
+
id: string;
|
|
1516
|
+
description: string;
|
|
1517
|
+
}>>;
|
|
1518
|
+
/** @deprecated Use `on()` instead */
|
|
1519
|
+
addAction<T = unknown>(hookId: string, handler: (data: T, ctx: PluginContext) => void | Promise<void>, options?: HookHandlerOptions): () => void;
|
|
1520
|
+
/** @deprecated Use `on()` instead */
|
|
1521
|
+
addFilter<T = unknown>(hookId: string, handler: (data: T, ctx: PluginContext) => T | Promise<T>, options?: HookHandlerOptions): () => void;
|
|
1522
|
+
/** @deprecated Use `emit(hookId, data, { pipe: true })` instead */
|
|
1523
|
+
applyFilter<T = unknown>(hookId: string, initialValue: T): Promise<T>;
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Hook emit options
|
|
1527
|
+
*/
|
|
1528
|
+
interface HookEmitOptions {
|
|
1529
|
+
/**
|
|
1530
|
+
* Emit mode.
|
|
1531
|
+
* - `event` (default): parallel fire-and-forget / first-result-wins
|
|
1532
|
+
* - `pipe`: serial synchronous pipeline, fail-fast on handler error
|
|
1533
|
+
* - `effect`: serial synchronous effects, fail-fast, ignores handler return values
|
|
1534
|
+
*/
|
|
1535
|
+
mode?: "event" | "pipe" | "effect";
|
|
1536
|
+
/**
|
|
1537
|
+
* Dispatch intent.
|
|
1538
|
+
* - `auto` (default): command-like bare ids may route to pluginApis.
|
|
1539
|
+
* - `command`: only route to the matching pluginApis procedure.
|
|
1540
|
+
* - `hook`: only notify registered hook listeners.
|
|
1541
|
+
*/
|
|
1542
|
+
dispatch?: "auto" | "command" | "hook";
|
|
1543
|
+
/**
|
|
1544
|
+
* Shared database transaction.
|
|
1545
|
+
*
|
|
1546
|
+
* Only valid with `mode: 'pipe'` because event mode is intentionally
|
|
1547
|
+
* fire-and-forget and does not provide transactional guarantees.
|
|
1548
|
+
*/
|
|
1549
|
+
tx?: any;
|
|
1550
|
+
/**
|
|
1551
|
+
* Request user id to pass through to synchronous hook handlers.
|
|
1552
|
+
*/
|
|
1553
|
+
userId?: string;
|
|
1554
|
+
/** @deprecated Use `mode: 'pipe'` instead. Kept for backward compatibility. */
|
|
1555
|
+
pipe?: boolean;
|
|
1556
|
+
}
|
|
1557
|
+
interface HookTransaction {
|
|
1558
|
+
run<T>(callback: (db: NonNullable<PluginContext["db"]>) => Promise<T>): Promise<T>;
|
|
1559
|
+
}
|
|
1560
|
+
interface HookContext {
|
|
1561
|
+
id: string;
|
|
1562
|
+
hookId: string;
|
|
1563
|
+
traceId?: string;
|
|
1564
|
+
pluginId: string;
|
|
1565
|
+
organizationId?: string | undefined;
|
|
1566
|
+
userId?: string | undefined;
|
|
1567
|
+
tx?: HookTransaction | undefined;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Hook Abort Error - Thrown by filters to block operations
|
|
1571
|
+
*
|
|
1572
|
+
* When a filter handler throws this error, the operation is aborted
|
|
1573
|
+
* and the error message is returned to the caller.
|
|
1574
|
+
*/
|
|
1575
|
+
declare class HookAbortError extends Error {
|
|
1576
|
+
constructor(message: string);
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Plugin Usage Capability - Explicit billing consumption
|
|
1580
|
+
*
|
|
1581
|
+
* Used by plugins that need dynamic consumption amounts per request
|
|
1582
|
+
* (e.g., token count, file size MB). For fixed consumption (1 unit per call),
|
|
1583
|
+
* use manifest `capabilities.billing.procedures` instead (zero-code).
|
|
1584
|
+
*/
|
|
1585
|
+
interface PluginUsageCapability {
|
|
1586
|
+
/**
|
|
1587
|
+
* Consume usage for a specific billing subject
|
|
1588
|
+
*
|
|
1589
|
+
* @param subject - Billing capability subject (must use {pluginId}.* prefix)
|
|
1590
|
+
* @param amount - Amount to consume (default: 1)
|
|
1591
|
+
* @throws EntitlementDeniedError if capability not approved or no quota
|
|
1592
|
+
*/
|
|
1593
|
+
consume(subject: string, amount?: number): Promise<void>;
|
|
1594
|
+
}
|
|
1595
|
+
type ApiPayload<T> = {
|
|
1596
|
+
[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];
|
|
1597
|
+
};
|
|
1598
|
+
|
|
1599
|
+
export { type PluginMetricsAllowedLabels as $, type ApiPayload as A, type PluginAssetCreateOptions as B, type PluginAssetInfo as C, type PluginAssetQuery as D, type EAuthModel as E, type PluginAssetUpdateData as F, type PluginAssetVariant as G, type HookContext as H, type PluginCurrencyCapability as I, type PluginEAuthCapability as J, type PluginEntityExtensionCapability as K, type PluginEntityExtensionFilter as L, MARKETPLACE_PUBLISH_AUTH_METHODS as M, type PluginFileCapability as N, type OpaquePublisherCandidateV1 as O, type PluginMediaInfo as P, type PluginFileInfo as Q, type PluginFileQuery as R, type PluginFileUploadInput as S, type PluginHookCapability as T, type PluginJobOptions as U, type PluginJobStatus as V, type PluginMediaCapability as W, type PluginMediaQuery as X, type PluginMediaUpdateData as Y, type PluginMediaUploadInput as Z, type PluginMediaVariant as _, type PluginContext as a, type PluginMetricsCapability as a0, type PluginNotificationActor as a1, type PluginNotificationCapability as a2, type PluginNotificationChannel as a3, type PluginNotificationEvent as a4, type PluginNotificationInput as a5, type PluginNotificationResult as a6, type PluginNotificationSendParams as a7, type PluginNotificationSendResult as a8, type PluginNotificationTarget as a9, type WebPluginSiteInfo as aA, type WebPluginTenantInfo as aB, type WebSlotExtensionQuery as aC, type WebSlotQueryResult as aD, type WebSlotRemoteExtension as aE, type WebSlotRenderOptions as aF, type WebSlotRenderRequest as aG, type WebSlotRenderResult as aH, type WebSlotRenderer as aI, type PluginNotificationTemplate as aa, type PluginOrganizationProvisioningCapability as ab, type PluginPaginatedResult as ac, type PluginPermissionCapability as ad, type PluginPermissionCheckContext as ae, type PluginPermissionDef as af, type PluginQueueCapability as ag, type PluginScopedDb as ah, type PluginSettingEntry as ai, type PluginSettingOptions as aj, type PluginSettingsCapability as ak, type PluginStorageCapability as al, type PluginStorageProvider as am, type PluginStorageProviderConfig as an, type PluginStorageProviderInfo as ao, type PluginStorageUploadInput as ap, type PluginStorageUploadResult as aq, type PluginTraceCapability as ar, type PluginUsageCapability as as, type PluginWebCapability as at, type ReadonlyPluginScopedDb as au, type WebPluginHead as av, type WebPluginHeadLink as aw, type WebPluginRouteHandler as ax, type WebPluginRouteRequest as ay, type WebPluginRouteResult as az, type HookHandlerOptions as b, type PluginLogger as c, type EAuthProvider as d, type EAuthRefreshInput as e, type EAuthRefreshResult as f, type EAuthStatus as g, type EAuthTokenResult as h, type EAuthUpsertInput as i, type EAuthUse as j, HookAbortError as k, type HookEmitOptions as l, HookPriority as m, type HookTransaction as n, type MarketplaceAttestationTargetV1 as o, type MarketplaceExecutionErrorCode as p, type MarketplaceExecutionFailureCode as q, type MarketplaceOrganizationExecutionV1 as r, type MarketplacePlatformReadAction as s, type MarketplacePublishActor as t, type MarketplacePublishAuthMethod as u, type MarketplacePublisherAction as v, type MarketplaceRegistrySigningCapability as w, type PluginApisCapability as x, type PluginArtifactCapability as y, type PluginAssetCapability as z };
|