@axiom-lattice/protocols 4.7.1 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +28 -0
- package/dist/index.d.mts +175 -12
- package/dist/index.d.ts +175 -12
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/AgentLatticeProtocol.ts +6 -0
- package/src/ChannelAdapterProtocol.ts +13 -1
- package/src/ChannelInstallationStoreProtocol.ts +15 -1
- package/src/ModelLatticeProtocol.ts +11 -0
- package/src/ModelProviderProtocol.ts +68 -6
- package/src/PluginDeploymentStoreProtocol.ts +56 -0
- package/src/PluginProtocol.ts +6 -3
- package/src/ProjectRoomProtocol.ts +6 -0
- package/src/TrustedRunContextProtocol.ts +17 -1
- package/src/__tests__/TrustedRunContextProtocol.test.ts +39 -0
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -41,6 +41,12 @@ interface BaseAgentConfig {
|
|
|
41
41
|
name: string; // Name
|
|
42
42
|
description: string; // Description
|
|
43
43
|
prompt: string; // Prompt
|
|
44
|
+
/**
|
|
45
|
+
* Owner user id when this config represents a user's personal assistant.
|
|
46
|
+
* `undefined` means a tenant/workspace-shared agent, which is the only kind
|
|
47
|
+
* discoverable in shared contexts (e.g. a public room's executor list).
|
|
48
|
+
*/
|
|
49
|
+
ownerUserId?: string;
|
|
44
50
|
/**
|
|
45
51
|
* Key of the parent agent to inherit configuration from.
|
|
46
52
|
* When set, unspecified fields are inherited from the parent agent's config.
|
|
@@ -81,7 +81,15 @@ export interface ChannelAdapter<TConfig = unknown> {
|
|
|
81
81
|
*
|
|
82
82
|
* 与 `sendReply` 不同,这不是对某条入站消息的最终回复,而是运行中途
|
|
83
83
|
* 产生的一条独立 bot 消息(例如 Project Room 的 clarify 卡片)。
|
|
84
|
-
*
|
|
84
|
+
*
|
|
85
|
+
* 支持两种(互斥的)关联方式,均由 `message.metadata` 承载:
|
|
86
|
+
* - `message.metadata.inputMessageId`:legacy presence 关联,指向触发该
|
|
87
|
+
* 运行的入站队列消息;需配合 `replyTarget.rawTarget` 中的
|
|
88
|
+
* `sourceRoomMessageId` / `inputMessageId`。
|
|
89
|
+
* - `message.metadata.correlationKey`(可选):**source-less/correlated**
|
|
90
|
+
* 中断,没有入站输入消息;由调用方提供关联键,幂等性以「每次中断」为单位
|
|
91
|
+
* (idempotency key 派生自该 correlationKey),`replyTarget.rawTarget`
|
|
92
|
+
* 只需 `targetMembershipId`。
|
|
85
93
|
*/
|
|
86
94
|
sendInterrupt?(
|
|
87
95
|
replyTarget: ReplyTarget,
|
|
@@ -112,6 +120,10 @@ export interface ChannelAdapter<TConfig = unknown> {
|
|
|
112
120
|
* 可选:断开持久连接并停止接收事件。
|
|
113
121
|
* 当 channel installation 被禁用或删除时调用。
|
|
114
122
|
* `installationId` 用于标识要断开的具体安装实例。
|
|
123
|
+
*
|
|
124
|
+
* 实现必须是**幂等**且对未连接的 installation 安全(no-op):多副本下
|
|
125
|
+
* `ChannelConnectionLeader` 在失去租约时会对共享 store 中的全部启用安装
|
|
126
|
+
* 调用 `disconnect`,其中可能包含本副本从未 `connect` 的实例。
|
|
115
127
|
*/
|
|
116
128
|
disconnect?(installationId: string): Promise<void>;
|
|
117
129
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Channel types persisted by the installation store, including internal-only channels. */
|
|
2
|
-
export type ChannelInstallationType = "lark" | "email" | "slack" | "wechat" | "room";
|
|
2
|
+
export type ChannelInstallationType = "lark" | "email" | "slack" | "wechat" | "wecom" | "room";
|
|
3
3
|
|
|
4
4
|
/** Channel types exposed by the public installation management API. */
|
|
5
5
|
export type PublicChannelInstallationType = Exclude<ChannelInstallationType, "room">;
|
|
@@ -19,6 +19,19 @@ export interface WechatChannelInstallationConfig {
|
|
|
19
19
|
uin?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Credentials for a WeCom (企业微信) 智能机器人 installation using the
|
|
24
|
+
* long-connection (API 模式) transport. Only `botId` + `secret` are needed —
|
|
25
|
+
* no CorpID / AgentID / Token / EncodingAESKey, and no callback URL.
|
|
26
|
+
*/
|
|
27
|
+
export interface WecomChannelInstallationConfig {
|
|
28
|
+
/** 机器人 BotID. */
|
|
29
|
+
botId: string;
|
|
30
|
+
/** 长连接专用 Secret. */
|
|
31
|
+
secret: string;
|
|
32
|
+
assistantId?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
/** A persisted tenant-scoped channel installation. */
|
|
23
36
|
export interface ChannelInstallation<TConfig = unknown> {
|
|
24
37
|
id: string;
|
|
@@ -49,6 +62,7 @@ type PublicInstallationBase = Omit<CreateChannelInstallationInput, "channel" | "
|
|
|
49
62
|
export type CreateChannelInstallationRequest = PublicInstallationBase & (
|
|
50
63
|
| { channel: "lark"; config: LarkChannelInstallationConfig }
|
|
51
64
|
| { channel: "wechat"; config: WechatChannelInstallationConfig }
|
|
65
|
+
| { channel: "wecom"; config: WecomChannelInstallationConfig }
|
|
52
66
|
| { channel: "email" | "slack"; config: Record<string, unknown> }
|
|
53
67
|
);
|
|
54
68
|
|
|
@@ -24,6 +24,17 @@ export interface LLMConfig {
|
|
|
24
24
|
streaming?: boolean;
|
|
25
25
|
apiKeyEnvName?: string;
|
|
26
26
|
apiKey?: string;
|
|
27
|
+
/**
|
|
28
|
+
* The upstream requires no credentials.
|
|
29
|
+
*
|
|
30
|
+
* A locally hosted model server — Ollama, vLLM, LM Studio — usually accepts
|
|
31
|
+
* unauthenticated requests. Without this flag a config carrying no key falls
|
|
32
|
+
* back to `process.env[apiKeyEnvName ?? "<PROVIDER>_API_KEY"]`, which would
|
|
33
|
+
* send the *gateway's own* deployment credential to whatever host the tenant
|
|
34
|
+
* configured. Setting it makes "no credential" an explicit statement rather
|
|
35
|
+
* than a missing value, so the fallback never runs.
|
|
36
|
+
*/
|
|
37
|
+
noAuth?: boolean;
|
|
27
38
|
baseURL?: string;
|
|
28
39
|
modelKwargs?: Record<string, any>;
|
|
29
40
|
extra?: Record<string, any>;
|
|
@@ -237,14 +237,16 @@ export interface CreateModelProviderRequest {
|
|
|
237
237
|
baseURL: string;
|
|
238
238
|
|
|
239
239
|
/**
|
|
240
|
-
* Upstream API key.
|
|
240
|
+
* Upstream API key. Optional: omitted means the upstream needs no
|
|
241
|
+
* authentication, which is the normal case for a locally hosted model server
|
|
242
|
+
* (Ollama, vLLM, LM Studio).
|
|
241
243
|
*
|
|
242
|
-
* A keyless provider
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
244
|
+
* A keyless provider must never fall back to the gateway's own environment
|
|
245
|
+
* credentials. `initChatModel` would otherwise reach for `OPENAI_API_KEY` and
|
|
246
|
+
* send the deployment's credential to the tenant's host. The runtime config
|
|
247
|
+
* carries an explicit no-auth marker instead — see `LLMConfig.noAuth`.
|
|
246
248
|
*/
|
|
247
|
-
apiKey
|
|
249
|
+
apiKey?: string;
|
|
248
250
|
|
|
249
251
|
/**
|
|
250
252
|
* Whether this provider participates in discovery and registration
|
|
@@ -350,6 +352,21 @@ export interface ProviderModelInput extends DiscoveredModel {
|
|
|
350
352
|
* Distinct from `enabled: false`, which means the tenant switched it off.
|
|
351
353
|
*/
|
|
352
354
|
stale?: boolean;
|
|
355
|
+
/**
|
|
356
|
+
* Per-model LLM config, merged over the provider's own settings when the
|
|
357
|
+
* runtime client is built.
|
|
358
|
+
*
|
|
359
|
+
* This is what lets one model on a provider run at a different temperature,
|
|
360
|
+
* or carry `modelKwargs` the server needs, without duplicating the provider.
|
|
361
|
+
*/
|
|
362
|
+
extra?: Record<string, unknown>;
|
|
363
|
+
/**
|
|
364
|
+
* Whether this is the tenant's default model.
|
|
365
|
+
*
|
|
366
|
+
* Omitted means "leave the stored flag alone": a discovery pass carries no
|
|
367
|
+
* opinion about which model is the default, and must not clear it.
|
|
368
|
+
*/
|
|
369
|
+
isDefault?: boolean;
|
|
353
370
|
}
|
|
354
371
|
|
|
355
372
|
/**
|
|
@@ -365,6 +382,22 @@ export interface ModelSelection {
|
|
|
365
382
|
enabled: boolean;
|
|
366
383
|
/** The upstream no longer offers this model; the row is kept, flagged. */
|
|
367
384
|
stale?: boolean;
|
|
385
|
+
/**
|
|
386
|
+
* Per-model LLM config, merged over the provider's own settings.
|
|
387
|
+
*
|
|
388
|
+
* Omitted means "leave whatever is stored alone" — the selection carries only
|
|
389
|
+
* what the caller is changing, and a model edited through the picker must not
|
|
390
|
+
* lose the config it already had.
|
|
391
|
+
*/
|
|
392
|
+
extra?: Record<string, unknown>;
|
|
393
|
+
/**
|
|
394
|
+
* Whether this is the tenant's default model.
|
|
395
|
+
*
|
|
396
|
+
* At most one model per tenant may carry it. Omitted means "leave the stored
|
|
397
|
+
* flag alone"; a default can only be replaced, never dropped by omission —
|
|
398
|
+
* see `ModelProviderStore.getDefaultModel`.
|
|
399
|
+
*/
|
|
400
|
+
isDefault?: boolean;
|
|
368
401
|
}
|
|
369
402
|
|
|
370
403
|
/**
|
|
@@ -418,6 +451,22 @@ export interface ModelProviderModelEntry {
|
|
|
418
451
|
*/
|
|
419
452
|
stale?: boolean;
|
|
420
453
|
|
|
454
|
+
/**
|
|
455
|
+
* Per-model LLM config, merged over the provider's own settings when the
|
|
456
|
+
* runtime client is built. Absent when the model runs on the provider's
|
|
457
|
+
* settings alone.
|
|
458
|
+
*/
|
|
459
|
+
extra?: Record<string, unknown>;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Whether this is the tenant's default model.
|
|
463
|
+
*
|
|
464
|
+
* At most one row per tenant carries it, enforced by a partial unique index.
|
|
465
|
+
* It is what a bare `"default"` model key resolves to for that tenant, and it
|
|
466
|
+
* cannot be deleted — replacing it means marking another model first.
|
|
467
|
+
*/
|
|
468
|
+
isDefault?: boolean;
|
|
469
|
+
|
|
421
470
|
/**
|
|
422
471
|
* Timestamp of the discovery that produced this row
|
|
423
472
|
*/
|
|
@@ -563,6 +612,19 @@ export interface TenantModelPublicEntry {
|
|
|
563
612
|
*/
|
|
564
613
|
stale: boolean;
|
|
565
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Per-model LLM config, merged over the provider's own settings. Absent when
|
|
617
|
+
* the model runs on the provider's settings alone.
|
|
618
|
+
*/
|
|
619
|
+
extra?: Record<string, unknown>;
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Whether this is the tenant's default model — the one a bare `"default"`
|
|
623
|
+
* key resolves to, and the one a tenant without its own would otherwise take
|
|
624
|
+
* from the deployment.
|
|
625
|
+
*/
|
|
626
|
+
isDefault?: boolean;
|
|
627
|
+
|
|
566
628
|
/**
|
|
567
629
|
* Whether this model can actually be executed by an agent.
|
|
568
630
|
* Phase 1: true only for the `default` tenant.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Lifecycle states of a published plugin's resident service. */
|
|
2
|
+
export type PluginDeploymentStatus =
|
|
3
|
+
| "requested"
|
|
4
|
+
| "provisioning"
|
|
5
|
+
| "running"
|
|
6
|
+
| "paused"
|
|
7
|
+
| "stopping"
|
|
8
|
+
| "stopped"
|
|
9
|
+
| "failed";
|
|
10
|
+
|
|
11
|
+
/** Lifecycle strategy: lazily paused vs. permanently resident. */
|
|
12
|
+
export type PluginDeploymentMode = "onDemand" | "alwaysOn";
|
|
13
|
+
|
|
14
|
+
/** Durable tenant-scoped record of one published plugin's resident service. */
|
|
15
|
+
export interface PluginDeployment {
|
|
16
|
+
id: string;
|
|
17
|
+
tenantId: string;
|
|
18
|
+
pluginType: string;
|
|
19
|
+
pluginVersion: string;
|
|
20
|
+
mode: PluginDeploymentMode;
|
|
21
|
+
status: PluginDeploymentStatus;
|
|
22
|
+
/** Backend provider key, e.g. "microsandbox-remote" | "opensandbox". */
|
|
23
|
+
provider: string;
|
|
24
|
+
/** Deterministic sandbox identity (`plugin-<hash(tenantId, pluginType)>`). */
|
|
25
|
+
sandboxName: string;
|
|
26
|
+
/** Guest port published by the host server. */
|
|
27
|
+
port: number;
|
|
28
|
+
/** Resolved endpoint (scheme-less route or host:port); may change over time. */
|
|
29
|
+
endpoint?: string;
|
|
30
|
+
/** Image used to create the sandbox, when pinned. */
|
|
31
|
+
imageRef?: string;
|
|
32
|
+
/** Idle timeout before an onDemand deployment is paused. */
|
|
33
|
+
idleTimeoutMs: number;
|
|
34
|
+
lastHealthAt?: string;
|
|
35
|
+
lastError?: string;
|
|
36
|
+
createdAt: string;
|
|
37
|
+
updatedAt: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Persistence operations for plugin deployments. */
|
|
41
|
+
export interface PluginDeploymentStore {
|
|
42
|
+
/** Lists every deployment for a tenant. */
|
|
43
|
+
listByTenant(tenantId: string): Promise<PluginDeployment[]>;
|
|
44
|
+
/** Returns the deployment for a plugin type, or undefined. */
|
|
45
|
+
get(tenantId: string, pluginType: string): Promise<PluginDeployment | undefined>;
|
|
46
|
+
/** Inserts or replaces a deployment keyed by tenant + plugin type. */
|
|
47
|
+
upsert(deployment: PluginDeployment): Promise<PluginDeployment>;
|
|
48
|
+
/** Applies a partial update (status/endpoint/health); returns the updated record. */
|
|
49
|
+
updateStatus(
|
|
50
|
+
tenantId: string,
|
|
51
|
+
pluginType: string,
|
|
52
|
+
patch: Partial<Omit<PluginDeployment, "id" | "tenantId" | "pluginType">>
|
|
53
|
+
): Promise<PluginDeployment | undefined>;
|
|
54
|
+
/** Deletes a deployment. Returns whether a row was removed. */
|
|
55
|
+
delete(tenantId: string, pluginType: string): Promise<boolean>;
|
|
56
|
+
}
|
package/src/PluginProtocol.ts
CHANGED
|
@@ -82,10 +82,13 @@ export interface PluginConnection {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* UI declaration for a plugin tool: an HTML
|
|
86
|
-
* the tool runs.
|
|
85
|
+
* UI declaration for a plugin tool: an HTML resource rendered as an MCP App
|
|
86
|
+
* when the tool runs.
|
|
87
87
|
*
|
|
88
|
-
* @property resource -
|
|
88
|
+
* @property resource - For GLOBAL plugins, a `ui://` key into the plugin's
|
|
89
|
+
* `meta.uiResources` map (inline HTML served without a sandbox read). For
|
|
90
|
+
* tenant sandbox plugins, a safe relative path (within the plugin directory)
|
|
91
|
+
* to an `.html` file on the tenant volume.
|
|
89
92
|
* @property displayMode - Preferred display mode; defaults to `inline` (resolved by the compiler).
|
|
90
93
|
* @property csp - Origins the UI needs (see `McpUiCsp`).
|
|
91
94
|
* @property permissions - Sandbox permissions requested (see `McpUiPermissions`).
|
|
@@ -69,6 +69,12 @@ export interface ProjectBotMembership {
|
|
|
69
69
|
roomThreadId: string;
|
|
70
70
|
joinedAt: Date;
|
|
71
71
|
updatedAt: Date;
|
|
72
|
+
/**
|
|
73
|
+
* True for a not-yet-materialized "virtual" public-project entry (dynamic
|
|
74
|
+
* roster projection). Virtual entries have no persisted row; their id
|
|
75
|
+
* materializes just-in-time on first interaction. Absent on real members.
|
|
76
|
+
*/
|
|
77
|
+
provisional?: boolean;
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
/** Identifies a human author of a project room message. */
|
|
@@ -22,6 +22,15 @@ export interface ProjectRoomTrustedRunContext {
|
|
|
22
22
|
* naming any specific value (ADR-118).
|
|
23
23
|
*/
|
|
24
24
|
source?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Host-provided signal that this project has no authored roster.
|
|
27
|
+
*
|
|
28
|
+
* Optional; `true` when present, `undefined`/`false` is treated as absent. Core uses it to skip
|
|
29
|
+
* Project roster authorization for the run's caller and owner (any tenant agent may own a task) and
|
|
30
|
+
* to list the tenant's agents — not the persisted roster — as available executors. The host stamps
|
|
31
|
+
* it only for the workspace general project. Mirrors {@link ProjectTaskTrustedRunContext.rosterExempt}.
|
|
32
|
+
*/
|
|
33
|
+
rosterExempt?: boolean;
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
/** Trusted Project Task identity persisted with a privileged queue message. */
|
|
@@ -111,17 +120,21 @@ export function parseTrustedRunContext(value: unknown): TrustedRunContext {
|
|
|
111
120
|
"tenantId", "workspaceId", "projectId", "roomId", "sourceRoomMessageId", "membershipId",
|
|
112
121
|
"assistantId", "inputMessageId", "role", "title",
|
|
113
122
|
] as const;
|
|
114
|
-
const projectRoomValues = snapshotExactRecord(projectRoomValue, requiredKeys, ["responsibility", "source"]);
|
|
123
|
+
const projectRoomValues = snapshotExactRecord(projectRoomValue, requiredKeys, ["responsibility", "source", "rosterExempt"]);
|
|
115
124
|
const hasResponsibility = projectRoomValues !== undefined
|
|
116
125
|
&& Object.prototype.hasOwnProperty.call(projectRoomValues, "responsibility");
|
|
117
126
|
const hasSource = projectRoomValues !== undefined
|
|
118
127
|
&& Object.prototype.hasOwnProperty.call(projectRoomValues, "source");
|
|
128
|
+
const hasRosterExempt = projectRoomValues !== undefined
|
|
129
|
+
&& Object.prototype.hasOwnProperty.call(projectRoomValues, "rosterExempt");
|
|
119
130
|
if (!projectRoomValues
|
|
120
131
|
|| requiredKeys.some((key) => typeof projectRoomValues[key] !== "string" || projectRoomValues[key].length === 0)
|
|
121
132
|
|| (hasResponsibility && projectRoomValues.responsibility !== undefined
|
|
122
133
|
&& (typeof projectRoomValues.responsibility !== "string" || projectRoomValues.responsibility.length === 0))
|
|
123
134
|
|| (hasSource && projectRoomValues.source !== undefined
|
|
124
135
|
&& (typeof projectRoomValues.source !== "string" || projectRoomValues.source.length === 0))
|
|
136
|
+
|| (hasRosterExempt && projectRoomValues.rosterExempt !== undefined
|
|
137
|
+
&& typeof projectRoomValues.rosterExempt !== "boolean")
|
|
125
138
|
|| (projectRoomValues.role !== "coordinator" && projectRoomValues.role !== "specialist")) {
|
|
126
139
|
throw new Error("Invalid trusted agent run context");
|
|
127
140
|
}
|
|
@@ -143,6 +156,9 @@ export function parseTrustedRunContext(value: unknown): TrustedRunContext {
|
|
|
143
156
|
if (hasSource && typeof projectRoomValues.source === "string") {
|
|
144
157
|
parsedProjectRoom.source = projectRoomValues.source;
|
|
145
158
|
}
|
|
159
|
+
if (hasRosterExempt && projectRoomValues.rosterExempt === true) {
|
|
160
|
+
parsedProjectRoom.rosterExempt = true;
|
|
161
|
+
}
|
|
146
162
|
return { projectRoom: parsedProjectRoom };
|
|
147
163
|
}
|
|
148
164
|
|
|
@@ -257,6 +257,45 @@ describe("parseTrustedRunContext", () => {
|
|
|
257
257
|
})).toThrow("Invalid trusted agent run context");
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
+
it("round-trips an explicit project room roster exemption", () => {
|
|
261
|
+
const parsed = parseTrustedRunContext({
|
|
262
|
+
projectRoom: { ...validProjectRoom(), rosterExempt: true },
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(parsed.projectRoom?.rosterExempt).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("leaves project room roster exemption undefined when absent", () => {
|
|
269
|
+
const parsed = parseTrustedRunContext({ projectRoom: validProjectRoom() });
|
|
270
|
+
|
|
271
|
+
expect(parsed.projectRoom?.rosterExempt).toBeUndefined();
|
|
272
|
+
expect(Object.prototype.hasOwnProperty.call(parsed.projectRoom, "rosterExempt")).toBe(false);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("treats an explicit project room roster exemption of undefined as absent", () => {
|
|
276
|
+
const parsed = parseTrustedRunContext({
|
|
277
|
+
projectRoom: { ...validProjectRoom(), rosterExempt: undefined },
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(parsed.projectRoom?.rosterExempt).toBeUndefined();
|
|
281
|
+
expect(Object.prototype.hasOwnProperty.call(parsed.projectRoom, "rosterExempt")).toBe(false);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("drops an explicit project room roster exemption of false", () => {
|
|
285
|
+
const parsed = parseTrustedRunContext({
|
|
286
|
+
projectRoom: { ...validProjectRoom(), rosterExempt: false },
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
expect(parsed.projectRoom?.rosterExempt).toBeUndefined();
|
|
290
|
+
expect(Object.prototype.hasOwnProperty.call(parsed.projectRoom, "rosterExempt")).toBe(false);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it("rejects a non-boolean project room roster exemption", () => {
|
|
294
|
+
expect(() => parseTrustedRunContext({
|
|
295
|
+
projectRoom: { ...validProjectRoom(), rosterExempt: "yes" },
|
|
296
|
+
})).toThrow("Invalid trusted agent run context");
|
|
297
|
+
});
|
|
298
|
+
|
|
260
299
|
it.each([...Object.keys(validProjectTask()), "source"])("rejects an empty project task %s", (field) => {
|
|
261
300
|
expect(() => parseTrustedRunContext({
|
|
262
301
|
projectTask: { ...validProjectTask(), [field]: "" },
|
package/src/index.ts
CHANGED
|
@@ -59,6 +59,7 @@ export * from "./ProjectBotMembershipStoreProtocol";
|
|
|
59
59
|
export * from "./ProjectRoomMessageStoreProtocol";
|
|
60
60
|
export * from "./ProjectRoomReadStateProtocol";
|
|
61
61
|
export * from "./UserPushSubscriptionStoreProtocol";
|
|
62
|
+
export * from "./PluginDeploymentStoreProtocol";
|
|
62
63
|
export * from "./LeaseStoreProtocol";
|
|
63
64
|
export * from "./OutboxStoreProtocol";
|
|
64
65
|
export * from "./ExactDataSnapshot";
|