@vertesia/common 1.4.0 → 1.5.0-dev.20260713.113008Z

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 (90) hide show
  1. package/lib/access-control.d.ts +31 -6
  2. package/lib/access-control.d.ts.map +1 -1
  3. package/lib/access-control.js +12 -2
  4. package/lib/access-control.js.map +1 -1
  5. package/lib/apikey.d.ts +29 -5
  6. package/lib/apikey.d.ts.map +1 -1
  7. package/lib/apikey.js.map +1 -1
  8. package/lib/apps.d.ts +78 -4
  9. package/lib/apps.d.ts.map +1 -1
  10. package/lib/apps.js +2 -0
  11. package/lib/apps.js.map +1 -1
  12. package/lib/audit-trail.d.ts +15 -2
  13. package/lib/audit-trail.d.ts.map +1 -1
  14. package/lib/audit-trail.js +20 -0
  15. package/lib/audit-trail.js.map +1 -1
  16. package/lib/environment.d.ts +7 -0
  17. package/lib/environment.d.ts.map +1 -1
  18. package/lib/index.d.ts +3 -0
  19. package/lib/index.d.ts.map +1 -1
  20. package/lib/index.js +2 -0
  21. package/lib/index.js.map +1 -1
  22. package/lib/integrations.d.ts +13 -1
  23. package/lib/integrations.d.ts.map +1 -1
  24. package/lib/integrations.js.map +1 -1
  25. package/lib/platform-event-validation.d.ts +45 -0
  26. package/lib/platform-event-validation.d.ts.map +1 -0
  27. package/lib/platform-event-validation.js +323 -0
  28. package/lib/platform-event-validation.js.map +1 -0
  29. package/lib/platform-event.d.ts +665 -0
  30. package/lib/platform-event.d.ts.map +1 -0
  31. package/lib/platform-event.js +2 -0
  32. package/lib/platform-event.js.map +1 -0
  33. package/lib/project.d.ts +32 -0
  34. package/lib/project.d.ts.map +1 -1
  35. package/lib/project.js.map +1 -1
  36. package/lib/prompt.d.ts +1 -0
  37. package/lib/prompt.d.ts.map +1 -1
  38. package/lib/prompt.js.map +1 -1
  39. package/lib/query.d.ts +1 -0
  40. package/lib/query.d.ts.map +1 -1
  41. package/lib/rate-limiter.d.ts +72 -0
  42. package/lib/rate-limiter.d.ts.map +1 -1
  43. package/lib/roles/types.d.ts +1 -1
  44. package/lib/roles/types.js +1 -1
  45. package/lib/secrets.d.ts +59 -0
  46. package/lib/secrets.d.ts.map +1 -1
  47. package/lib/store/agent-run.d.ts +17 -1
  48. package/lib/store/agent-run.d.ts.map +1 -1
  49. package/lib/store/process-validation.js +19 -0
  50. package/lib/store/process-validation.js.map +1 -1
  51. package/lib/store/store.d.ts +234 -10
  52. package/lib/store/store.d.ts.map +1 -1
  53. package/lib/store/store.js +3 -1
  54. package/lib/store/store.js.map +1 -1
  55. package/lib/store/workflow.d.ts +6 -5
  56. package/lib/store/workflow.d.ts.map +1 -1
  57. package/lib/store/workflow.js.map +1 -1
  58. package/lib/sts-token-types.d.ts +1 -0
  59. package/lib/sts-token-types.d.ts.map +1 -1
  60. package/lib/sts-token-types.js.map +1 -1
  61. package/lib/user.d.ts +36 -1
  62. package/lib/user.d.ts.map +1 -1
  63. package/lib/user.js +39 -0
  64. package/lib/user.js.map +1 -1
  65. package/lib/vertesia-common.js +3 -2
  66. package/lib/vertesia-common.js.map +1 -1
  67. package/package.json +4 -7
  68. package/src/access-control.ts +31 -6
  69. package/src/apikey.ts +29 -5
  70. package/src/apps.ts +87 -4
  71. package/src/audit-trail.ts +34 -18
  72. package/src/environment.ts +7 -0
  73. package/src/index.ts +25 -0
  74. package/src/integrations.ts +14 -1
  75. package/src/platform-event-validation.test.ts +225 -0
  76. package/src/platform-event-validation.ts +359 -0
  77. package/src/platform-event.ts +771 -0
  78. package/src/project.ts +38 -0
  79. package/src/prompt.ts +1 -0
  80. package/src/query.ts +1 -0
  81. package/src/rate-limiter.ts +78 -0
  82. package/src/roles/types.ts +1 -1
  83. package/src/secrets.ts +69 -0
  84. package/src/store/agent-run.ts +22 -1
  85. package/src/store/process-validation.test.ts +62 -0
  86. package/src/store/process-validation.ts +18 -0
  87. package/src/store/store.ts +263 -10
  88. package/src/store/workflow.ts +7 -5
  89. package/src/sts-token-types.ts +1 -0
  90. package/src/user.ts +49 -1
