@actagent/googlechat 2026.6.2
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/README.md +11 -0
- package/actagent.plugin.json +17 -0
- package/api.ts +4 -0
- package/channel-config-api.ts +2 -0
- package/channel-plugin-api.ts +2 -0
- package/config-api.ts +3 -0
- package/contract-api.ts +6 -0
- package/directory-contract-api.ts +7 -0
- package/doctor-contract-api.ts +2 -0
- package/index.ts +21 -0
- package/npm-shrinkwrap.json +314 -0
- package/package.json +88 -0
- package/runtime-api.ts +61 -0
- package/secret-contract-api.ts +6 -0
- package/setup-entry.ts +14 -0
- package/setup-plugin-api.ts +3 -0
- package/src/accounts.ts +185 -0
- package/src/actions.test.ts +312 -0
- package/src/actions.ts +228 -0
- package/src/api.ts +346 -0
- package/src/approval-auth.test.ts +25 -0
- package/src/approval-auth.ts +38 -0
- package/src/approval-card-actions.test.ts +113 -0
- package/src/approval-card-actions.ts +307 -0
- package/src/approval-card-click.test.ts +279 -0
- package/src/approval-card-click.ts +94 -0
- package/src/approval-handler.runtime.test.ts +388 -0
- package/src/approval-handler.runtime.ts +413 -0
- package/src/approval-native.test.ts +399 -0
- package/src/approval-native.ts +246 -0
- package/src/auth.ts +219 -0
- package/src/channel-base.ts +123 -0
- package/src/channel-config.test.ts +174 -0
- package/src/channel.adapters.ts +363 -0
- package/src/channel.deps.runtime.ts +30 -0
- package/src/channel.runtime.ts +18 -0
- package/src/channel.setup.ts +7 -0
- package/src/channel.test.ts +845 -0
- package/src/channel.ts +214 -0
- package/src/config-schema.test.ts +32 -0
- package/src/config-schema.ts +4 -0
- package/src/doctor-contract.test.ts +76 -0
- package/src/doctor-contract.ts +181 -0
- package/src/doctor.ts +58 -0
- package/src/gateway.ts +84 -0
- package/src/google-auth.runtime.test.ts +571 -0
- package/src/google-auth.runtime.ts +570 -0
- package/src/group-policy.ts +18 -0
- package/src/monitor-access.test.ts +492 -0
- package/src/monitor-access.ts +466 -0
- package/src/monitor-durable.test.ts +40 -0
- package/src/monitor-durable.ts +24 -0
- package/src/monitor-reply-delivery.ts +162 -0
- package/src/monitor-routing.ts +66 -0
- package/src/monitor-types.ts +34 -0
- package/src/monitor-webhook.test.ts +670 -0
- package/src/monitor-webhook.ts +361 -0
- package/src/monitor.reply-delivery.test.ts +145 -0
- package/src/monitor.test.ts +389 -0
- package/src/monitor.ts +530 -0
- package/src/monitor.webhook-routing.test.ts +258 -0
- package/src/runtime.ts +10 -0
- package/src/secret-contract.test.ts +61 -0
- package/src/secret-contract.ts +162 -0
- package/src/setup-core.ts +41 -0
- package/src/setup-surface.ts +244 -0
- package/src/setup.test.ts +620 -0
- package/src/targets.test.ts +562 -0
- package/src/targets.ts +67 -0
- package/src/types.config.ts +4 -0
- package/src/types.ts +139 -0
- package/test-api.ts +3 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
// Googlechat tests cover monitor plugin behavior.
|
|
2
|
+
import { recordChannelBotPairLoopAndCheckSuppression } from "actagent/plugin-sdk/channel-inbound";
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import type { ResolvedGoogleChatAccount } from "./accounts.js";
|
|
5
|
+
import type { GoogleChatCoreRuntime, GoogleChatRuntimeEnv } from "./monitor-types.js";
|
|
6
|
+
import { testing } from "./monitor.js";
|
|
7
|
+
import type { GoogleChatEvent } from "./types.js";
|
|
8
|
+
|
|
9
|
+
const apiMocks = vi.hoisted(() => ({
|
|
10
|
+
downloadGoogleChatMedia: vi.fn(),
|
|
11
|
+
sendGoogleChatMessage: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
const accessMocks = vi.hoisted(() => ({
|
|
15
|
+
applyGoogleChatInboundAccessPolicy: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
vi.mock("./api.js", () => ({
|
|
19
|
+
downloadGoogleChatMedia: apiMocks.downloadGoogleChatMedia,
|
|
20
|
+
sendGoogleChatMessage: apiMocks.sendGoogleChatMessage,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
vi.mock("./monitor-access.js", () => ({
|
|
24
|
+
applyGoogleChatInboundAccessPolicy: accessMocks.applyGoogleChatInboundAccessPolicy,
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
apiMocks.downloadGoogleChatMedia.mockReset();
|
|
29
|
+
apiMocks.sendGoogleChatMessage.mockReset();
|
|
30
|
+
accessMocks.applyGoogleChatInboundAccessPolicy.mockReset();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("googlechat monitor bot loop protection", () => {
|
|
34
|
+
it("maps accepted bot-authored messages to shared channel-turn facts", () => {
|
|
35
|
+
expect(
|
|
36
|
+
testing.resolveGoogleChatBotLoopProtection({
|
|
37
|
+
allowBots: true,
|
|
38
|
+
isBotSender: true,
|
|
39
|
+
senderId: "users/other-bot",
|
|
40
|
+
appUserId: "users/app-bot",
|
|
41
|
+
accountId: "work",
|
|
42
|
+
conversationId: "spaces/AAA",
|
|
43
|
+
config: { maxEventsPerWindow: 3 },
|
|
44
|
+
defaultsConfig: { maxEventsPerWindow: 20 },
|
|
45
|
+
eventTime: "2026-03-22T00:00:00.000Z",
|
|
46
|
+
}),
|
|
47
|
+
).toEqual({
|
|
48
|
+
scopeId: "work",
|
|
49
|
+
conversationId: "spaces/AAA",
|
|
50
|
+
senderId: "users/other-bot",
|
|
51
|
+
receiverId: "users/app-bot",
|
|
52
|
+
config: { maxEventsPerWindow: 3 },
|
|
53
|
+
defaultsConfig: { maxEventsPerWindow: 20 },
|
|
54
|
+
defaultEnabled: true,
|
|
55
|
+
nowMs: Date.parse("2026-03-22T00:00:00.000Z"),
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("does not guard human messages or the app's own echo", () => {
|
|
60
|
+
expect(
|
|
61
|
+
testing.resolveGoogleChatBotLoopProtection({
|
|
62
|
+
allowBots: true,
|
|
63
|
+
isBotSender: false,
|
|
64
|
+
senderId: "users/alice",
|
|
65
|
+
appUserId: "users/app",
|
|
66
|
+
accountId: "work",
|
|
67
|
+
conversationId: "spaces/AAA",
|
|
68
|
+
}),
|
|
69
|
+
).toBeUndefined();
|
|
70
|
+
expect(
|
|
71
|
+
testing.resolveGoogleChatBotLoopProtection({
|
|
72
|
+
allowBots: true,
|
|
73
|
+
isBotSender: true,
|
|
74
|
+
senderId: "users/app",
|
|
75
|
+
appUserId: "users/app",
|
|
76
|
+
accountId: "work",
|
|
77
|
+
conversationId: "spaces/AAA",
|
|
78
|
+
}),
|
|
79
|
+
).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("layers space bot loop overrides over account settings field-by-field", () => {
|
|
83
|
+
expect(
|
|
84
|
+
testing.resolveGoogleChatBotLoopProtectionConfig({
|
|
85
|
+
accountConfig: { windowSeconds: 120, cooldownSeconds: 240 },
|
|
86
|
+
groupConfig: { maxEventsPerWindow: 3 },
|
|
87
|
+
}),
|
|
88
|
+
).toEqual({
|
|
89
|
+
maxEventsPerWindow: 3,
|
|
90
|
+
windowSeconds: 120,
|
|
91
|
+
cooldownSeconds: 240,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("suppresses bot loops before creating typing messages", async () => {
|
|
96
|
+
const eventTimeMs = Date.parse("2026-03-22T00:00:00.000Z");
|
|
97
|
+
const accountId = `bot-loop-typing-${eventTimeMs}`;
|
|
98
|
+
const conversationId = "spaces/LOOP";
|
|
99
|
+
const senderId = "users/other-bot";
|
|
100
|
+
const receiverId = "users/app";
|
|
101
|
+
const runTurn = vi.fn();
|
|
102
|
+
const core = {
|
|
103
|
+
logging: { shouldLogVerbose: () => false },
|
|
104
|
+
channel: {
|
|
105
|
+
inbound: { run: runTurn },
|
|
106
|
+
},
|
|
107
|
+
} as unknown as GoogleChatCoreRuntime;
|
|
108
|
+
const runtime = { error: vi.fn(), log: vi.fn() } satisfies GoogleChatRuntimeEnv;
|
|
109
|
+
const account = {
|
|
110
|
+
accountId,
|
|
111
|
+
config: {
|
|
112
|
+
allowBots: true,
|
|
113
|
+
botUser: receiverId,
|
|
114
|
+
botLoopProtection: { maxEventsPerWindow: 1, windowSeconds: 60, cooldownSeconds: 60 },
|
|
115
|
+
typingIndicator: "message",
|
|
116
|
+
},
|
|
117
|
+
credentialSource: "inline",
|
|
118
|
+
} as ResolvedGoogleChatAccount;
|
|
119
|
+
const event = {
|
|
120
|
+
type: "MESSAGE",
|
|
121
|
+
eventTime: "2026-03-22T00:00:00.001Z",
|
|
122
|
+
space: { name: conversationId, type: "DM" },
|
|
123
|
+
message: {
|
|
124
|
+
name: "spaces/LOOP/messages/2",
|
|
125
|
+
text: "loop",
|
|
126
|
+
sender: { name: senderId, type: "BOT" },
|
|
127
|
+
},
|
|
128
|
+
} satisfies GoogleChatEvent;
|
|
129
|
+
|
|
130
|
+
accessMocks.applyGoogleChatInboundAccessPolicy.mockResolvedValue({
|
|
131
|
+
ok: true,
|
|
132
|
+
commandAuthorized: undefined,
|
|
133
|
+
effectiveWasMentioned: undefined,
|
|
134
|
+
groupBotLoopProtection: undefined,
|
|
135
|
+
groupSystemPrompt: undefined,
|
|
136
|
+
});
|
|
137
|
+
recordChannelBotPairLoopAndCheckSuppression({
|
|
138
|
+
scopeId: accountId,
|
|
139
|
+
conversationId,
|
|
140
|
+
senderId,
|
|
141
|
+
receiverId,
|
|
142
|
+
config: account.config.botLoopProtection,
|
|
143
|
+
defaultEnabled: true,
|
|
144
|
+
nowMs: eventTimeMs,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await testing.processMessageWithPipeline({
|
|
148
|
+
event,
|
|
149
|
+
account,
|
|
150
|
+
config: {},
|
|
151
|
+
runtime,
|
|
152
|
+
core,
|
|
153
|
+
mediaMaxMb: 10,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
expect(apiMocks.sendGoogleChatMessage).not.toHaveBeenCalled();
|
|
157
|
+
expect(apiMocks.downloadGoogleChatMedia).not.toHaveBeenCalled();
|
|
158
|
+
expect(runTurn).not.toHaveBeenCalled();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("googlechat monitor direct messages", () => {
|
|
163
|
+
it("creates typing messages by default", async () => {
|
|
164
|
+
const runTurn = vi.fn();
|
|
165
|
+
const buildContext = vi.fn((payload: unknown) => payload);
|
|
166
|
+
const core = {
|
|
167
|
+
logging: { shouldLogVerbose: () => false },
|
|
168
|
+
channel: {
|
|
169
|
+
routing: {
|
|
170
|
+
resolveAgentRoute: () => ({
|
|
171
|
+
agentId: "agent-1",
|
|
172
|
+
accountId: "work",
|
|
173
|
+
sessionKey: "session-1",
|
|
174
|
+
}),
|
|
175
|
+
},
|
|
176
|
+
session: {
|
|
177
|
+
resolveStorePath: () => "/tmp/actagent-googlechat-test",
|
|
178
|
+
readSessionUpdatedAt: () => undefined,
|
|
179
|
+
recordInboundSession: vi.fn(),
|
|
180
|
+
},
|
|
181
|
+
reply: {
|
|
182
|
+
resolveEnvelopeFormatOptions: () => ({}),
|
|
183
|
+
formatAgentEnvelope: ({ body }: { body: string }) => body,
|
|
184
|
+
dispatchReplyWithBufferedBlockDispatcher: vi.fn(),
|
|
185
|
+
},
|
|
186
|
+
inbound: { buildContext, run: runTurn },
|
|
187
|
+
},
|
|
188
|
+
} as unknown as GoogleChatCoreRuntime;
|
|
189
|
+
const runtime = { error: vi.fn(), log: vi.fn() } satisfies GoogleChatRuntimeEnv;
|
|
190
|
+
const account = {
|
|
191
|
+
accountId: "work",
|
|
192
|
+
config: {},
|
|
193
|
+
credentialSource: "inline",
|
|
194
|
+
} as ResolvedGoogleChatAccount;
|
|
195
|
+
const event = {
|
|
196
|
+
type: "MESSAGE",
|
|
197
|
+
eventTime: "2026-03-22T00:00:00.001Z",
|
|
198
|
+
space: { name: "spaces/DM", type: "DM" },
|
|
199
|
+
message: {
|
|
200
|
+
name: "spaces/DM/messages/2",
|
|
201
|
+
text: "hello",
|
|
202
|
+
sender: { name: "users/alice", displayName: "Alice", type: "HUMAN" },
|
|
203
|
+
},
|
|
204
|
+
} satisfies GoogleChatEvent;
|
|
205
|
+
|
|
206
|
+
accessMocks.applyGoogleChatInboundAccessPolicy.mockResolvedValue({
|
|
207
|
+
ok: true,
|
|
208
|
+
commandAuthorized: undefined,
|
|
209
|
+
effectiveWasMentioned: undefined,
|
|
210
|
+
groupBotLoopProtection: undefined,
|
|
211
|
+
groupSystemPrompt: undefined,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
await testing.processMessageWithPipeline({
|
|
215
|
+
event,
|
|
216
|
+
account,
|
|
217
|
+
config: {},
|
|
218
|
+
runtime,
|
|
219
|
+
core,
|
|
220
|
+
mediaMaxMb: 10,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(apiMocks.sendGoogleChatMessage).toHaveBeenCalledWith({
|
|
224
|
+
account,
|
|
225
|
+
space: "spaces/DM",
|
|
226
|
+
text: "_ACTAgent is typing..._",
|
|
227
|
+
thread: undefined,
|
|
228
|
+
});
|
|
229
|
+
expect(runTurn).toHaveBeenCalledOnce();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("omits thread metadata from DM reply context and typing messages", async () => {
|
|
233
|
+
const runTurn = vi.fn();
|
|
234
|
+
const buildContext = vi.fn((payload: unknown) => payload);
|
|
235
|
+
const core = {
|
|
236
|
+
logging: { shouldLogVerbose: () => false },
|
|
237
|
+
channel: {
|
|
238
|
+
routing: {
|
|
239
|
+
resolveAgentRoute: () => ({
|
|
240
|
+
agentId: "agent-1",
|
|
241
|
+
accountId: "work",
|
|
242
|
+
sessionKey: "session-1",
|
|
243
|
+
}),
|
|
244
|
+
},
|
|
245
|
+
session: {
|
|
246
|
+
resolveStorePath: () => "/tmp/actagent-googlechat-test",
|
|
247
|
+
readSessionUpdatedAt: () => undefined,
|
|
248
|
+
recordInboundSession: vi.fn(),
|
|
249
|
+
},
|
|
250
|
+
reply: {
|
|
251
|
+
resolveEnvelopeFormatOptions: () => ({}),
|
|
252
|
+
formatAgentEnvelope: ({ body }: { body: string }) => body,
|
|
253
|
+
dispatchReplyWithBufferedBlockDispatcher: vi.fn(),
|
|
254
|
+
},
|
|
255
|
+
inbound: { buildContext, run: runTurn },
|
|
256
|
+
},
|
|
257
|
+
} as unknown as GoogleChatCoreRuntime;
|
|
258
|
+
const runtime = { error: vi.fn(), log: vi.fn() } satisfies GoogleChatRuntimeEnv;
|
|
259
|
+
const account = {
|
|
260
|
+
accountId: "work",
|
|
261
|
+
config: {
|
|
262
|
+
typingIndicator: "message",
|
|
263
|
+
},
|
|
264
|
+
credentialSource: "inline",
|
|
265
|
+
} as ResolvedGoogleChatAccount;
|
|
266
|
+
const event = {
|
|
267
|
+
type: "MESSAGE",
|
|
268
|
+
eventTime: "2026-03-22T00:00:00.001Z",
|
|
269
|
+
space: { name: "spaces/DM", type: "DM" },
|
|
270
|
+
message: {
|
|
271
|
+
name: "spaces/DM/messages/2",
|
|
272
|
+
text: "hello",
|
|
273
|
+
thread: { name: "spaces/DM/threads/thread-1" },
|
|
274
|
+
sender: { name: "users/alice", displayName: "Alice", type: "HUMAN" },
|
|
275
|
+
},
|
|
276
|
+
} satisfies GoogleChatEvent;
|
|
277
|
+
|
|
278
|
+
accessMocks.applyGoogleChatInboundAccessPolicy.mockResolvedValue({
|
|
279
|
+
ok: true,
|
|
280
|
+
commandAuthorized: undefined,
|
|
281
|
+
effectiveWasMentioned: undefined,
|
|
282
|
+
groupBotLoopProtection: undefined,
|
|
283
|
+
groupSystemPrompt: undefined,
|
|
284
|
+
});
|
|
285
|
+
apiMocks.sendGoogleChatMessage.mockResolvedValue({
|
|
286
|
+
messageName: "spaces/DM/messages/typing",
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
await testing.processMessageWithPipeline({
|
|
290
|
+
event,
|
|
291
|
+
account,
|
|
292
|
+
config: {},
|
|
293
|
+
runtime,
|
|
294
|
+
core,
|
|
295
|
+
mediaMaxMb: 10,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
expect(buildContext).toHaveBeenCalledWith(
|
|
299
|
+
expect.objectContaining({
|
|
300
|
+
reply: {
|
|
301
|
+
to: "googlechat:spaces/DM",
|
|
302
|
+
originatingTo: "googlechat:spaces/DM",
|
|
303
|
+
replyToId: undefined,
|
|
304
|
+
replyToIdFull: undefined,
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
expect(apiMocks.sendGoogleChatMessage).toHaveBeenCalledWith({
|
|
309
|
+
account,
|
|
310
|
+
space: "spaces/DM",
|
|
311
|
+
text: "_ACTAgent is typing..._",
|
|
312
|
+
thread: undefined,
|
|
313
|
+
});
|
|
314
|
+
expect(runTurn).toHaveBeenCalledOnce();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("drops invalid event timestamps from inbound runtime payloads", async () => {
|
|
318
|
+
const runTurn = vi.fn();
|
|
319
|
+
const buildContext = vi.fn((payload: unknown) => payload);
|
|
320
|
+
const formatAgentEnvelope = vi.fn(({ body }: { body: string }) => body);
|
|
321
|
+
const core = {
|
|
322
|
+
logging: { shouldLogVerbose: () => false },
|
|
323
|
+
channel: {
|
|
324
|
+
routing: {
|
|
325
|
+
resolveAgentRoute: () => ({
|
|
326
|
+
agentId: "agent-1",
|
|
327
|
+
accountId: "work",
|
|
328
|
+
sessionKey: "session-1",
|
|
329
|
+
}),
|
|
330
|
+
},
|
|
331
|
+
session: {
|
|
332
|
+
resolveStorePath: () => "/tmp/actagent-googlechat-test",
|
|
333
|
+
readSessionUpdatedAt: () => undefined,
|
|
334
|
+
recordInboundSession: vi.fn(),
|
|
335
|
+
},
|
|
336
|
+
reply: {
|
|
337
|
+
resolveEnvelopeFormatOptions: () => ({}),
|
|
338
|
+
formatAgentEnvelope,
|
|
339
|
+
dispatchReplyWithBufferedBlockDispatcher: vi.fn(),
|
|
340
|
+
},
|
|
341
|
+
inbound: { buildContext, run: runTurn },
|
|
342
|
+
},
|
|
343
|
+
} as unknown as GoogleChatCoreRuntime;
|
|
344
|
+
const runtime = { error: vi.fn(), log: vi.fn() } satisfies GoogleChatRuntimeEnv;
|
|
345
|
+
const account = {
|
|
346
|
+
accountId: "work",
|
|
347
|
+
config: {
|
|
348
|
+
typingIndicator: "message",
|
|
349
|
+
},
|
|
350
|
+
credentialSource: "inline",
|
|
351
|
+
} as ResolvedGoogleChatAccount;
|
|
352
|
+
const event = {
|
|
353
|
+
type: "MESSAGE",
|
|
354
|
+
eventTime: "not-a-timestamp",
|
|
355
|
+
space: { name: "spaces/DM", type: "DM" },
|
|
356
|
+
message: {
|
|
357
|
+
name: "spaces/DM/messages/2",
|
|
358
|
+
text: "hello",
|
|
359
|
+
sender: { name: "users/alice", displayName: "Alice", type: "HUMAN" },
|
|
360
|
+
},
|
|
361
|
+
} satisfies GoogleChatEvent;
|
|
362
|
+
|
|
363
|
+
accessMocks.applyGoogleChatInboundAccessPolicy.mockResolvedValue({
|
|
364
|
+
ok: true,
|
|
365
|
+
commandAuthorized: undefined,
|
|
366
|
+
effectiveWasMentioned: undefined,
|
|
367
|
+
groupBotLoopProtection: undefined,
|
|
368
|
+
groupSystemPrompt: undefined,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
await testing.processMessageWithPipeline({
|
|
372
|
+
event,
|
|
373
|
+
account,
|
|
374
|
+
config: {},
|
|
375
|
+
runtime,
|
|
376
|
+
core,
|
|
377
|
+
mediaMaxMb: 10,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
expect(formatAgentEnvelope).toHaveBeenCalledWith(
|
|
381
|
+
expect.objectContaining({ timestamp: undefined }),
|
|
382
|
+
);
|
|
383
|
+
expect(buildContext).toHaveBeenCalledWith(expect.objectContaining({ timestamp: undefined }));
|
|
384
|
+
const runArg = runTurn.mock.calls[0]?.[0] as
|
|
385
|
+
| { adapter?: { ingest?: () => { timestamp?: number } } }
|
|
386
|
+
| undefined;
|
|
387
|
+
expect(runArg?.adapter?.ingest?.().timestamp).toBeUndefined();
|
|
388
|
+
});
|
|
389
|
+
});
|