@loopman/langchain-sdk 1.0.9
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/LICENSE +374 -0
- package/README.md +594 -0
- package/dist/agents/loopman-agent.d.ts +29 -0
- package/dist/agents/loopman-agent.d.ts.map +1 -0
- package/dist/agents/loopman-agent.js +441 -0
- package/dist/agents/loopman-agent.js.map +1 -0
- package/dist/client/loopman-api.d.ts +123 -0
- package/dist/client/loopman-api.d.ts.map +1 -0
- package/dist/client/loopman-api.js +407 -0
- package/dist/client/loopman-api.js.map +1 -0
- package/dist/helpers/prompt-orchestrator.d.ts +12 -0
- package/dist/helpers/prompt-orchestrator.d.ts.map +1 -0
- package/dist/helpers/prompt-orchestrator.js +133 -0
- package/dist/helpers/prompt-orchestrator.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/loopman-agent-wrapper.d.ts +70 -0
- package/dist/loopman-agent-wrapper.d.ts.map +1 -0
- package/dist/loopman-agent-wrapper.js +157 -0
- package/dist/loopman-agent-wrapper.js.map +1 -0
- package/dist/loopman-middleware.d.ts +78 -0
- package/dist/loopman-middleware.d.ts.map +1 -0
- package/dist/loopman-middleware.js +367 -0
- package/dist/loopman-middleware.js.map +1 -0
- package/dist/mcp/loopman-mcp-client.d.ts +17 -0
- package/dist/mcp/loopman-mcp-client.d.ts.map +1 -0
- package/dist/mcp/loopman-mcp-client.js +76 -0
- package/dist/mcp/loopman-mcp-client.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts +29 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -0
- package/dist/mcp/tool-registry.js +143 -0
- package/dist/mcp/tool-registry.js.map +1 -0
- package/dist/services/index.d.ts +12 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +9 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/logger.service.d.ts +107 -0
- package/dist/services/logger.service.d.ts.map +1 -0
- package/dist/services/logger.service.js +173 -0
- package/dist/services/logger.service.js.map +1 -0
- package/dist/services/loopman.service.d.ts +72 -0
- package/dist/services/loopman.service.d.ts.map +1 -0
- package/dist/services/loopman.service.js +271 -0
- package/dist/services/loopman.service.js.map +1 -0
- package/dist/services/polling.service.d.ts +136 -0
- package/dist/services/polling.service.d.ts.map +1 -0
- package/dist/services/polling.service.js +428 -0
- package/dist/services/polling.service.js.map +1 -0
- package/dist/types.d.ts +242 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +35 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { LoopmanApiClient } from "../client/loopman-api";
|
|
2
|
+
import { LoggerService } from "./logger.service";
|
|
3
|
+
import { PollingService } from "./polling.service";
|
|
4
|
+
/**
|
|
5
|
+
* Service to interact with Loopman Backoffice API
|
|
6
|
+
* Handles logs, decisions, and polling
|
|
7
|
+
*/
|
|
8
|
+
export class LoopmanService {
|
|
9
|
+
apiClient;
|
|
10
|
+
config;
|
|
11
|
+
// Expose services for direct access
|
|
12
|
+
polling;
|
|
13
|
+
logger;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = {
|
|
16
|
+
timeout: 5 * 60 * 1000, // 5 minutes
|
|
17
|
+
pollingInterval: 5000, // 5 seconds
|
|
18
|
+
debug: false,
|
|
19
|
+
...config,
|
|
20
|
+
};
|
|
21
|
+
this.apiClient = new LoopmanApiClient({ apiKey: config.apiKey });
|
|
22
|
+
// Create logger service
|
|
23
|
+
this.logger = new LoggerService({
|
|
24
|
+
apiClient: this.apiClient,
|
|
25
|
+
apiKey: this.config.apiKey,
|
|
26
|
+
workflowId: this.config.workflowId,
|
|
27
|
+
executionId: this.config.executionId,
|
|
28
|
+
source: "LoopmanService",
|
|
29
|
+
debug: this.config.debug,
|
|
30
|
+
enableRemoteLogs: true,
|
|
31
|
+
});
|
|
32
|
+
// Create polling service and inject a dedicated logger
|
|
33
|
+
this.polling = new PollingService(this.apiClient);
|
|
34
|
+
const pollingLogger = new LoggerService({
|
|
35
|
+
apiClient: this.apiClient,
|
|
36
|
+
apiKey: this.config.apiKey,
|
|
37
|
+
workflowId: this.config.workflowId,
|
|
38
|
+
executionId: this.config.executionId,
|
|
39
|
+
source: "PollingService",
|
|
40
|
+
debug: this.config.debug,
|
|
41
|
+
enableRemoteLogs: true,
|
|
42
|
+
});
|
|
43
|
+
this.polling.setLogger(pollingLogger);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Send a log to Loopman API
|
|
47
|
+
* @deprecated Use logger.info(), logger.warn(), etc. instead
|
|
48
|
+
*/
|
|
49
|
+
async sendLog(level, message) {
|
|
50
|
+
// Delegate to logger service
|
|
51
|
+
this.logger[level](message);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get current user information
|
|
55
|
+
*/
|
|
56
|
+
async getCurrentUser() {
|
|
57
|
+
return await this.apiClient.getCurrentUser(this.config.apiKey);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get guidelines for the current workflow
|
|
61
|
+
* @param category - Optional category filter
|
|
62
|
+
* @returns Guidelines response with list of guidelines
|
|
63
|
+
*/
|
|
64
|
+
async getGuidelines(category) {
|
|
65
|
+
try {
|
|
66
|
+
const params = new URLSearchParams();
|
|
67
|
+
params.append("workflow_external_id", this.config.workflowId);
|
|
68
|
+
if (category) {
|
|
69
|
+
params.append("category", category);
|
|
70
|
+
}
|
|
71
|
+
const response = await this.apiClient.get(this.config.apiKey, `/api/v1/guidelines?${params.toString()}`);
|
|
72
|
+
if (this.config.debug) {
|
|
73
|
+
console.log(`[LoopmanService] Retrieved ${response.guidelines.length} guidelines`);
|
|
74
|
+
}
|
|
75
|
+
return response;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (this.config.debug) {
|
|
79
|
+
console.error("[LoopmanService] Failed to get guidelines:", error);
|
|
80
|
+
}
|
|
81
|
+
// Return empty guidelines on error
|
|
82
|
+
return { guidelines: [] };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get decision context (history of decisions) for the current workflow execution
|
|
87
|
+
* @returns Decision context with history of previous decisions
|
|
88
|
+
*/
|
|
89
|
+
async getDecisionContext() {
|
|
90
|
+
try {
|
|
91
|
+
const response = await this.apiClient.get(this.config.apiKey, `/api/v1/workflows/${this.config.workflowId}/executions/${this.config.executionId}/decisions`);
|
|
92
|
+
if (this.config.debug) {
|
|
93
|
+
console.log(`[LoopmanService] Retrieved ${response.decisions.length} decisions in context`);
|
|
94
|
+
}
|
|
95
|
+
return response;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (this.config.debug) {
|
|
99
|
+
console.error("[LoopmanService] Failed to get decision context:", error);
|
|
100
|
+
}
|
|
101
|
+
// Return empty decisions on error
|
|
102
|
+
return { decisions: [] };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get workflow categories
|
|
107
|
+
* Returns available categories for guidelines in this workflow
|
|
108
|
+
* @returns Array of category names
|
|
109
|
+
*/
|
|
110
|
+
async getWorkflowCategories() {
|
|
111
|
+
try {
|
|
112
|
+
const response = await this.apiClient.get(this.config.apiKey, `/api/v1/workflows/${this.config.workflowId}/categories`);
|
|
113
|
+
if (this.config.debug) {
|
|
114
|
+
console.log(`[LoopmanService] Retrieved ${response.categories.length} categories`);
|
|
115
|
+
}
|
|
116
|
+
return response.categories;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (this.config.debug) {
|
|
120
|
+
console.error("[LoopmanService] Failed to get workflow categories:", error);
|
|
121
|
+
}
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Convert tool arguments to structured information items
|
|
127
|
+
* Formats tool parameters for human-readable display in Loopman UI
|
|
128
|
+
*/
|
|
129
|
+
convertToolArgsToInformation(toolName, toolArgs) {
|
|
130
|
+
const information = [];
|
|
131
|
+
information.push({
|
|
132
|
+
type: "text",
|
|
133
|
+
label: `Tool`,
|
|
134
|
+
value: toolName,
|
|
135
|
+
});
|
|
136
|
+
if (!toolArgs || typeof toolArgs !== "object") {
|
|
137
|
+
return information;
|
|
138
|
+
}
|
|
139
|
+
// Iterate through tool arguments and create information items
|
|
140
|
+
for (const [key, value] of Object.entries(toolArgs)) {
|
|
141
|
+
if (value === null || value === undefined) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const label = key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, " ");
|
|
145
|
+
// Detect URLs
|
|
146
|
+
if (typeof value === "string" &&
|
|
147
|
+
(value.startsWith("http://") || value.startsWith("https://"))) {
|
|
148
|
+
information.push({
|
|
149
|
+
type: "url",
|
|
150
|
+
label: `${label} URL`,
|
|
151
|
+
value: value,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Detect arrays (convert to bullet points)
|
|
155
|
+
else if (Array.isArray(value)) {
|
|
156
|
+
information.push({
|
|
157
|
+
type: "bulletPoints",
|
|
158
|
+
label: label,
|
|
159
|
+
value: value.map(String),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// Text values
|
|
163
|
+
else {
|
|
164
|
+
information.push({
|
|
165
|
+
type: "text",
|
|
166
|
+
label: label,
|
|
167
|
+
value: String(value),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return information;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create a task in Loopman for human review of a tool call
|
|
175
|
+
* Maps tool call data to a task that humans can validate/reject/modify
|
|
176
|
+
*
|
|
177
|
+
* @param toolName - Name of the tool to be validated
|
|
178
|
+
* @param toolArgs - Arguments for the tool call
|
|
179
|
+
* @param description - Optional description of the action
|
|
180
|
+
* @param toolCallId - Optional unique ID from LangChain tool call
|
|
181
|
+
* @param businessContext - Optional business context explaining the action
|
|
182
|
+
* @param parentTaskId - Optional parent task ID to create hierarchical link
|
|
183
|
+
* @param proposedDecision - Optional proposed decision from parent task
|
|
184
|
+
* @param decisionReasoning - Optional decision reasoning from parent task
|
|
185
|
+
* @returns The created task response from Loopman API
|
|
186
|
+
*/
|
|
187
|
+
async createTaskForValidation(toolName, toolArgs, description, toolCallId, businessContext, parentTaskId, proposedDecision, decisionReasoning) {
|
|
188
|
+
try {
|
|
189
|
+
const timestamp = new Date().toISOString();
|
|
190
|
+
const externalReference = `${this.config.workflowId}-${this.config.executionId}-${toolName}-${Date.now()}`;
|
|
191
|
+
// Generate idempotency key based on execution, tool call, and unique call ID
|
|
192
|
+
// This prevents duplicate tasks while allowing multiple calls with same args
|
|
193
|
+
let idempotencyKey;
|
|
194
|
+
if (toolCallId) {
|
|
195
|
+
// Use tool_call_id from LangChain for uniqueness (preferred)
|
|
196
|
+
idempotencyKey = `${this.config.executionId}-${toolName}-${toolCallId}`;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Fallback: hash of args + timestamp for uniqueness
|
|
200
|
+
const argsHash = JSON.stringify(toolArgs);
|
|
201
|
+
const uniqueSuffix = `${Date.now()}-${Buffer.from(argsHash)
|
|
202
|
+
.toString("base64")
|
|
203
|
+
.slice(0, 20)}`;
|
|
204
|
+
idempotencyKey = `${this.config.executionId}-${toolName}-${uniqueSuffix}`;
|
|
205
|
+
}
|
|
206
|
+
const payload = {
|
|
207
|
+
title: `Tool validation`,
|
|
208
|
+
description: description || `Validation required for tool: ${toolName}`,
|
|
209
|
+
workflowIdentifier: this.config.workflowId,
|
|
210
|
+
executionIdentifier: this.config.executionId,
|
|
211
|
+
channelId: this.config.channelId,
|
|
212
|
+
category: "tool-validation",
|
|
213
|
+
businessContext: businessContext, // Business explanation (from parent or current)
|
|
214
|
+
proposedDecision, // Inherited from parent task if available
|
|
215
|
+
decisionReasoning, // Inherited from parent task if available
|
|
216
|
+
metadata: {
|
|
217
|
+
source: "loopman-langchain-sdk-typescript",
|
|
218
|
+
timestamp,
|
|
219
|
+
toolName,
|
|
220
|
+
toolArgs,
|
|
221
|
+
parentTaskId, // Link to parent reflection task
|
|
222
|
+
},
|
|
223
|
+
information: this.convertToolArgsToInformation(toolName, toolArgs),
|
|
224
|
+
priority: "MEDIUM",
|
|
225
|
+
externalReference,
|
|
226
|
+
idempotencyKey,
|
|
227
|
+
};
|
|
228
|
+
this.logger.debug("[LoopmanService] Creating task for tool validation:", payload);
|
|
229
|
+
const taskResponse = await this.apiClient.post(this.config.apiKey, `/api/v1/tasks`, payload);
|
|
230
|
+
this.logger.debug(`[LoopmanService] Task created with ID: ${taskResponse.id}`, { status: taskResponse.status });
|
|
231
|
+
return taskResponse;
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
this.logger.error("[LoopmanService] Failed to create task:", error);
|
|
235
|
+
throw new Error(`Failed to create task in Loopman: ${error instanceof Error ? error.message : String(error)}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get the current status of a task
|
|
240
|
+
* @param taskId - The ID of the task to check
|
|
241
|
+
* @returns The task response from Loopman API
|
|
242
|
+
*/
|
|
243
|
+
async getTask(taskId) {
|
|
244
|
+
try {
|
|
245
|
+
const taskResponse = await this.apiClient.get(this.config.apiKey, `/api/v1/tasks/${taskId}`);
|
|
246
|
+
this.logger.debug(`[LoopmanService] Task ${taskId} status: ${taskResponse.status}`);
|
|
247
|
+
return taskResponse;
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
this.logger.error("[LoopmanService] Failed to get task:", error);
|
|
251
|
+
throw new Error(`Failed to get task from Loopman: ${error instanceof Error ? error.message : String(error)}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get polling options with current configuration
|
|
256
|
+
* Helper method to construct PollingOptions for direct PollingService usage
|
|
257
|
+
*/
|
|
258
|
+
getPollingOptions(taskId, abortSignal) {
|
|
259
|
+
return {
|
|
260
|
+
taskId,
|
|
261
|
+
workflowId: this.config.workflowId,
|
|
262
|
+
executionId: this.config.executionId,
|
|
263
|
+
apiKey: this.config.apiKey,
|
|
264
|
+
timeoutMs: this.config.timeout,
|
|
265
|
+
pollingIntervalMs: this.config.pollingInterval,
|
|
266
|
+
abortSignal,
|
|
267
|
+
debug: this.config.debug,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=loopman.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopman.service.js","sourceRoot":"","sources":["../../src/services/loopman.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { LoopmanApiClient } from "../client/loopman-api";
|
|
2
|
+
import { LoggerService } from "./logger.service";
|
|
3
|
+
/**
|
|
4
|
+
* Polling options for decision monitoring
|
|
5
|
+
*/
|
|
6
|
+
export interface PollingOptions {
|
|
7
|
+
/** Decision ID to poll for */
|
|
8
|
+
taskId: string;
|
|
9
|
+
/** Workflow ID */
|
|
10
|
+
workflowId: string;
|
|
11
|
+
/** Execution ID */
|
|
12
|
+
executionId: string;
|
|
13
|
+
/** API key for authentication */
|
|
14
|
+
apiKey: string;
|
|
15
|
+
/** Timeout in milliseconds (default: 5 minutes) */
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
/** Base polling interval in milliseconds (default: 5000) */
|
|
18
|
+
pollingIntervalMs?: number;
|
|
19
|
+
/** Abort signal for cancellation */
|
|
20
|
+
abortSignal?: AbortSignal;
|
|
21
|
+
/** Enable debug logging */
|
|
22
|
+
debug?: boolean;
|
|
23
|
+
/** Callback for status updates */
|
|
24
|
+
onStatusUpdate?: (status: string, iteration: number) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Decision status response from API
|
|
28
|
+
*/
|
|
29
|
+
export interface DecisionStatusResponse {
|
|
30
|
+
id: string;
|
|
31
|
+
status: "PENDING" | "VALIDATED" | "REFUSED" | "NEED_CHANGES" | "CANCELLED" | "EXPIRED";
|
|
32
|
+
feedback?: string;
|
|
33
|
+
modified_data?: any;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
[key: string]: any;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Polling result with final decision
|
|
40
|
+
*/
|
|
41
|
+
export interface PollingResult {
|
|
42
|
+
/** Decision status */
|
|
43
|
+
status: "VALIDATED" | "REFUSED" | "NEED_CHANGES" | "CANCELLED" | "EXPIRED" | "ABORTED" | "TIMEOUT";
|
|
44
|
+
/** Decision ID */
|
|
45
|
+
taskId: string;
|
|
46
|
+
/** Elapsed time in milliseconds */
|
|
47
|
+
elapsedTime: number;
|
|
48
|
+
/** Number of polling iterations */
|
|
49
|
+
iterations: number;
|
|
50
|
+
/** Full decision data */
|
|
51
|
+
data?: DecisionStatusResponse;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Service for polling decision status and waiting for human review
|
|
55
|
+
*
|
|
56
|
+
* Inspired by the Python SDK PollingService with improvements:
|
|
57
|
+
* - Session management (start/stop polling)
|
|
58
|
+
* - Interruption notifications to backend
|
|
59
|
+
* - Jitter in polling intervals (±20%)
|
|
60
|
+
* - Graceful handling of 500 errors
|
|
61
|
+
* - Consecutive error tracking
|
|
62
|
+
* - AbortSignal support for cancellation
|
|
63
|
+
* - Progress callbacks
|
|
64
|
+
* - Centralized logging with LoggerService
|
|
65
|
+
*/
|
|
66
|
+
export declare class PollingService {
|
|
67
|
+
private apiClient;
|
|
68
|
+
private logger;
|
|
69
|
+
private debug;
|
|
70
|
+
constructor(apiClient: LoopmanApiClient);
|
|
71
|
+
/**
|
|
72
|
+
* Set logger for this polling service
|
|
73
|
+
* Called by LoopmanService to inject the logger
|
|
74
|
+
*/
|
|
75
|
+
setLogger(logger: LoggerService): void;
|
|
76
|
+
/**
|
|
77
|
+
* Wait for a human decision on a specific decision
|
|
78
|
+
* @param options Polling options
|
|
79
|
+
* @returns Polling result with final decision
|
|
80
|
+
*/
|
|
81
|
+
waitForDecision(options: PollingOptions): Promise<PollingResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Check task status via API
|
|
84
|
+
* Uses the simplified /api/v1/tasks/:id/status endpoint
|
|
85
|
+
*/
|
|
86
|
+
private checkTaskStatus;
|
|
87
|
+
/**
|
|
88
|
+
* Map task status from API to decision status
|
|
89
|
+
*/
|
|
90
|
+
private mapTaskStatusToDecisionStatus;
|
|
91
|
+
/**
|
|
92
|
+
* Start polling session on backend
|
|
93
|
+
* Uses the simplified /api/v1/tasks/:id/polling/start endpoint
|
|
94
|
+
*/
|
|
95
|
+
private startPollingSession;
|
|
96
|
+
/**
|
|
97
|
+
* Stop polling session on backend
|
|
98
|
+
* Uses the simplified /api/v1/tasks/:id/polling/stop endpoint
|
|
99
|
+
*/
|
|
100
|
+
private stopPollingSession;
|
|
101
|
+
/**
|
|
102
|
+
* Notify backend about workflow interruption
|
|
103
|
+
* Uses /api/v1/tasks/:id/interruption endpoint (best effort - may not exist yet)
|
|
104
|
+
*/
|
|
105
|
+
private notifyInterruption;
|
|
106
|
+
/**
|
|
107
|
+
* Check if error is a 500 error (server-side issue)
|
|
108
|
+
*/
|
|
109
|
+
private is500Error;
|
|
110
|
+
/**
|
|
111
|
+
* Add jitter to polling interval (±20%)
|
|
112
|
+
* This helps distribute load on the server when multiple clients are polling
|
|
113
|
+
*/
|
|
114
|
+
private addJitter;
|
|
115
|
+
/**
|
|
116
|
+
* Sleep with optional abort signal support
|
|
117
|
+
*/
|
|
118
|
+
private sleep;
|
|
119
|
+
/**
|
|
120
|
+
* Log debug message
|
|
121
|
+
*/
|
|
122
|
+
private logDebug;
|
|
123
|
+
/**
|
|
124
|
+
* Log info message
|
|
125
|
+
*/
|
|
126
|
+
private logInfo;
|
|
127
|
+
/**
|
|
128
|
+
* Log warning message
|
|
129
|
+
*/
|
|
130
|
+
private logWarn;
|
|
131
|
+
/**
|
|
132
|
+
* Log error message
|
|
133
|
+
*/
|
|
134
|
+
private logError;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=polling.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.service.d.ts","sourceRoot":"","sources":["../../src/services/polling.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kCAAkC;IAClC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EACF,SAAS,GACT,WAAW,GACX,SAAS,GACT,cAAc,GACd,WAAW,GACX,SAAS,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EACF,WAAW,GACX,SAAS,GACT,cAAc,GACd,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,CAAC;IACd,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,IAAI,CAAC,EAAE,sBAAsB,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,KAAK,CAAkB;gBAEnB,SAAS,EAAE,gBAAgB;IAIvC;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAItC;;;;OAIG;IACG,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAsLtE;;;OAGG;YACW,eAAe;IA8G7B;;OAEG;IACH,OAAO,CAAC,6BAA6B;IAoBrC;;;OAGG;YACW,mBAAmB;IAsBjC;;;OAGG;YACW,kBAAkB;IAwBhC;;;OAGG;YACW,kBAAkB;IA+BhC;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;;OAGG;IACH,OAAO,CAAC,SAAS;IAMjB;;OAEG;IACH,OAAO,CAAC,KAAK;IAoBb;;OAEG;IACH,OAAO,CAAC,QAAQ;IAQhB;;OAEG;IACH,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,OAAO,CAAC,QAAQ;CAWjB"}
|