package/src/project.ts CHANGED
@@ -269,6 +269,39 @@ export const BrowserUseProjectConfigurationSchema: JSONSchemaType<BrowserUseProj
269
269
  export type ProjectSearchTier = 'standard' | 'performance';
270
270
  export type ElasticsearchBackend = 'serverless' | 'hosted';
271
271
 
272
+ export interface ProjectIntakeConfiguration {
273
+ /**
274
+ * Generate table-of-content sections during standard document intake.
275
+ * Defaults to false.
276
+ */
277
+ generate_toc?: boolean;
278
+
279
+ /**
280
+ * Skip table-of-content generation when the document text exceeds this many characters.
281
+ * Avoids sending very large documents through the TOC interactions. Unset means no limit.
282
+ */
283
+ generate_toc_max_size?: number;
284
+
285
+ /**
286
+ * Select or assign a content type during standard intake.
287
+ * Defaults to true.
288
+ */
289
+ generate_content_type?: boolean;
290
+
291
+ /**
292
+ * Extract document properties after content type assignment.
293
+ * Defaults to true.
294
+ */
295
+ generate_properties?: boolean;
296
+
297
+ /**
298
+ * Default content type assigned during intake when type selection finds no matching type.
299
+ * A type id resolvable in this project (a stored `oid:` type, an `app:` type, or a `sys:` type).
300
+ * Defaults to the platform `sys:GenericDocument` when unset.
301
+ */
302
+ default_content_type?: string;
303
+ }
304
+
272
305
  export interface ProjectConfiguration {
273
306
  human_context?: string;
274
307
 
@@ -321,6 +354,11 @@ export interface ProjectConfiguration {
321
354
  backend?: ElasticsearchBackend;
322
355
  };
323
356
 
357
+ /**
358
+ * Standard content intake behavior.
359
+ */
360
+ intake?: ProjectIntakeConfiguration;
361
+
324
362
  /**
325
363
  * Primary language for full-text search analysis.
326
364
  * ISO 639-1 code (e.g., 'en', 'fr', 'ja', 'de').
package/src/prompt.ts CHANGED
@@ -46,6 +46,7 @@ export interface PromptTemplateRef {
46
46
  version: number;
47
47
  status: PromptStatus;
48
48
  content_type?: TemplateType;
49
+ tags?: string[];
49
50
  created_at: Date;
50
51
  updated_at: Date;
51
52
  }
package/src/query.ts CHANGED
@@ -64,6 +64,7 @@ export interface ObjectTypeSearchQuery extends SimpleSearchQuery {
64
64
 
65
65
  export interface PromptSearchQuery extends SimpleSearchQuery {
66
66
  role?: string;
67
+ tags?: string[];
67
68
  matchInteractions?: boolean;
68
69
  }
69
70
 
@@ -32,3 +32,81 @@ export interface RateLimiterStatus {
32
32
 
33
33
  // Always return an array for consistency
34
34
  export type RateLimiterStatusResponse = RateLimiterStatus[];
35
+
36
+ /**
37
+ * A caller's own quota standing (GET /api/v1/quota/standing) — "where am I".
38
+ * API rate limits are genuinely per-tenant; workflow admission and the LLM limiter are
39
+ * global/discovered, so they are reported as posture, not per-tenant numbers.
40
+ */
41
+ export interface QuotaStandingWindow {
42
+ /** Effective limit for this window (after effective account tier + per-tenant override). */
43
+ limit: number;
44
+ /** Requests used in the current window. */
45
+ used: number;
46
+ /** Requests remaining (max(0, limit - used)). */
47
+ remaining: number;
48
+ window_ms: number;
49
+ }
50
+
51
+ export interface QuotaStandingResource {
52
+ resource: string;
53
+ name: string;
54
+ burst: QuotaStandingWindow;
55
+ quota: QuotaStandingWindow;
56
+ }
57
+
58
+ export interface QuotaStandingAdmissionClass {
59
+ /** Workflow class (e.g. ExecuteConversationWorkflow). */
60
+ class: string;
61
+ /** This tenant's currently active (leased) slots for the class. */
62
+ tenant_active: number;
63
+ }
64
+
65
+ /**
66
+ * Effective quota tier name after account-level overrides and account-type derivation.
67
+ * Code-defined tier names are currently `QuotaTier`, but this remains a string because deployments
68
+ * can introduce quota tiers through configuration.
69
+ */
70
+ export type QuotaEffectiveTier = string;
71
+
72
+ export interface QuotaStandingResponse {
73
+ tenant_id: string;
74
+ /**
75
+ * False when the limiter store (Redis) was unavailable, so `api`/`admission` are empty because
76
+ * standing could not be read — NOT because there are no limits. Limiters fail open in this case.
77
+ */
78
+ available: boolean;
79
+ /** Deployment base tier (env QUOTA_BASE_TIER); `default` = the static limits stand. */
80
+ base_tier: string;
81
+ /**
82
+ * Tier used to compute the API limits below: explicit account `quota_tier`, else account_type
83
+ * derived tier, else `base_tier` when the account tier could not be resolved.
84
+ */
85
+ effective_tier: QuotaEffectiveTier;
86
+ /** Per-resource API rate-limit standing (effective limits + current usage). */
87
+ api: QuotaStandingResource[];
88
+ /**
89
+ * Workflow admission: per-tenant active slots per probed class. The budget itself is global and
90
+ * discovered (AIMD), not a per-tenant number — this is occupancy, not a limit.
91
+ */
92
+ admission: {
93
+ classes: QuotaStandingAdmissionClass[];
94
+ note: string;
95
+ };
96
+ /** The LLM interaction limiter is shared per environment/model, not per tenant. */
97
+ llm: {
98
+ note: string;
99
+ };
100
+ }
101
+
102
+ /**
103
+ * Lightweight per-account quota tier for the calling account — served by `GET /api/v1/quota/tier`.
104
+ * A cheap, cacheable read that lets another service (e.g. zeno-server's API rate limiter) resolve
105
+ * the caller's tier through studio-server instead of reaching into the account store directly.
106
+ * `tier` is the SAME value {@link QuotaStandingResponse.effective_tier} reports: the account's
107
+ * explicit `quota_tier`, else its account_type-derived tier, else the deployment base tier when the
108
+ * account tier cannot be resolved.
109
+ */
110
+ export interface QuotaTierResponse {
111
+ tier: QuotaEffectiveTier;
112
+ }
@@ -8,7 +8,7 @@ import type { Permission } from '../access-control.js';
8
8
  */
9
9
 
10
10
  /**
11
- * Kind of object a ContentSet's `resource_props` matches at query time. Used
11
+ * Kind of object a ResourceSet's `resource_props` matches at query time. Used
12
12
  * in `AceConditions.scope` (validated at runtime against this list) and as
13
13
  * the prefix in JWT `content_security` keys (e.g. `collection:read`).
14
14
  *
package/src/secrets.ts CHANGED
@@ -3,6 +3,7 @@ import type {
3
3
  WebsiteCredentialRecord,
4
4
  WebsiteCredentialSecretInput,
5
5
  } from './browser-credentials.js';
6
+ import type { EventCategory } from './platform-event.js';
6
7
 
7
8
  // First supported top-level secret kind. OAuth connector grants continue to use
8
9
  // the OAuth/MCP token flows and can be materialized later by tools that need them.
@@ -58,3 +59,71 @@ export interface UpdateSecretRequest {
58
59
  clear_totp?: boolean;
59
60
  clear_oauth?: boolean;
60
61
  }
62
+
63
+ export interface EventWebhookSigningSecretRequest {
64
+ account_id?: string;
65
+ project_id: string;
66
+ }
67
+
68
+ export interface EventWebhookSigningSecretResponse {
69
+ subscription_id: string;
70
+ secret: string;
71
+ secret_label: string;
72
+ }
73
+
74
+ export interface SignEventWebhookRequest extends EventWebhookSigningSecretRequest {
75
+ delivery_id: string;
76
+ body: string;
77
+ event_id: string;
78
+ event_category: EventCategory;
79
+ action: string;
80
+ timestamp?: number;
81
+ }
82
+
83
+ export interface SignEventWebhookResponse {
84
+ headers: Record<string, string>;
85
+ timestamp: number;
86
+ signature: string;
87
+ }
88
+
89
+ export interface EventIngestSigningSecretRequest {
90
+ account_id?: string;
91
+ project_id: string;
92
+ }
93
+
94
+ export interface EventIngestSigningSecretResponse {
95
+ channel_id: string;
96
+ secret: string;
97
+ secret_label: string;
98
+ }
99
+
100
+ export interface VerifyEventIngestSignatureRequest extends EventIngestSigningSecretRequest {
101
+ /** Raw request body bytes (exactly as received) the sender signed. */
102
+ body: string;
103
+ /** Signature value from the request header. */
104
+ signature_header: string;
105
+ algorithm?: 'sha256' | 'sha1';
106
+ encoding?: 'hex' | 'base64';
107
+ /** Literal prefix to strip from the header value, e.g. `sha256=`. */
108
+ prefix?: string;
109
+ }
110
+
111
+ export interface VerifyEventIngestSignatureResponse {
112
+ valid: boolean;
113
+ }
114
+
115
+ export interface GithubInstallationTokenRequest {
116
+ account_id?: string;
117
+ project_id: string;
118
+ /** Numeric GitHub App installation id (from the trusted webhook payload, never agent-supplied). */
119
+ installation_id: string;
120
+ /** `owner/name` of the repo to scope the token to. Required — tokens are always repository-scoped. */
121
+ repo: string;
122
+ }
123
+
124
+ export interface GithubInstallationTokenResponse {
125
+ /** Short-lived, repository-scoped GitHub App installation token. */
126
+ token: string;
127
+ /** ISO-8601 expiry returned by GitHub, when available. */
128
+ expires_at?: string;
129
+ }
@@ -20,6 +20,8 @@ import type {
20
20
  InteractionRef,
21
21
  RunSource,
22
22
  } from '../interaction.js';
