@mercuryo-ai/magicpay-cli 0.1.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/README.md +56 -0
- package/dist/agentbrowse-assistive.d.ts +2 -0
- package/dist/agentbrowse-assistive.d.ts.map +1 -0
- package/dist/agentbrowse-assistive.js +66 -0
- package/dist/assistive-llm-client.d.ts +13 -0
- package/dist/assistive-llm-client.d.ts.map +1 -0
- package/dist/assistive-llm-client.js +152 -0
- package/dist/browser-bridge/act.d.ts +5 -0
- package/dist/browser-bridge/act.d.ts.map +1 -0
- package/dist/browser-bridge/act.js +8 -0
- package/dist/browser-bridge/observe.d.ts +5 -0
- package/dist/browser-bridge/observe.d.ts.map +1 -0
- package/dist/browser-bridge/observe.js +53 -0
- package/dist/browser-home.d.ts +7 -0
- package/dist/browser-home.d.ts.map +1 -0
- package/dist/browser-home.js +34 -0
- package/dist/commands/act.d.ts +5 -0
- package/dist/commands/act.d.ts.map +1 -0
- package/dist/commands/act.js +8 -0
- package/dist/commands/attach.d.ts +4 -0
- package/dist/commands/attach.d.ts.map +1 -0
- package/dist/commands/attach.js +10 -0
- package/dist/commands/browser-status.d.ts +5 -0
- package/dist/commands/browser-status.d.ts.map +1 -0
- package/dist/commands/browser-status.js +5 -0
- package/dist/commands/close.d.ts +4 -0
- package/dist/commands/close.d.ts.map +1 -0
- package/dist/commands/close.js +11 -0
- package/dist/commands/end-session.d.ts +22 -0
- package/dist/commands/end-session.d.ts.map +1 -0
- package/dist/commands/end-session.js +104 -0
- package/dist/commands/extract.d.ts +4 -0
- package/dist/commands/extract.d.ts.map +1 -0
- package/dist/commands/extract.js +14 -0
- package/dist/commands/fill-secret.d.ts +10 -0
- package/dist/commands/fill-secret.d.ts.map +1 -0
- package/dist/commands/fill-secret.js +483 -0
- package/dist/commands/find-form.d.ts +57 -0
- package/dist/commands/find-form.d.ts.map +1 -0
- package/dist/commands/find-form.js +138 -0
- package/dist/commands/get-secrets-catalog.d.ts +13 -0
- package/dist/commands/get-secrets-catalog.d.ts.map +1 -0
- package/dist/commands/get-secrets-catalog.js +103 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +28 -0
- package/dist/commands/launch.d.ts +4 -0
- package/dist/commands/launch.d.ts.map +1 -0
- package/dist/commands/launch.js +10 -0
- package/dist/commands/mock-approve-secret.d.ts +21 -0
- package/dist/commands/mock-approve-secret.d.ts.map +1 -0
- package/dist/commands/mock-approve-secret.js +69 -0
- package/dist/commands/mock-deny-secret.d.ts +21 -0
- package/dist/commands/mock-deny-secret.d.ts.map +1 -0
- package/dist/commands/mock-deny-secret.js +69 -0
- package/dist/commands/navigate.d.ts +4 -0
- package/dist/commands/navigate.d.ts.map +1 -0
- package/dist/commands/navigate.js +9 -0
- package/dist/commands/observe.d.ts +5 -0
- package/dist/commands/observe.d.ts.map +1 -0
- package/dist/commands/observe.js +53 -0
- package/dist/commands/poll-secret.d.ts +13 -0
- package/dist/commands/poll-secret.d.ts.map +1 -0
- package/dist/commands/poll-secret.js +87 -0
- package/dist/commands/request-secret.d.ts +15 -0
- package/dist/commands/request-secret.d.ts.map +1 -0
- package/dist/commands/request-secret.js +235 -0
- package/dist/commands/screenshot.d.ts +4 -0
- package/dist/commands/screenshot.d.ts.map +1 -0
- package/dist/commands/screenshot.js +11 -0
- package/dist/commands/solve-captcha.d.ts +19 -0
- package/dist/commands/solve-captcha.d.ts.map +1 -0
- package/dist/commands/solve-captcha.js +63 -0
- package/dist/commands/start-session.d.ts +28 -0
- package/dist/commands/start-session.d.ts.map +1 -0
- package/dist/commands/start-session.js +298 -0
- package/dist/commands/status.d.ts +27 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +51 -0
- package/dist/commands/submit-form.d.ts +36 -0
- package/dist/commands/submit-form.d.ts.map +1 -0
- package/dist/commands/submit-form.js +242 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +1 -0
- package/dist/fillable-form-state.d.ts +5 -0
- package/dist/fillable-form-state.d.ts.map +1 -0
- package/dist/fillable-form-state.js +22 -0
- package/dist/gateway.d.ts +10 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +49 -0
- package/dist/generated/build-config.d.ts +2 -0
- package/dist/generated/build-config.d.ts.map +1 -0
- package/dist/generated/build-config.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +398 -0
- package/dist/mock-secret-cabinet.d.ts +37 -0
- package/dist/mock-secret-cabinet.d.ts.map +1 -0
- package/dist/mock-secret-cabinet.js +321 -0
- package/dist/mock-secret-store.d.ts +12 -0
- package/dist/mock-secret-store.d.ts.map +1 -0
- package/dist/mock-secret-store.js +108 -0
- package/dist/mock-stored-secrets.json +180 -0
- package/dist/otel-exporter.d.ts +58 -0
- package/dist/otel-exporter.d.ts.map +1 -0
- package/dist/otel-exporter.js +241 -0
- package/dist/otel-projector.d.ts +59 -0
- package/dist/otel-projector.d.ts.map +1 -0
- package/dist/otel-projector.js +325 -0
- package/dist/output.d.ts +10 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +29 -0
- package/dist/package-version.d.ts +2 -0
- package/dist/package-version.d.ts.map +1 -0
- package/dist/package-version.js +14 -0
- package/dist/protected-exposure.d.ts +4 -0
- package/dist/protected-exposure.d.ts.map +1 -0
- package/dist/protected-exposure.js +17 -0
- package/dist/request-output.d.ts +4 -0
- package/dist/request-output.d.ts.map +1 -0
- package/dist/request-output.js +27 -0
- package/dist/run-store.d.ts +130 -0
- package/dist/run-store.d.ts.map +1 -0
- package/dist/run-store.js +245 -0
- package/dist/secret-backend.d.ts +28 -0
- package/dist/secret-backend.d.ts.map +1 -0
- package/dist/secret-backend.js +335 -0
- package/dist/secret-state.d.ts +7 -0
- package/dist/secret-state.d.ts.map +1 -0
- package/dist/secret-state.js +26 -0
- package/dist/session-backend.d.ts +34 -0
- package/dist/session-backend.d.ts.map +1 -0
- package/dist/session-backend.js +36 -0
- package/dist/update-check.d.ts +13 -0
- package/dist/update-check.d.ts.map +1 -0
- package/dist/update-check.js +175 -0
- package/dist/workflow-session-completion.d.ts +32 -0
- package/dist/workflow-session-completion.d.ts.map +1 -0
- package/dist/workflow-session-completion.js +149 -0
- package/dist/workflow-state.d.ts +2 -0
- package/dist/workflow-state.d.ts.map +1 -0
- package/dist/workflow-state.js +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { getMagicPayMockSecretRequestsPath } from '@mercuryo-ai/magicpay-home';
|
|
4
|
+
import { resolveCatalogHost } from '@mercuryo-ai/magicpay-sdk/core';
|
|
5
|
+
const MOCK_SECRET_REQUEST_STORE_PATH_ENV = 'MAGICPAY_MOCK_SECRET_REQUEST_STORE_PATH';
|
|
6
|
+
const DEFAULT_MOCK_SECRET_REQUEST_STORE_PATH = getMagicPayMockSecretRequestsPath();
|
|
7
|
+
let testMockSecretRequestStorePath;
|
|
8
|
+
function resolveConfiguredStorePath() {
|
|
9
|
+
if (testMockSecretRequestStorePath) {
|
|
10
|
+
return testMockSecretRequestStorePath;
|
|
11
|
+
}
|
|
12
|
+
const configured = process.env[MOCK_SECRET_REQUEST_STORE_PATH_ENV]?.trim();
|
|
13
|
+
if (configured) {
|
|
14
|
+
return resolve(configured);
|
|
15
|
+
}
|
|
16
|
+
if (existsSync(DEFAULT_MOCK_SECRET_REQUEST_STORE_PATH)) {
|
|
17
|
+
return DEFAULT_MOCK_SECRET_REQUEST_STORE_PATH;
|
|
18
|
+
}
|
|
19
|
+
return DEFAULT_MOCK_SECRET_REQUEST_STORE_PATH;
|
|
20
|
+
}
|
|
21
|
+
function ensureMockCabinetDir() {
|
|
22
|
+
const storePath = resolveConfiguredStorePath();
|
|
23
|
+
mkdirSync(dirname(storePath), { recursive: true });
|
|
24
|
+
return storePath;
|
|
25
|
+
}
|
|
26
|
+
function readMockStore() {
|
|
27
|
+
const storePath = resolveConfiguredStorePath();
|
|
28
|
+
if (!existsSync(storePath)) {
|
|
29
|
+
return {
|
|
30
|
+
version: 2,
|
|
31
|
+
nextRequest: 1,
|
|
32
|
+
requests: {},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const raw = JSON.parse(readFileSync(storePath, 'utf-8'));
|
|
37
|
+
return {
|
|
38
|
+
version: 2,
|
|
39
|
+
nextRequest: Number.isFinite(raw.nextRequest) ? Number(raw.nextRequest) : 1,
|
|
40
|
+
requests: raw.requests ?? {},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return {
|
|
45
|
+
version: 2,
|
|
46
|
+
nextRequest: 1,
|
|
47
|
+
requests: {},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function writeMockStore(store) {
|
|
52
|
+
const storePath = ensureMockCabinetDir();
|
|
53
|
+
writeFileSync(storePath, JSON.stringify(store, null, 2));
|
|
54
|
+
}
|
|
55
|
+
function nowIso(value) {
|
|
56
|
+
return value ?? new Date().toISOString();
|
|
57
|
+
}
|
|
58
|
+
function defaultExpiry(createdAt) {
|
|
59
|
+
return new Date(new Date(createdAt).getTime() + 15 * 60_000).toISOString();
|
|
60
|
+
}
|
|
61
|
+
function isExpired(record, now) {
|
|
62
|
+
if (!record.expiresAt || record.status !== 'pending') {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return new Date(record.expiresAt).getTime() <= new Date(now).getTime();
|
|
66
|
+
}
|
|
67
|
+
function requestStatusForSession(status) {
|
|
68
|
+
return status === 'pending' ? 'waiting_for_user' : 'in_progress';
|
|
69
|
+
}
|
|
70
|
+
function toSessionState(record) {
|
|
71
|
+
return {
|
|
72
|
+
sessionId: record.sessionId,
|
|
73
|
+
status: requestStatusForSession(record.status),
|
|
74
|
+
currentRequestId: record.status === 'pending' ? record.requestId : null,
|
|
75
|
+
lastEventSeq: 0,
|
|
76
|
+
browserSessionId: null,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function resolveHintFields(fields) {
|
|
80
|
+
if (fields.length === 0) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const [first] = fields;
|
|
84
|
+
if (typeof first === 'string') {
|
|
85
|
+
return fields.map((fieldKey) => ({ key: fieldKey }));
|
|
86
|
+
}
|
|
87
|
+
return fields.map((field) => ({ ...field }));
|
|
88
|
+
}
|
|
89
|
+
function buildRequestKey(input) {
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
sessionId: input.sessionId,
|
|
92
|
+
fillRef: input.fillRef,
|
|
93
|
+
storedSecretRef: input.storedSecretRef ?? null,
|
|
94
|
+
kind: input.kind ?? null,
|
|
95
|
+
host: input.host,
|
|
96
|
+
scopeRef: input.scopeRef ?? null,
|
|
97
|
+
fields: [...input.fields].map((field) => field.key).sort(),
|
|
98
|
+
purpose: input.purpose,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function requestMatchesKey(record, key) {
|
|
102
|
+
return (buildRequestKey({
|
|
103
|
+
sessionId: record.sessionId,
|
|
104
|
+
fillRef: record.fillRef,
|
|
105
|
+
storedSecretRef: record.storedSecretRef,
|
|
106
|
+
kind: record.kind,
|
|
107
|
+
host: record.host ?? '',
|
|
108
|
+
scopeRef: record.scopeRef,
|
|
109
|
+
fields: record.fields,
|
|
110
|
+
purpose: record.purpose,
|
|
111
|
+
}) === key);
|
|
112
|
+
}
|
|
113
|
+
function nextRequestId(store) {
|
|
114
|
+
return `sr_mock_${store.nextRequest++}`;
|
|
115
|
+
}
|
|
116
|
+
function requestTypeForStoredSecret(storedSecretRef) {
|
|
117
|
+
return storedSecretRef ? 'secret_read' : 'secret_write';
|
|
118
|
+
}
|
|
119
|
+
function normalizeRequest(record, now) {
|
|
120
|
+
if (!isExpired(record, now)) {
|
|
121
|
+
return record;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
...record,
|
|
125
|
+
status: 'expired',
|
|
126
|
+
updatedAt: now,
|
|
127
|
+
resolvedAt: now,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function findReusableRequest(store, input) {
|
|
131
|
+
const requestKey = buildRequestKey(input);
|
|
132
|
+
const matching = Object.values(store.requests).filter((request) => request.sessionId === input.sessionId && requestMatchesKey(request, requestKey));
|
|
133
|
+
const reusableFulfilled = matching.find((request) => request.status === 'fulfilled' && request.claims.length === 0);
|
|
134
|
+
if (reusableFulfilled) {
|
|
135
|
+
return reusableFulfilled;
|
|
136
|
+
}
|
|
137
|
+
return matching.find((request) => request.status === 'pending') ?? null;
|
|
138
|
+
}
|
|
139
|
+
function resolveHost(input) {
|
|
140
|
+
if (input.secretHint.host) {
|
|
141
|
+
return resolveCatalogHost(input.secretHint.host);
|
|
142
|
+
}
|
|
143
|
+
if (input.page?.url) {
|
|
144
|
+
return resolveCatalogHost(input.page.url);
|
|
145
|
+
}
|
|
146
|
+
throw new Error('secret_request_host_resolution_failed');
|
|
147
|
+
}
|
|
148
|
+
function resolveScopeRef(input) {
|
|
149
|
+
return input.secretHint.scopeRef;
|
|
150
|
+
}
|
|
151
|
+
export function setMockSecretRequestStorePathForTests(storePath) {
|
|
152
|
+
testMockSecretRequestStorePath = storePath ? resolve(storePath) : undefined;
|
|
153
|
+
}
|
|
154
|
+
export function createOrReuseMockSecretRequest(input, options = {}) {
|
|
155
|
+
const store = readMockStore();
|
|
156
|
+
const now = nowIso(options.now);
|
|
157
|
+
const fields = resolveHintFields(input.secretHint.fields);
|
|
158
|
+
const host = resolveHost(input);
|
|
159
|
+
const scopeRef = resolveScopeRef(input);
|
|
160
|
+
const existing = findReusableRequest(store, {
|
|
161
|
+
sessionId: input.sessionId,
|
|
162
|
+
fillRef: input.fillRef,
|
|
163
|
+
storedSecretRef: input.secretHint.storedSecretRef,
|
|
164
|
+
kind: input.secretHint.kind,
|
|
165
|
+
host,
|
|
166
|
+
scopeRef,
|
|
167
|
+
fields,
|
|
168
|
+
purpose: input.purpose,
|
|
169
|
+
});
|
|
170
|
+
if (existing) {
|
|
171
|
+
const normalized = normalizeRequest(existing, now);
|
|
172
|
+
store.requests[normalized.requestId] = normalized;
|
|
173
|
+
writeMockStore(store);
|
|
174
|
+
return {
|
|
175
|
+
requestId: normalized.requestId,
|
|
176
|
+
snapshot: normalized,
|
|
177
|
+
reused: true,
|
|
178
|
+
duplicate: false,
|
|
179
|
+
session: toSessionState(normalized),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const requestId = nextRequestId(store);
|
|
183
|
+
const request = {
|
|
184
|
+
requestId,
|
|
185
|
+
sessionId: input.sessionId,
|
|
186
|
+
fillRef: input.fillRef,
|
|
187
|
+
requestType: requestTypeForStoredSecret(input.secretHint.storedSecretRef),
|
|
188
|
+
status: 'pending',
|
|
189
|
+
...(input.secretHint.storedSecretRef
|
|
190
|
+
? { storedSecretRef: input.secretHint.storedSecretRef }
|
|
191
|
+
: {}),
|
|
192
|
+
...(input.secretHint.kind ? { kind: input.secretHint.kind } : {}),
|
|
193
|
+
host,
|
|
194
|
+
...(input.page?.ref ? { pageRef: input.page.ref } : {}),
|
|
195
|
+
...(scopeRef ? { scopeRef } : {}),
|
|
196
|
+
createdAt: now,
|
|
197
|
+
updatedAt: now,
|
|
198
|
+
expiresAt: defaultExpiry(now),
|
|
199
|
+
purpose: input.purpose,
|
|
200
|
+
fields,
|
|
201
|
+
claims: [],
|
|
202
|
+
};
|
|
203
|
+
store.requests[requestId] = request;
|
|
204
|
+
writeMockStore(store);
|
|
205
|
+
return {
|
|
206
|
+
requestId,
|
|
207
|
+
snapshot: request,
|
|
208
|
+
reused: false,
|
|
209
|
+
duplicate: false,
|
|
210
|
+
session: toSessionState(request),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
export function pollMockSecretRequest(sessionId, requestId, options = {}) {
|
|
214
|
+
const store = readMockStore();
|
|
215
|
+
const current = store.requests[requestId];
|
|
216
|
+
if (!current || current.sessionId !== sessionId) {
|
|
217
|
+
return {
|
|
218
|
+
success: false,
|
|
219
|
+
kind: 'not_found',
|
|
220
|
+
reason: 'MagicPay mock storage did not find a secret request for the provided session ID and request ID.',
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const normalized = normalizeRequest(current, nowIso(options.now));
|
|
224
|
+
store.requests[requestId] = normalized;
|
|
225
|
+
writeMockStore(store);
|
|
226
|
+
return {
|
|
227
|
+
success: true,
|
|
228
|
+
result: {
|
|
229
|
+
requestId,
|
|
230
|
+
snapshot: normalized,
|
|
231
|
+
session: toSessionState(normalized),
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function transitionRequestDecision(requestId, status, options = {}) {
|
|
236
|
+
const store = readMockStore();
|
|
237
|
+
const current = store.requests[requestId];
|
|
238
|
+
if (!current) {
|
|
239
|
+
throw new Error('secret_request_not_found');
|
|
240
|
+
}
|
|
241
|
+
const now = nowIso(options.now);
|
|
242
|
+
const normalized = normalizeRequest(current, now);
|
|
243
|
+
if (normalized.status === 'expired') {
|
|
244
|
+
store.requests[requestId] = normalized;
|
|
245
|
+
writeMockStore(store);
|
|
246
|
+
throw new Error('secret_request_expired');
|
|
247
|
+
}
|
|
248
|
+
if (normalized.status !== 'pending') {
|
|
249
|
+
throw new Error(`secret_request_not_pending:${normalized.status}`);
|
|
250
|
+
}
|
|
251
|
+
const decided = {
|
|
252
|
+
...normalized,
|
|
253
|
+
status,
|
|
254
|
+
updatedAt: now,
|
|
255
|
+
resolvedAt: now,
|
|
256
|
+
...(status === 'fulfilled' ? { approvedAt: now } : {}),
|
|
257
|
+
};
|
|
258
|
+
store.requests[requestId] = decided;
|
|
259
|
+
writeMockStore(store);
|
|
260
|
+
return decided;
|
|
261
|
+
}
|
|
262
|
+
export function approveMockSecretRequest(requestId, options = {}) {
|
|
263
|
+
return transitionRequestDecision(requestId, 'fulfilled', options);
|
|
264
|
+
}
|
|
265
|
+
export function denyMockSecretRequest(requestId, options = {}) {
|
|
266
|
+
return transitionRequestDecision(requestId, 'denied', options);
|
|
267
|
+
}
|
|
268
|
+
export function claimMockSecretRequest(sessionId, requestId, claimId, options) {
|
|
269
|
+
const store = readMockStore();
|
|
270
|
+
const current = store.requests[requestId];
|
|
271
|
+
if (!current || current.sessionId !== sessionId) {
|
|
272
|
+
throw new Error('secret_request_not_found');
|
|
273
|
+
}
|
|
274
|
+
const now = nowIso(options.now);
|
|
275
|
+
const normalized = normalizeRequest(current, now);
|
|
276
|
+
if (normalized.status !== 'fulfilled') {
|
|
277
|
+
throw new Error(`secret_request_not_fulfilled:${normalized.status}`);
|
|
278
|
+
}
|
|
279
|
+
const existingClaim = normalized.claims.find((claim) => claim.claimId === claimId);
|
|
280
|
+
if (!existingClaim && normalized.claims.length > 0) {
|
|
281
|
+
throw new Error('secret_request_already_claimed');
|
|
282
|
+
}
|
|
283
|
+
const storedSecretRef = normalized.storedSecretRef;
|
|
284
|
+
if (!storedSecretRef) {
|
|
285
|
+
throw new Error('mock_secret_values_missing');
|
|
286
|
+
}
|
|
287
|
+
const values = options.resolveValues(storedSecretRef);
|
|
288
|
+
if (!values) {
|
|
289
|
+
throw new Error('mock_secret_values_missing');
|
|
290
|
+
}
|
|
291
|
+
const issuedAt = existingClaim?.issuedAt ?? now;
|
|
292
|
+
if (!existingClaim) {
|
|
293
|
+
store.requests[requestId] = {
|
|
294
|
+
...normalized,
|
|
295
|
+
updatedAt: now,
|
|
296
|
+
claims: [...normalized.claims, { claimId, issuedAt }],
|
|
297
|
+
};
|
|
298
|
+
writeMockStore(store);
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
requestId,
|
|
302
|
+
issuedAt,
|
|
303
|
+
expiresAt: normalized.expiresAt,
|
|
304
|
+
secret: {
|
|
305
|
+
values: values,
|
|
306
|
+
source: 'saved_secret',
|
|
307
|
+
storedSecretRef,
|
|
308
|
+
...(normalized.kind ? { kind: normalized.kind } : {}),
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
export function resetMockSecretRequestStore() {
|
|
313
|
+
const storePath = resolveConfiguredStorePath();
|
|
314
|
+
if (existsSync(storePath)) {
|
|
315
|
+
rmSync(storePath, { force: true });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export const __testMockSecretCabinet = {
|
|
319
|
+
defaultExpiry,
|
|
320
|
+
readMockStore,
|
|
321
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SecretCatalog, StoredSecretMetadata } from '@mercuryo-ai/magicpay-sdk';
|
|
2
|
+
export declare function setMockSecretStorePathForTests(storePath?: string): void;
|
|
3
|
+
export declare function normalizeMerchantKey(value: string): string;
|
|
4
|
+
export declare function listMockStoredSecretsForHost(hostOrUrl: string, options?: {
|
|
5
|
+
merchantKey?: string;
|
|
6
|
+
}): StoredSecretMetadata[];
|
|
7
|
+
export declare function fetchMockSecretCatalog(hostOrUrl: string, options?: {
|
|
8
|
+
merchantKey?: string;
|
|
9
|
+
syncedAt?: string;
|
|
10
|
+
}): SecretCatalog;
|
|
11
|
+
export declare function resolveMockStoredSecretValues(storedSecretRef: string): Record<string, string> | null;
|
|
12
|
+
//# sourceMappingURL=mock-secret-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-secret-store.d.ts","sourceRoot":"","sources":["../src/mock-secret-store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAiGrF,wBAAgB,8BAA8B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAEvE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;CACjB,GACL,oBAAoB,EAAE,CAgBxB;AAED,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACd,GACL,aAAa,CAUf;AAED,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,MAAM,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAS/B"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { getMagicPayMockStoredSecretsPath } from '@mercuryo-ai/magicpay-home';
|
|
5
|
+
import { resolveCatalogHost } from '@mercuryo-ai/magicpay-sdk/core';
|
|
6
|
+
const MOCK_SECRET_STORE_PATH_ENV = 'MAGICPAY_MOCK_SECRET_STORE_PATH';
|
|
7
|
+
const DEFAULT_MOCK_SECRET_STORE_PATH = fileURLToPath(new URL('./mock-stored-secrets.json', import.meta.url));
|
|
8
|
+
const USER_MOCK_SECRET_STORE_PATH = getMagicPayMockStoredSecretsPath();
|
|
9
|
+
let testMockSecretStorePath;
|
|
10
|
+
function normalizeLookupValue(value) {
|
|
11
|
+
return value.trim().toLowerCase();
|
|
12
|
+
}
|
|
13
|
+
function storedSecretAppliesToHost(metadata, host) {
|
|
14
|
+
const normalizedHost = normalizeLookupValue(host);
|
|
15
|
+
const applicabilityValue = metadata.applicability.value
|
|
16
|
+
? normalizeLookupValue(metadata.applicability.value)
|
|
17
|
+
: undefined;
|
|
18
|
+
switch (metadata.applicability.target) {
|
|
19
|
+
case 'global':
|
|
20
|
+
return true;
|
|
21
|
+
case 'host':
|
|
22
|
+
return applicabilityValue === normalizedHost;
|
|
23
|
+
case 'site':
|
|
24
|
+
return (applicabilityValue === normalizedHost ||
|
|
25
|
+
(typeof applicabilityValue === 'string' &&
|
|
26
|
+
normalizedHost.endsWith(`.${applicabilityValue}`)));
|
|
27
|
+
default:
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function resolveConfiguredStorePath() {
|
|
32
|
+
if (testMockSecretStorePath) {
|
|
33
|
+
return testMockSecretStorePath;
|
|
34
|
+
}
|
|
35
|
+
const configured = process.env[MOCK_SECRET_STORE_PATH_ENV]?.trim();
|
|
36
|
+
if (configured) {
|
|
37
|
+
return resolve(configured);
|
|
38
|
+
}
|
|
39
|
+
if (existsSync(USER_MOCK_SECRET_STORE_PATH)) {
|
|
40
|
+
return USER_MOCK_SECRET_STORE_PATH;
|
|
41
|
+
}
|
|
42
|
+
if (existsSync(DEFAULT_MOCK_SECRET_STORE_PATH)) {
|
|
43
|
+
return DEFAULT_MOCK_SECRET_STORE_PATH;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
function resolveMockSecretStorePath() {
|
|
48
|
+
const storePath = resolveConfiguredStorePath();
|
|
49
|
+
if (storePath) {
|
|
50
|
+
return storePath;
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`mock_secret_store_not_found:${DEFAULT_MOCK_SECRET_STORE_PATH}:${USER_MOCK_SECRET_STORE_PATH}`);
|
|
53
|
+
}
|
|
54
|
+
function cloneMetadata(metadata) {
|
|
55
|
+
return {
|
|
56
|
+
...metadata,
|
|
57
|
+
fieldKeys: [...metadata.fieldKeys],
|
|
58
|
+
fieldPolicies: metadata.fieldPolicies ? { ...metadata.fieldPolicies } : undefined,
|
|
59
|
+
preferredForMerchantKeys: metadata.preferredForMerchantKeys
|
|
60
|
+
? [...metadata.preferredForMerchantKeys]
|
|
61
|
+
: undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function loadMockStoredSecretRecords() {
|
|
65
|
+
return JSON.parse(readFileSync(resolveMockSecretStorePath(), 'utf-8'));
|
|
66
|
+
}
|
|
67
|
+
function preferenceScore(metadata, merchantKey) {
|
|
68
|
+
return metadata.preferredForMerchantKeys?.some((candidate) => normalizeLookupValue(candidate) === merchantKey)
|
|
69
|
+
? 1
|
|
70
|
+
: 0;
|
|
71
|
+
}
|
|
72
|
+
export function setMockSecretStorePathForTests(storePath) {
|
|
73
|
+
testMockSecretStorePath = storePath ? resolve(storePath) : undefined;
|
|
74
|
+
}
|
|
75
|
+
export function normalizeMerchantKey(value) {
|
|
76
|
+
return normalizeLookupValue(value);
|
|
77
|
+
}
|
|
78
|
+
export function listMockStoredSecretsForHost(hostOrUrl, options = {}) {
|
|
79
|
+
const host = resolveCatalogHost(hostOrUrl);
|
|
80
|
+
const merchantKey = normalizeMerchantKey(options.merchantKey ?? host);
|
|
81
|
+
return loadMockStoredSecretRecords()
|
|
82
|
+
.filter((record) => storedSecretAppliesToHost(record.metadata, host))
|
|
83
|
+
.sort((left, right) => {
|
|
84
|
+
const preferenceDelta = preferenceScore(right.metadata, merchantKey) - preferenceScore(left.metadata, merchantKey);
|
|
85
|
+
if (preferenceDelta !== 0) {
|
|
86
|
+
return preferenceDelta;
|
|
87
|
+
}
|
|
88
|
+
return left.metadata.displayName.localeCompare(right.metadata.displayName);
|
|
89
|
+
})
|
|
90
|
+
.map((record) => cloneMetadata(record.metadata));
|
|
91
|
+
}
|
|
92
|
+
export function fetchMockSecretCatalog(hostOrUrl, options = {}) {
|
|
93
|
+
const host = resolveCatalogHost(hostOrUrl);
|
|
94
|
+
return {
|
|
95
|
+
host,
|
|
96
|
+
syncedAt: options.syncedAt ?? new Date().toISOString(),
|
|
97
|
+
storedSecrets: listMockStoredSecretsForHost(host, {
|
|
98
|
+
merchantKey: options.merchantKey ?? host,
|
|
99
|
+
}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function resolveMockStoredSecretValues(storedSecretRef) {
|
|
103
|
+
const match = loadMockStoredSecretRecords().find((record) => record.metadata.storedSecretRef === storedSecretRef);
|
|
104
|
+
if (!match) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return { ...match.values };
|
|
108
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"metadata": {
|
|
4
|
+
"storedSecretRef": "secret_site_login_airline_primary",
|
|
5
|
+
"kind": "login",
|
|
6
|
+
"scope": "site",
|
|
7
|
+
"displayName": "Airline account login",
|
|
8
|
+
"fieldKeys": ["username", "password"],
|
|
9
|
+
"fieldPolicies": {
|
|
10
|
+
"username": "deterministic_only",
|
|
11
|
+
"password": "deterministic_only"
|
|
12
|
+
},
|
|
13
|
+
"intentRequired": true,
|
|
14
|
+
"applicability": {
|
|
15
|
+
"target": "site",
|
|
16
|
+
"value": "airline.example"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"values": {
|
|
20
|
+
"username": "traveler@example.com",
|
|
21
|
+
"password": "test-airline-password"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"metadata": {
|
|
26
|
+
"storedSecretRef": "secret_host_login_streaming_primary",
|
|
27
|
+
"kind": "login",
|
|
28
|
+
"scope": "site",
|
|
29
|
+
"displayName": "Streaming auth login",
|
|
30
|
+
"fieldKeys": ["username", "password"],
|
|
31
|
+
"fieldPolicies": {
|
|
32
|
+
"username": "deterministic_only",
|
|
33
|
+
"password": "deterministic_only"
|
|
34
|
+
},
|
|
35
|
+
"intentRequired": true,
|
|
36
|
+
"applicability": {
|
|
37
|
+
"target": "host",
|
|
38
|
+
"value": "auth.streaming.example"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"values": {
|
|
42
|
+
"username": "streaming@example.com",
|
|
43
|
+
"password": "test-streaming-password"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"metadata": {
|
|
48
|
+
"storedSecretRef": "secret_global_identity_primary",
|
|
49
|
+
"kind": "identity",
|
|
50
|
+
"scope": "global",
|
|
51
|
+
"displayName": "Primary passport identity",
|
|
52
|
+
"fieldKeys": [
|
|
53
|
+
"full_name",
|
|
54
|
+
"document_number",
|
|
55
|
+
"date_of_birth",
|
|
56
|
+
"nationality",
|
|
57
|
+
"issue_date",
|
|
58
|
+
"expiry_date",
|
|
59
|
+
"issuing_country"
|
|
60
|
+
],
|
|
61
|
+
"fieldPolicies": {
|
|
62
|
+
"full_name": "llm_assisted",
|
|
63
|
+
"document_number": "deterministic_only",
|
|
64
|
+
"date_of_birth": "deterministic_only",
|
|
65
|
+
"nationality": "llm_assisted",
|
|
66
|
+
"issue_date": "deterministic_only",
|
|
67
|
+
"expiry_date": "deterministic_only",
|
|
68
|
+
"issuing_country": "llm_assisted"
|
|
69
|
+
},
|
|
70
|
+
"intentRequired": true,
|
|
71
|
+
"applicability": {
|
|
72
|
+
"target": "global"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"values": {
|
|
76
|
+
"full_name": "Dmitry Ukhanov",
|
|
77
|
+
"document_number": "AA1234567",
|
|
78
|
+
"date_of_birth": "1990-05-18",
|
|
79
|
+
"nationality": "RU",
|
|
80
|
+
"issue_date": "2020-01-10",
|
|
81
|
+
"expiry_date": "2030-01-10",
|
|
82
|
+
"issuing_country": "RU"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"metadata": {
|
|
87
|
+
"storedSecretRef": "secret_site_identity_aviasales_primary",
|
|
88
|
+
"kind": "identity",
|
|
89
|
+
"scope": "site",
|
|
90
|
+
"displayName": "Aviasales passenger identity",
|
|
91
|
+
"fieldKeys": [
|
|
92
|
+
"full_name",
|
|
93
|
+
"document_number",
|
|
94
|
+
"date_of_birth",
|
|
95
|
+
"nationality",
|
|
96
|
+
"issue_date",
|
|
97
|
+
"expiry_date",
|
|
98
|
+
"issuing_country"
|
|
99
|
+
],
|
|
100
|
+
"fieldPolicies": {
|
|
101
|
+
"full_name": "llm_assisted",
|
|
102
|
+
"document_number": "deterministic_only",
|
|
103
|
+
"date_of_birth": "deterministic_only",
|
|
104
|
+
"nationality": "llm_assisted",
|
|
105
|
+
"issue_date": "deterministic_only",
|
|
106
|
+
"expiry_date": "deterministic_only",
|
|
107
|
+
"issuing_country": "llm_assisted"
|
|
108
|
+
},
|
|
109
|
+
"intentRequired": true,
|
|
110
|
+
"applicability": {
|
|
111
|
+
"target": "site",
|
|
112
|
+
"value": "aviasales.ru"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"values": {
|
|
116
|
+
"full_name": "Dmitry Ukhanov",
|
|
117
|
+
"document_number": "751234567",
|
|
118
|
+
"date_of_birth": "1990-05-18",
|
|
119
|
+
"nationality": "RU",
|
|
120
|
+
"issue_date": "2020-01-10",
|
|
121
|
+
"expiry_date": "2030-01-10",
|
|
122
|
+
"issuing_country": "RU"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"metadata": {
|
|
127
|
+
"storedSecretRef": "secret_global_card_default",
|
|
128
|
+
"kind": "payment_card",
|
|
129
|
+
"scope": "global",
|
|
130
|
+
"displayName": "Primary payment card",
|
|
131
|
+
"fieldKeys": ["cardholder", "pan", "exp_month", "exp_year", "cvv"],
|
|
132
|
+
"fieldPolicies": {
|
|
133
|
+
"cardholder": "deterministic_only",
|
|
134
|
+
"pan": "deterministic_only",
|
|
135
|
+
"exp_month": "deterministic_only",
|
|
136
|
+
"exp_year": "deterministic_only",
|
|
137
|
+
"cvv": "deterministic_only"
|
|
138
|
+
},
|
|
139
|
+
"intentRequired": true,
|
|
140
|
+
"applicability": {
|
|
141
|
+
"target": "global"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"values": {
|
|
145
|
+
"cardholder": "Dmitry Ukhanov",
|
|
146
|
+
"pan": "4242424242424242",
|
|
147
|
+
"exp_month": "12",
|
|
148
|
+
"exp_year": "2030",
|
|
149
|
+
"cvv": "123"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"metadata": {
|
|
154
|
+
"storedSecretRef": "secret_global_card_travel",
|
|
155
|
+
"kind": "payment_card",
|
|
156
|
+
"scope": "global",
|
|
157
|
+
"displayName": "Travel payment card",
|
|
158
|
+
"fieldKeys": ["cardholder", "pan", "exp_month", "exp_year", "cvv"],
|
|
159
|
+
"fieldPolicies": {
|
|
160
|
+
"cardholder": "deterministic_only",
|
|
161
|
+
"pan": "deterministic_only",
|
|
162
|
+
"exp_month": "deterministic_only",
|
|
163
|
+
"exp_year": "deterministic_only",
|
|
164
|
+
"cvv": "deterministic_only"
|
|
165
|
+
},
|
|
166
|
+
"intentRequired": true,
|
|
167
|
+
"applicability": {
|
|
168
|
+
"target": "global"
|
|
169
|
+
},
|
|
170
|
+
"preferredForMerchantKeys": ["airline.example", "booking.example"]
|
|
171
|
+
},
|
|
172
|
+
"values": {
|
|
173
|
+
"cardholder": "Dmitry Ukhanov",
|
|
174
|
+
"pan": "4000002760003184",
|
|
175
|
+
"exp_month": "11",
|
|
176
|
+
"exp_year": "2029",
|
|
177
|
+
"cvv": "456"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type OtlpTraceRequest } from './otel-projector.js';
|
|
2
|
+
export type OtlpHttpJsonExporterConfig = {
|
|
3
|
+
tracesEndpoint: string;
|
|
4
|
+
headers: Record<string, string>;
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
protocol: 'http/json';
|
|
7
|
+
};
|
|
8
|
+
export type ExportStepTraceResult = {
|
|
9
|
+
attempted: false;
|
|
10
|
+
reason: 'config_missing' | 'run_missing' | 'step_missing' | 'unsupported_protocol';
|
|
11
|
+
} | {
|
|
12
|
+
attempted: true;
|
|
13
|
+
success: true;
|
|
14
|
+
status: number;
|
|
15
|
+
payload: OtlpTraceRequest;
|
|
16
|
+
} | {
|
|
17
|
+
attempted: true;
|
|
18
|
+
success: false;
|
|
19
|
+
status?: number;
|
|
20
|
+
reason: string;
|
|
21
|
+
payload: OtlpTraceRequest;
|
|
22
|
+
};
|
|
23
|
+
export type ExportRunRootTraceResult = {
|
|
24
|
+
attempted: false;
|
|
25
|
+
reason: 'config_missing' | 'run_missing';
|
|
26
|
+
} | {
|
|
27
|
+
attempted: true;
|
|
28
|
+
success: true;
|
|
29
|
+
status: number;
|
|
30
|
+
payload: OtlpTraceRequest;
|
|
31
|
+
} | {
|
|
32
|
+
attempted: true;
|
|
33
|
+
success: false;
|
|
34
|
+
status?: number;
|
|
35
|
+
reason: string;
|
|
36
|
+
payload: OtlpTraceRequest;
|
|
37
|
+
};
|
|
38
|
+
export declare function loadOtlpHttpJsonExporterConfig(env?: NodeJS.ProcessEnv): OtlpHttpJsonExporterConfig | null;
|
|
39
|
+
export declare function buildRunStepOtlpTraceRequest(runId: string, stepId: string): OtlpTraceRequest | null;
|
|
40
|
+
export declare function exportRunStepToOtlpHttpJson(params?: {
|
|
41
|
+
runId: string;
|
|
42
|
+
stepId: string;
|
|
43
|
+
config?: OtlpHttpJsonExporterConfig | null;
|
|
44
|
+
fetchImpl?: typeof fetch;
|
|
45
|
+
}): Promise<ExportStepTraceResult>;
|
|
46
|
+
export declare function buildRunRootOtlpTraceRequest(runId: string): OtlpTraceRequest | null;
|
|
47
|
+
export declare function exportRunRootToOtlpHttpJson(params?: {
|
|
48
|
+
runId: string;
|
|
49
|
+
config?: OtlpHttpJsonExporterConfig | null;
|
|
50
|
+
fetchImpl?: typeof fetch;
|
|
51
|
+
}): Promise<ExportRunRootTraceResult>;
|
|
52
|
+
export declare function exportRunStepToOtlpHttpJsonBestEffort(runId: string | undefined, stepId: string | undefined, options?: {
|
|
53
|
+
fetchImpl?: typeof fetch;
|
|
54
|
+
}): Promise<ExportStepTraceResult>;
|
|
55
|
+
export declare function exportRunRootToOtlpHttpJsonBestEffort(runId: string | undefined, options?: {
|
|
56
|
+
fetchImpl?: typeof fetch;
|
|
57
|
+
}): Promise<ExportRunRootTraceResult>;
|
|
58
|
+
//# sourceMappingURL=otel-exporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel-exporter.d.ts","sourceRoot":"","sources":["../src/otel-exporter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM7H,MAAM,MAAM,0BAA0B,GAAG;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAC7B;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,gBAAgB,GAAG,aAAa,GAAG,cAAc,GAAG,sBAAsB,CAAC;CACpF,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,CAAC;CAC3B,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEN,MAAM,MAAM,wBAAwB,GAChC;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,gBAAgB,GAAG,aAAa,CAAC;CAC1C,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,CAAC;CAC3B,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAsEN,wBAAgB,8BAA8B,CAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,0BAA0B,GAAG,IAAI,CA0CnC;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAenG;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,GAAE;IACN,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAI1B,GACA,OAAO,CAAC,qBAAqB,CAAC,CAuDhC;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAOnF;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,GAAE;IACN,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAG1B,GACA,OAAO,CAAC,wBAAwB,CAAC,CAkDnC;AAED,wBAAsB,qCAAqC,CACzD,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB,GACL,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAED,wBAAsB,qCAAqC,CACzD,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB,GACL,OAAO,CAAC,wBAAwB,CAAC,CASnC"}
|