23
+ import type { EventRef } from '../platform-event.js';
24
+ import type { ResourceRef } from '../refs.js';
23
25
  import type { AgentEvent } from '../workflow-analytics.js';
24
26
  import type { AgentToolApprovalMode } from './agent-approval.js';
25
27
  import type { ProcessDefinitionBody, ProcessState } from './process.js';
@@ -53,7 +55,7 @@ export type AgentRunArchiveState = 'none' | 'pending' | 'archiving' | 'complete'
53
55
  /**
54
56
  * How the agent run was created.
55
57
  */
56
- export type AgentRunType = 'api' | 'schedule';
58
+ export type AgentRunType = 'api' | 'schedule' | 'event_subscription';
57
59
 
58
60
  /**
59
61
  * Internal discriminator key for documents stored in the agent_runs collection.
@@ -130,6 +132,12 @@ export interface RunBase {
130
132
  /** Schedule ID — set when this run was triggered by a Temporal schedule */
131
133
  schedule_id?: string;
132
134
 
135
+ /** Event subscription ID — set when this run was triggered by the event bus. */
136
+ event_subscription_id?: string;
137
+
138
+ /** Event reference — set when this run was triggered by the event bus. */
139
+ event_ref?: EventRef;
140
+
133
141
  /** Archive lifecycle state */
134
142
  archive_state?: AgentRunArchiveState;
135
143
 
@@ -235,6 +243,13 @@ export interface AgentRun<TData = Record<string, unknown>, TProperties = Record<
235
243
 
236
244
  interactionRef: InteractionRef;
237
245
 
246
+ /**
247
+ * Resolved environment reference (name resolved from `config.environment` id).
248
+ * Populated by the list endpoint; may be absent on other endpoints or when the id
249
+ * cannot be resolved, in which case consumers should fall back to `config.environment`.
250
+ */
251
+ environmentRef?: ResourceRef;
252
+
238
253
  // --- Lifecycle ---
239
254
 
240
255
  /** Current status of the agent run */
@@ -749,6 +764,12 @@ export interface AgentRunSearchHit {
749
764
  /** Schedule ID (if schedule-triggered) */
750
765
  schedule_id?: string;
751
766
 
767
+ /** Event subscription ID (if event-triggered) */
768
+ event_subscription_id?: string;
769
+
770
+ /** Event reference (if event-triggered) */
771
+ event_ref?: EventRef;
772
+
752
773
  /** How the run was created */
753
774
  source_type?: AgentRunType;
754
775
 
@@ -410,6 +410,68 @@ describe('process definition validation', () => {
410
410
  expect(result.errors).toContain('human_task node "review" is missing task');
411
411
  });
412
412
 
413
+ it('rejects human_task fields that use "id" instead of "name"', () => {
414
+ const definition = validDefinition();
415
+ definition.nodes.review.task = {
416
+ title: 'Review',
417
+ fields: [{ id: 'approved', type: 'boolean' } as unknown as { name: string; type: 'boolean' }],
418
+ };
419
+
420
+ const result = getProcessDefinitionValidationResult(definition);
421
+
422
+ expect(result.valid).toBe(false);
423
+ expect(result.errors).toContain(
424
+ 'human_task node "review" task.fields[0].name must be a non-empty string (not "id")',
425
+ );
426
+ });
427
+
428
+ it('rejects human_task fields with an unsupported type', () => {
429
+ const definition = validDefinition();
430
+ definition.nodes.review.task = {
431
+ title: 'Review',
432
+ fields: [{ name: 'approved', type: 'date' } as unknown as { name: string; type: 'string' }],
433
+ };
434
+
435
+ const result = getProcessDefinitionValidationResult(definition);
436
+
437
+ expect(result.valid).toBe(false);
438
+ expect(result.errors).toContain(
439
+ 'human_task node "review" task.fields[0].type must be one of string, number, boolean, select, text',
440
+ );
441
+ });
442
+
443
+ it('rejects select fields without options', () => {
444
+ const definition = validDefinition();
445
+ definition.nodes.review.task = {
446
+ title: 'Review',
447
+ fields: [{ name: 'decision', type: 'select' }],
448
+ };
449
+
450
+ const result = getProcessDefinitionValidationResult(definition);
451
+
452
+ expect(result.valid).toBe(false);
453
+ expect(result.errors).toContain(
454
+ 'human_task node "review" task.fields[0] of type "select" requires a non-empty options[] array',
455
+ );
456
+ });
457
+
458
+ it('accepts human_task select fields with options', () => {
459
+ const definition = validDefinition();
460
+ definition.nodes.review.task = {
461
+ title: 'Review',
462
+ fields: [
463
+ {
464
+ name: 'decision',
465
+ type: 'select',
466
+ options: ['approved', 'rejected'],
467
+ required: true,
468
+ },
469
+ ],
470
+ };
471
+
472
+ expect(() => validateProcessDefinitionBody(definition)).not.toThrow();
473
+ });
474
+
413
475
  it('rejects overly deep guard rules', () => {
414
476
  const definition = validDefinition();
415
477
  let guard: Record<string, unknown> = { var: 'approved' };
@@ -113,6 +113,24 @@ function validateNodeDefinition(
113
113
  errors.push(`human_task node "${nodeId}" task title is missing`);
114
114
  } else if (!Array.isArray(node.task.fields)) {
115
115
  errors.push(`human_task node "${nodeId}" task fields must be an array`);
116
+ } else {
117
+ const allowedTypes = ['string', 'number', 'boolean', 'select', 'text'];
118
+ (node.task.fields as unknown[]).forEach((field, i) => {
119
+ const path = `human_task node "${nodeId}" task.fields[${i}]`;
120
+ if (!isRecord(field)) {
121
+ errors.push(`${path} must be an object`);
122
+ return;
123
+ }
124
+ if (typeof field.name !== 'string' || field.name.length === 0) {
125
+ errors.push(`${path}.name must be a non-empty string (not "id")`);
126
+ }
127
+ if (typeof field.type !== 'string' || !allowedTypes.includes(field.type)) {
128
+ errors.push(`${path}.type must be one of ${allowedTypes.join(', ')}`);
129
+ }
130
+ if (field.type === 'select' && !(Array.isArray(field.options) && field.options.length > 0)) {
131
+ errors.push(`${path} of type "select" requires a non-empty options[] array`);
132
+ }
133
+ });
116
134
  }
117
135
  }
118
136
  if (node.type === 'tool') {