@xyo-network/diviner-image-thumbnail 2.75.14 → 2.75.16
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/dist/docs.json +735 -356
- package/package.json +26 -26
- package/dist/browser/Diviner/Diviner.cjs +0 -233
- package/dist/browser/Diviner/Diviner.cjs.map +0 -1
- package/dist/browser/Diviner/Diviner.js +0 -219
- package/dist/browser/Diviner/Diviner.js.map +0 -1
- package/dist/browser/Diviner/index.cjs +0 -235
- package/dist/browser/Diviner/index.cjs.map +0 -1
- package/dist/browser/Diviner/index.js +0 -219
- package/dist/browser/Diviner/index.js.map +0 -1
- package/dist/node/Diviner/Diviner.js +0 -247
- package/dist/node/Diviner/Diviner.js.map +0 -1
- package/dist/node/Diviner/Diviner.mjs +0 -229
- package/dist/node/Diviner/Diviner.mjs.map +0 -1
- package/dist/node/Diviner/index.js +0 -249
- package/dist/node/Diviner/index.js.map +0 -1
- package/dist/node/Diviner/index.mjs +0 -229
- package/dist/node/Diviner/index.mjs.map +0 -1
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/Diviner/index.ts
|
|
21
|
-
var Diviner_exports = {};
|
|
22
|
-
__export(Diviner_exports, {
|
|
23
|
-
ImageThumbnailDiviner: () => ImageThumbnailDiviner
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(Diviner_exports);
|
|
26
|
-
|
|
27
|
-
// src/Diviner/Diviner.ts
|
|
28
|
-
var import_assert = require("@xylabs/assert");
|
|
29
|
-
var import_exists = require("@xylabs/exists");
|
|
30
|
-
var import_abstract_diviner = require("@xyo-network/abstract-diviner");
|
|
31
|
-
var import_archivist_model = require("@xyo-network/archivist-model");
|
|
32
|
-
var import_archivist_wrapper = require("@xyo-network/archivist-wrapper");
|
|
33
|
-
var import_boundwitness_model = require("@xyo-network/boundwitness-model");
|
|
34
|
-
var import_core = require("@xyo-network/core");
|
|
35
|
-
var import_diviner_boundwitness_model = require("@xyo-network/diviner-boundwitness-model");
|
|
36
|
-
var import_diviner_model = require("@xyo-network/diviner-model");
|
|
37
|
-
var import_diviner_payload_model = require("@xyo-network/diviner-payload-model");
|
|
38
|
-
var import_diviner_wrapper = require("@xyo-network/diviner-wrapper");
|
|
39
|
-
var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
|
|
40
|
-
var import_module_model = require("@xyo-network/module-model");
|
|
41
|
-
var import_payload_builder = require("@xyo-network/payload-builder");
|
|
42
|
-
var import_witness_timestamp = require("@xyo-network/witness-timestamp");
|
|
43
|
-
var moduleName = "ImageThumbnailDiviner";
|
|
44
|
-
var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDiviner {
|
|
45
|
-
static configSchemas = [import_image_thumbnail_payload_plugin.ImageThumbnailDivinerConfigSchema, import_diviner_model.DivinerConfigSchema];
|
|
46
|
-
_pollId;
|
|
47
|
-
get payloadDivinerLimit() {
|
|
48
|
-
return this.config.payloadDivinerLimit ?? 1e4;
|
|
49
|
-
}
|
|
50
|
-
get pollFrequency() {
|
|
51
|
-
return this.config.pollFrequency ?? 1e4;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Works in the background to populate index for the Diviner
|
|
55
|
-
* @returns
|
|
56
|
-
*/
|
|
57
|
-
backgroundDivine = async () => {
|
|
58
|
-
const lastState = await this.retrieveState() ?? { offset: 0 };
|
|
59
|
-
const { offset } = lastState;
|
|
60
|
-
const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore("thumbnailStore");
|
|
61
|
-
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_boundwitness_model.BoundWitnessDivinerQuerySchema }).fields({
|
|
62
|
-
limit: this.payloadDivinerLimit,
|
|
63
|
-
offset,
|
|
64
|
-
order: "asc",
|
|
65
|
-
payload_schemas: [import_image_thumbnail_payload_plugin.ImageThumbnailSchema, import_witness_timestamp.TimestampSchema]
|
|
66
|
-
});
|
|
67
|
-
const batch = await boundWitnessDiviner.divine([query]);
|
|
68
|
-
if (batch.length === 0)
|
|
69
|
-
return;
|
|
70
|
-
const indexableHashes = (await Promise.all(
|
|
71
|
-
batch.filter(import_boundwitness_model.isBoundWitness).map(async (bw) => {
|
|
72
|
-
const imageThumbnailIndexes = bw.payload_schemas?.map((schema, index) => schema === import_image_thumbnail_payload_plugin.ImageThumbnailSchema ? index : void 0).filter(import_exists.exists);
|
|
73
|
-
const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === import_witness_timestamp.TimestampSchema);
|
|
74
|
-
if (!imageThumbnailIndexes.length || timestampIndex === -1)
|
|
75
|
-
return void 0;
|
|
76
|
-
const imageThumbnails = bw.payload_hashes.map((hash, index) => imageThumbnailIndexes.includes(index) ? hash : void 0).filter(import_exists.exists);
|
|
77
|
-
const timestampHash = bw.payload_hashes?.[timestampIndex];
|
|
78
|
-
const boundWitnessHash = await import_core.PayloadHasher.hashAsync(bw);
|
|
79
|
-
return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash]);
|
|
80
|
-
})
|
|
81
|
-
)).flat().filter(import_exists.exists);
|
|
82
|
-
const archivist = await this.getArchivistForStore("thumbnailStore");
|
|
83
|
-
const indexableData = (await Promise.all(
|
|
84
|
-
indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {
|
|
85
|
-
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
86
|
-
const imageThumbnailPayload = results.find(import_image_thumbnail_payload_plugin.isImageThumbnail);
|
|
87
|
-
const timestampPayload = results.find(import_witness_timestamp.isTimestamp);
|
|
88
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
89
|
-
return void 0;
|
|
90
|
-
const calculatedImageThumbnailHash = await import_core.PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
91
|
-
const calculatedTimestampHash = await import_core.PayloadHasher.hashAsync(timestampPayload);
|
|
92
|
-
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
93
|
-
return void 0;
|
|
94
|
-
return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload];
|
|
95
|
-
})
|
|
96
|
-
)).filter(import_exists.exists);
|
|
97
|
-
const indexes = indexableData.map(
|
|
98
|
-
([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {
|
|
99
|
-
const { sourceUrl: url } = thumbnailPayload;
|
|
100
|
-
const { timestamp } = timestampPayload;
|
|
101
|
-
const status = thumbnailPayload.http?.status;
|
|
102
|
-
const success = thumbnailPayload.http?.status ? true : false;
|
|
103
|
-
const sources = [boundWitnessHash, thumbnailHash, timestampHash];
|
|
104
|
-
const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url };
|
|
105
|
-
const result = new import_payload_builder.PayloadBuilder({ schema: import_image_thumbnail_payload_plugin.ImageThumbnailResultIndexSchema }).fields(fields).build();
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
);
|
|
109
|
-
const indexArchivist = await this.getArchivistForStore("indexStore");
|
|
110
|
-
await indexArchivist.insert(indexes);
|
|
111
|
-
const nextOffset = offset + batch.length + 1;
|
|
112
|
-
const currentState = { ...lastState, offset: nextOffset };
|
|
113
|
-
await this.commitState(currentState);
|
|
114
|
-
};
|
|
115
|
-
/**
|
|
116
|
-
* Commit the internal state of the Diviner process. This is similar
|
|
117
|
-
* to a transaction completion in a database and should only be called
|
|
118
|
-
* when results have been successfully persisted to the appropriate
|
|
119
|
-
* external stores.
|
|
120
|
-
*/
|
|
121
|
-
async commitState(state) {
|
|
122
|
-
const stateStore = (0, import_assert.assertEx)(this.config.stateStore?.archivist, `${moduleName}: No stateStore configured`);
|
|
123
|
-
const module2 = (0, import_assert.assertEx)(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`);
|
|
124
|
-
await (0, import_archivist_model.withArchivistModule)(module2, async (archivist) => {
|
|
125
|
-
const mod = import_archivist_wrapper.ArchivistWrapper.wrap(archivist, this.account);
|
|
126
|
-
const payload = new import_payload_builder.PayloadBuilder({ schema: import_module_model.ModuleStateSchema }).fields({ state }).build();
|
|
127
|
-
await mod.insert([payload]);
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
async divineHandler(payloads = []) {
|
|
131
|
-
const urls = payloads.filter(import_image_thumbnail_payload_plugin.isImageThumbnailDivinerQuery);
|
|
132
|
-
const diviner = await this.getPayloadDivinerForStore("indexStore");
|
|
133
|
-
const results = (await Promise.all(
|
|
134
|
-
urls.map(async (payload) => {
|
|
135
|
-
const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload;
|
|
136
|
-
const limit = payloadLimit ?? 1;
|
|
137
|
-
const order = payloadOrder ?? "desc";
|
|
138
|
-
const offset = payloadOffset ?? 0;
|
|
139
|
-
const success = payloadSuccess ?? true;
|
|
140
|
-
const fields = { limit, offset, order, success, url };
|
|
141
|
-
if (payloadSuccess === void 0)
|
|
142
|
-
fields.status = payloadStatus ?? 200;
|
|
143
|
-
if (success === true && payloadStatus !== void 0)
|
|
144
|
-
fields.status = payloadStatus;
|
|
145
|
-
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_payload_model.PayloadDivinerQuerySchema }).fields(fields).build();
|
|
146
|
-
return await diviner.divine([query]);
|
|
147
|
-
})
|
|
148
|
-
)).flat().filter(import_image_thumbnail_payload_plugin.isImageThumbnailResult);
|
|
149
|
-
return results;
|
|
150
|
-
}
|
|
151
|
-
async getArchivistForStore(store, wrap) {
|
|
152
|
-
const name = (0, import_assert.assertEx)(this.config?.[store]?.archivist, () => `${moduleName}: Config for ${store}.archivist not specified`);
|
|
153
|
-
const mod = (0, import_assert.assertEx)(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`);
|
|
154
|
-
return wrap ? import_archivist_wrapper.ArchivistWrapper.wrap(mod, this.account) : (0, import_archivist_model.asArchivistInstance)(mod, () => `${moduleName}: ${store}.archivist is not an Archivist`);
|
|
155
|
-
}
|
|
156
|
-
async getBoundWitnessDivinerForStore(store, wrap) {
|
|
157
|
-
const name = (0, import_assert.assertEx)(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`);
|
|
158
|
-
const mod = (0, import_assert.assertEx)(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`);
|
|
159
|
-
return wrap ? import_diviner_wrapper.DivinerWrapper.wrap(mod, this.account) : (0, import_diviner_model.asDivinerInstance)(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`);
|
|
160
|
-
}
|
|
161
|
-
async getPayloadDivinerForStore(store, wrap) {
|
|
162
|
-
const name = (0, import_assert.assertEx)(this.config?.[store]?.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`);
|
|
163
|
-
const mod = (0, import_assert.assertEx)(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`);
|
|
164
|
-
return wrap ? import_diviner_wrapper.DivinerWrapper.wrap(mod, this.account) : (0, import_diviner_model.asDivinerInstance)(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Retrieves the last state of the Diviner process. Used to recover state after
|
|
168
|
-
* preemptions, reboots, etc.
|
|
169
|
-
*/
|
|
170
|
-
async retrieveState() {
|
|
171
|
-
let hash = "";
|
|
172
|
-
const diviner = await this.getBoundWitnessDivinerForStore("stateStore");
|
|
173
|
-
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_boundwitness_model.BoundWitnessDivinerQuerySchema }).fields({
|
|
174
|
-
address: this.account.address,
|
|
175
|
-
limit: 1,
|
|
176
|
-
offset: 0,
|
|
177
|
-
order: "desc",
|
|
178
|
-
payload_schemas: [import_module_model.ModuleStateSchema]
|
|
179
|
-
});
|
|
180
|
-
const boundWitnesses = await diviner.divine([query]);
|
|
181
|
-
if (boundWitnesses.length > 0) {
|
|
182
|
-
const boundWitness = boundWitnesses[0];
|
|
183
|
-
if ((0, import_boundwitness_model.isBoundWitness)(boundWitness)) {
|
|
184
|
-
hash = boundWitness.addresses.map((address, index) => ({ address, index })).filter(({ address }) => address === this.account.address).reduce(
|
|
185
|
-
(prev, curr) => boundWitness.payload_schemas?.[curr?.index] === import_module_model.ModuleStateSchema ? boundWitness.payload_hashes[curr?.index] : prev,
|
|
186
|
-
""
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (hash) {
|
|
191
|
-
const stateStoreArchivist = (0, import_assert.assertEx)(this.config.stateStore?.archivist, `${moduleName}: No stateStore archivist configured`);
|
|
192
|
-
await (0, import_archivist_model.withArchivistModule)(
|
|
193
|
-
(0, import_assert.assertEx)(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),
|
|
194
|
-
async (mod) => {
|
|
195
|
-
const archivist = import_archivist_wrapper.ArchivistWrapper.wrap(mod, this.account);
|
|
196
|
-
const payloads = await archivist.get([hash]);
|
|
197
|
-
if (payloads.length > 0) {
|
|
198
|
-
const payload = payloads[0];
|
|
199
|
-
if ((0, import_module_model.isModuleState)(payload)) {
|
|
200
|
-
return payload.state;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
return void 0;
|
|
207
|
-
}
|
|
208
|
-
async startHandler() {
|
|
209
|
-
await super.startHandler();
|
|
210
|
-
this.poll();
|
|
211
|
-
return true;
|
|
212
|
-
}
|
|
213
|
-
async stopHandler(_timeout) {
|
|
214
|
-
if (this._pollId) {
|
|
215
|
-
clearTimeout(this._pollId);
|
|
216
|
-
this._pollId = void 0;
|
|
217
|
-
}
|
|
218
|
-
return await super.stopHandler();
|
|
219
|
-
}
|
|
220
|
-
poll() {
|
|
221
|
-
this._pollId = setTimeout(async () => {
|
|
222
|
-
try {
|
|
223
|
-
await this.backgroundDivine();
|
|
224
|
-
} catch (e) {
|
|
225
|
-
console.log(e);
|
|
226
|
-
} finally {
|
|
227
|
-
if (this._pollId)
|
|
228
|
-
clearTimeout(this._pollId);
|
|
229
|
-
this._pollId = void 0;
|
|
230
|
-
this.poll();
|
|
231
|
-
}
|
|
232
|
-
}, this.pollFrequency);
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/Diviner/index.ts","../../../src/Diviner/Diviner.ts"],"sourcesContent":["export * from './Diviner'\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { AbstractDiviner } from '@xyo-network/abstract-diviner'\nimport { asArchivistInstance, withArchivistModule } from '@xyo-network/archivist-model'\nimport { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { asDivinerInstance, DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n // Find all the indexable hashes in this batch\n type IndexableHashes = Readonly<[boundWitnessHash: string, imageThumbnailHash: string, timestampHash: string]>\n const indexableHashes: IndexableHashes[] = (\n await Promise.all(\n batch.filter(isBoundWitness).map(async (bw) => {\n const imageThumbnailIndexes = bw.payload_schemas\n ?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined))\n .filter(exists)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined\n const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)\n const timestampHash = bw.payload_hashes?.[timestampIndex]\n const boundWitnessHash = await PayloadHasher.hashAsync(bw)\n return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash] as const)\n }),\n )\n )\n .flat()\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n // Find all the indexable data associated with the indexable hashes\n type IndexableData = Readonly<\n [\n boundWitnessHash: string,\n imageThumbnailHash: string,\n imageThumbnailPayload: ImageThumbnail,\n timestampHash: string,\n timestampPayload: TimeStamp,\n ]\n >\n const indexableData: IndexableData[] = (\n await Promise.all(\n indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n const success = thumbnailPayload.http?.status ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length + 1\n const currentState = { ...lastState, offset: nextOffset }\n await this.commitState(currentState)\n }\n\n /**\n * Commit the internal state of the Diviner process. This is similar\n * to a transaction completion in a database and should only be called\n * when results have been successfully persisted to the appropriate\n * external stores.\n */\n protected async commitState(state: ImageThumbnailDivinerState) {\n const stateStore = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore configured`)\n const module = assertEx(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`)\n await withArchivistModule(module, async (archivist) => {\n const mod = ArchivistWrapper.wrap(archivist, this.account)\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n await mod.insert([payload])\n })\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess ?? true\n const fields: Partial<ImageThumbnailResultQuery> = { limit, offset, order, success, url }\n // Default to filtering on 200 status code if success was not supplied\n if (payloadSuccess === undefined) fields.status = payloadStatus ?? 200\n // If success is true and status was supplied, use it\n if (success === true && payloadStatus !== undefined) fields.status = payloadStatus\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.archivist, () => `${moduleName}: Config for ${store}.archivist not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`)\n return wrap ? ArchivistWrapper.wrap(mod, this.account) : asArchivistInstance(mod, () => `${moduleName}: ${store}.archivist is not an Archivist`)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`)\n return wrap\n ? DivinerWrapper.wrap(mod, this.account)\n : asDivinerInstance(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`)\n return wrap ? DivinerWrapper.wrap(mod, this.account) : asDivinerInstance(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`)\n }\n\n /**\n * Retrieves the last state of the Diviner process. Used to recover state after\n * preemptions, reboots, etc.\n */\n protected async retrieveState(): Promise<ImageThumbnailDivinerState | undefined> {\n let hash: string = ''\n const diviner = await this.getBoundWitnessDivinerForStore('stateStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n const boundWitnesses = await diviner.divine([query])\n if (boundWitnesses.length > 0) {\n const boundWitness = boundWitnesses[0]\n if (isBoundWitness(boundWitness)) {\n // Find the index for this address in the BoundWitness that is a ModuleState\n hash = boundWitness.addresses\n .map((address, index) => ({ address, index }))\n .filter(({ address }) => address === this.account.address)\n .reduce(\n (prev, curr) => (boundWitness.payload_schemas?.[curr?.index] === ModuleStateSchema ? boundWitness.payload_hashes[curr?.index] : prev),\n '',\n )\n }\n }\n\n // If we able to located the last state\n if (hash) {\n // Get last state\n const stateStoreArchivist = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore archivist configured`)\n await withArchivistModule(\n assertEx(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),\n async (mod) => {\n const archivist = ArchivistWrapper.wrap(mod, this.account)\n const payloads = await archivist.get([hash])\n if (payloads.length > 0) {\n const payload = payloads[0]\n if (isModuleState(payload)) {\n return payload.state\n }\n }\n },\n )\n }\n return undefined\n }\n\n protected override async startHandler(): Promise<boolean> {\n await super.startHandler()\n this.poll()\n return true\n }\n\n protected override async stopHandler(_timeout?: number | undefined): Promise<boolean> {\n if (this._pollId) {\n clearTimeout(this._pollId)\n this._pollId = undefined\n }\n return await super.stopHandler()\n }\n\n private poll() {\n this._pollId = setTimeout(async () => {\n try {\n await this.backgroundDivine()\n } catch (e) {\n console.log(e)\n } finally {\n if (this._pollId) clearTimeout(this._pollId)\n this._pollId = undefined\n this.poll()\n }\n }, this.pollFrequency)\n }\n}\n"],"mappings":"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","names":["module"]}
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
// src/Diviner/Diviner.ts
|
|
2
|
-
import { assertEx } from "@xylabs/assert";
|
|
3
|
-
import { exists } from "@xylabs/exists";
|
|
4
|
-
import { AbstractDiviner } from "@xyo-network/abstract-diviner";
|
|
5
|
-
import { asArchivistInstance, withArchivistModule } from "@xyo-network/archivist-model";
|
|
6
|
-
import { ArchivistWrapper } from "@xyo-network/archivist-wrapper";
|
|
7
|
-
import { isBoundWitness } from "@xyo-network/boundwitness-model";
|
|
8
|
-
import { PayloadHasher } from "@xyo-network/core";
|
|
9
|
-
import { BoundWitnessDivinerQuerySchema } from "@xyo-network/diviner-boundwitness-model";
|
|
10
|
-
import { asDivinerInstance, DivinerConfigSchema } from "@xyo-network/diviner-model";
|
|
11
|
-
import { PayloadDivinerQuerySchema } from "@xyo-network/diviner-payload-model";
|
|
12
|
-
import { DivinerWrapper } from "@xyo-network/diviner-wrapper";
|
|
13
|
-
import {
|
|
14
|
-
ImageThumbnailDivinerConfigSchema,
|
|
15
|
-
ImageThumbnailResultIndexSchema,
|
|
16
|
-
ImageThumbnailSchema,
|
|
17
|
-
isImageThumbnail,
|
|
18
|
-
isImageThumbnailDivinerQuery,
|
|
19
|
-
isImageThumbnailResult
|
|
20
|
-
} from "@xyo-network/image-thumbnail-payload-plugin";
|
|
21
|
-
import { isModuleState, ModuleStateSchema } from "@xyo-network/module-model";
|
|
22
|
-
import { PayloadBuilder } from "@xyo-network/payload-builder";
|
|
23
|
-
import { isTimestamp, TimestampSchema } from "@xyo-network/witness-timestamp";
|
|
24
|
-
var moduleName = "ImageThumbnailDiviner";
|
|
25
|
-
var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
26
|
-
static configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema];
|
|
27
|
-
_pollId;
|
|
28
|
-
get payloadDivinerLimit() {
|
|
29
|
-
return this.config.payloadDivinerLimit ?? 1e4;
|
|
30
|
-
}
|
|
31
|
-
get pollFrequency() {
|
|
32
|
-
return this.config.pollFrequency ?? 1e4;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Works in the background to populate index for the Diviner
|
|
36
|
-
* @returns
|
|
37
|
-
*/
|
|
38
|
-
backgroundDivine = async () => {
|
|
39
|
-
const lastState = await this.retrieveState() ?? { offset: 0 };
|
|
40
|
-
const { offset } = lastState;
|
|
41
|
-
const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore("thumbnailStore");
|
|
42
|
-
const query = new PayloadBuilder({ schema: BoundWitnessDivinerQuerySchema }).fields({
|
|
43
|
-
limit: this.payloadDivinerLimit,
|
|
44
|
-
offset,
|
|
45
|
-
order: "asc",
|
|
46
|
-
payload_schemas: [ImageThumbnailSchema, TimestampSchema]
|
|
47
|
-
});
|
|
48
|
-
const batch = await boundWitnessDiviner.divine([query]);
|
|
49
|
-
if (batch.length === 0)
|
|
50
|
-
return;
|
|
51
|
-
const indexableHashes = (await Promise.all(
|
|
52
|
-
batch.filter(isBoundWitness).map(async (bw) => {
|
|
53
|
-
const imageThumbnailIndexes = bw.payload_schemas?.map((schema, index) => schema === ImageThumbnailSchema ? index : void 0).filter(exists);
|
|
54
|
-
const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema);
|
|
55
|
-
if (!imageThumbnailIndexes.length || timestampIndex === -1)
|
|
56
|
-
return void 0;
|
|
57
|
-
const imageThumbnails = bw.payload_hashes.map((hash, index) => imageThumbnailIndexes.includes(index) ? hash : void 0).filter(exists);
|
|
58
|
-
const timestampHash = bw.payload_hashes?.[timestampIndex];
|
|
59
|
-
const boundWitnessHash = await PayloadHasher.hashAsync(bw);
|
|
60
|
-
return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash]);
|
|
61
|
-
})
|
|
62
|
-
)).flat().filter(exists);
|
|
63
|
-
const archivist = await this.getArchivistForStore("thumbnailStore");
|
|
64
|
-
const indexableData = (await Promise.all(
|
|
65
|
-
indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {
|
|
66
|
-
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
67
|
-
const imageThumbnailPayload = results.find(isImageThumbnail);
|
|
68
|
-
const timestampPayload = results.find(isTimestamp);
|
|
69
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
70
|
-
return void 0;
|
|
71
|
-
const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
72
|
-
const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload);
|
|
73
|
-
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
74
|
-
return void 0;
|
|
75
|
-
return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload];
|
|
76
|
-
})
|
|
77
|
-
)).filter(exists);
|
|
78
|
-
const indexes = indexableData.map(
|
|
79
|
-
([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {
|
|
80
|
-
const { sourceUrl: url } = thumbnailPayload;
|
|
81
|
-
const { timestamp } = timestampPayload;
|
|
82
|
-
const status = thumbnailPayload.http?.status;
|
|
83
|
-
const success = thumbnailPayload.http?.status ? true : false;
|
|
84
|
-
const sources = [boundWitnessHash, thumbnailHash, timestampHash];
|
|
85
|
-
const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url };
|
|
86
|
-
const result = new PayloadBuilder({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build();
|
|
87
|
-
return result;
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
const indexArchivist = await this.getArchivistForStore("indexStore");
|
|
91
|
-
await indexArchivist.insert(indexes);
|
|
92
|
-
const nextOffset = offset + batch.length + 1;
|
|
93
|
-
const currentState = { ...lastState, offset: nextOffset };
|
|
94
|
-
await this.commitState(currentState);
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* Commit the internal state of the Diviner process. This is similar
|
|
98
|
-
* to a transaction completion in a database and should only be called
|
|
99
|
-
* when results have been successfully persisted to the appropriate
|
|
100
|
-
* external stores.
|
|
101
|
-
*/
|
|
102
|
-
async commitState(state) {
|
|
103
|
-
const stateStore = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore configured`);
|
|
104
|
-
const module = assertEx(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`);
|
|
105
|
-
await withArchivistModule(module, async (archivist) => {
|
|
106
|
-
const mod = ArchivistWrapper.wrap(archivist, this.account);
|
|
107
|
-
const payload = new PayloadBuilder({ schema: ModuleStateSchema }).fields({ state }).build();
|
|
108
|
-
await mod.insert([payload]);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
async divineHandler(payloads = []) {
|
|
112
|
-
const urls = payloads.filter(isImageThumbnailDivinerQuery);
|
|
113
|
-
const diviner = await this.getPayloadDivinerForStore("indexStore");
|
|
114
|
-
const results = (await Promise.all(
|
|
115
|
-
urls.map(async (payload) => {
|
|
116
|
-
const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload;
|
|
117
|
-
const limit = payloadLimit ?? 1;
|
|
118
|
-
const order = payloadOrder ?? "desc";
|
|
119
|
-
const offset = payloadOffset ?? 0;
|
|
120
|
-
const success = payloadSuccess ?? true;
|
|
121
|
-
const fields = { limit, offset, order, success, url };
|
|
122
|
-
if (payloadSuccess === void 0)
|
|
123
|
-
fields.status = payloadStatus ?? 200;
|
|
124
|
-
if (success === true && payloadStatus !== void 0)
|
|
125
|
-
fields.status = payloadStatus;
|
|
126
|
-
const query = new PayloadBuilder({ schema: PayloadDivinerQuerySchema }).fields(fields).build();
|
|
127
|
-
return await diviner.divine([query]);
|
|
128
|
-
})
|
|
129
|
-
)).flat().filter(isImageThumbnailResult);
|
|
130
|
-
return results;
|
|
131
|
-
}
|
|
132
|
-
async getArchivistForStore(store, wrap) {
|
|
133
|
-
const name = assertEx(this.config?.[store]?.archivist, () => `${moduleName}: Config for ${store}.archivist not specified`);
|
|
134
|
-
const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`);
|
|
135
|
-
return wrap ? ArchivistWrapper.wrap(mod, this.account) : asArchivistInstance(mod, () => `${moduleName}: ${store}.archivist is not an Archivist`);
|
|
136
|
-
}
|
|
137
|
-
async getBoundWitnessDivinerForStore(store, wrap) {
|
|
138
|
-
const name = assertEx(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`);
|
|
139
|
-
const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`);
|
|
140
|
-
return wrap ? DivinerWrapper.wrap(mod, this.account) : asDivinerInstance(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`);
|
|
141
|
-
}
|
|
142
|
-
async getPayloadDivinerForStore(store, wrap) {
|
|
143
|
-
const name = assertEx(this.config?.[store]?.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`);
|
|
144
|
-
const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`);
|
|
145
|
-
return wrap ? DivinerWrapper.wrap(mod, this.account) : asDivinerInstance(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Retrieves the last state of the Diviner process. Used to recover state after
|
|
149
|
-
* preemptions, reboots, etc.
|
|
150
|
-
*/
|
|
151
|
-
async retrieveState() {
|
|
152
|
-
let hash = "";
|
|
153
|
-
const diviner = await this.getBoundWitnessDivinerForStore("stateStore");
|
|
154
|
-
const query = new PayloadBuilder({ schema: BoundWitnessDivinerQuerySchema }).fields({
|
|
155
|
-
address: this.account.address,
|
|
156
|
-
limit: 1,
|
|
157
|
-
offset: 0,
|
|
158
|
-
order: "desc",
|
|
159
|
-
payload_schemas: [ModuleStateSchema]
|
|
160
|
-
});
|
|
161
|
-
const boundWitnesses = await diviner.divine([query]);
|
|
162
|
-
if (boundWitnesses.length > 0) {
|
|
163
|
-
const boundWitness = boundWitnesses[0];
|
|
164
|
-
if (isBoundWitness(boundWitness)) {
|
|
165
|
-
hash = boundWitness.addresses.map((address, index) => ({ address, index })).filter(({ address }) => address === this.account.address).reduce(
|
|
166
|
-
(prev, curr) => boundWitness.payload_schemas?.[curr?.index] === ModuleStateSchema ? boundWitness.payload_hashes[curr?.index] : prev,
|
|
167
|
-
""
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (hash) {
|
|
172
|
-
const stateStoreArchivist = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore archivist configured`);
|
|
173
|
-
await withArchivistModule(
|
|
174
|
-
assertEx(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),
|
|
175
|
-
async (mod) => {
|
|
176
|
-
const archivist = ArchivistWrapper.wrap(mod, this.account);
|
|
177
|
-
const payloads = await archivist.get([hash]);
|
|
178
|
-
if (payloads.length > 0) {
|
|
179
|
-
const payload = payloads[0];
|
|
180
|
-
if (isModuleState(payload)) {
|
|
181
|
-
return payload.state;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
return void 0;
|
|
188
|
-
}
|
|
189
|
-
async startHandler() {
|
|
190
|
-
await super.startHandler();
|
|
191
|
-
this.poll();
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
async stopHandler(_timeout) {
|
|
195
|
-
if (this._pollId) {
|
|
196
|
-
clearTimeout(this._pollId);
|
|
197
|
-
this._pollId = void 0;
|
|
198
|
-
}
|
|
199
|
-
return await super.stopHandler();
|
|
200
|
-
}
|
|
201
|
-
poll() {
|
|
202
|
-
this._pollId = setTimeout(async () => {
|
|
203
|
-
try {
|
|
204
|
-
await this.backgroundDivine();
|
|
205
|
-
} catch (e) {
|
|
206
|
-
console.log(e);
|
|
207
|
-
} finally {
|
|
208
|
-
if (this._pollId)
|
|
209
|
-
clearTimeout(this._pollId);
|
|
210
|
-
this._pollId = void 0;
|
|
211
|
-
this.poll();
|
|
212
|
-
}
|
|
213
|
-
}, this.pollFrequency);
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
export {
|
|
217
|
-
ImageThumbnailDiviner
|
|
218
|
-
};
|
|
219
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/Diviner/Diviner.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { AbstractDiviner } from '@xyo-network/abstract-diviner'\nimport { asArchivistInstance, withArchivistModule } from '@xyo-network/archivist-model'\nimport { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { asDivinerInstance, DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n // Find all the indexable hashes in this batch\n type IndexableHashes = Readonly<[boundWitnessHash: string, imageThumbnailHash: string, timestampHash: string]>\n const indexableHashes: IndexableHashes[] = (\n await Promise.all(\n batch.filter(isBoundWitness).map(async (bw) => {\n const imageThumbnailIndexes = bw.payload_schemas\n ?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined))\n .filter(exists)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined\n const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)\n const timestampHash = bw.payload_hashes?.[timestampIndex]\n const boundWitnessHash = await PayloadHasher.hashAsync(bw)\n return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash] as const)\n }),\n )\n )\n .flat()\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n // Find all the indexable data associated with the indexable hashes\n type IndexableData = Readonly<\n [\n boundWitnessHash: string,\n imageThumbnailHash: string,\n imageThumbnailPayload: ImageThumbnail,\n timestampHash: string,\n timestampPayload: TimeStamp,\n ]\n >\n const indexableData: IndexableData[] = (\n await Promise.all(\n indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n const success = thumbnailPayload.http?.status ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length + 1\n const currentState = { ...lastState, offset: nextOffset }\n await this.commitState(currentState)\n }\n\n /**\n * Commit the internal state of the Diviner process. This is similar\n * to a transaction completion in a database and should only be called\n * when results have been successfully persisted to the appropriate\n * external stores.\n */\n protected async commitState(state: ImageThumbnailDivinerState) {\n const stateStore = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore configured`)\n const module = assertEx(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`)\n await withArchivistModule(module, async (archivist) => {\n const mod = ArchivistWrapper.wrap(archivist, this.account)\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n await mod.insert([payload])\n })\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess ?? true\n const fields: Partial<ImageThumbnailResultQuery> = { limit, offset, order, success, url }\n // Default to filtering on 200 status code if success was not supplied\n if (payloadSuccess === undefined) fields.status = payloadStatus ?? 200\n // If success is true and status was supplied, use it\n if (success === true && payloadStatus !== undefined) fields.status = payloadStatus\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.archivist, () => `${moduleName}: Config for ${store}.archivist not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`)\n return wrap ? ArchivistWrapper.wrap(mod, this.account) : asArchivistInstance(mod, () => `${moduleName}: ${store}.archivist is not an Archivist`)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`)\n return wrap\n ? DivinerWrapper.wrap(mod, this.account)\n : asDivinerInstance(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore, wrap?: boolean) {\n const name = assertEx(this.config?.[store]?.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`)\n const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`)\n return wrap ? DivinerWrapper.wrap(mod, this.account) : asDivinerInstance(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`)\n }\n\n /**\n * Retrieves the last state of the Diviner process. Used to recover state after\n * preemptions, reboots, etc.\n */\n protected async retrieveState(): Promise<ImageThumbnailDivinerState | undefined> {\n let hash: string = ''\n const diviner = await this.getBoundWitnessDivinerForStore('stateStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n const boundWitnesses = await diviner.divine([query])\n if (boundWitnesses.length > 0) {\n const boundWitness = boundWitnesses[0]\n if (isBoundWitness(boundWitness)) {\n // Find the index for this address in the BoundWitness that is a ModuleState\n hash = boundWitness.addresses\n .map((address, index) => ({ address, index }))\n .filter(({ address }) => address === this.account.address)\n .reduce(\n (prev, curr) => (boundWitness.payload_schemas?.[curr?.index] === ModuleStateSchema ? boundWitness.payload_hashes[curr?.index] : prev),\n '',\n )\n }\n }\n\n // If we able to located the last state\n if (hash) {\n // Get last state\n const stateStoreArchivist = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore archivist configured`)\n await withArchivistModule(\n assertEx(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),\n async (mod) => {\n const archivist = ArchivistWrapper.wrap(mod, this.account)\n const payloads = await archivist.get([hash])\n if (payloads.length > 0) {\n const payload = payloads[0]\n if (isModuleState(payload)) {\n return payload.state\n }\n }\n },\n )\n }\n return undefined\n }\n\n protected override async startHandler(): Promise<boolean> {\n await super.startHandler()\n this.poll()\n return true\n }\n\n protected override async stopHandler(_timeout?: number | undefined): Promise<boolean> {\n if (this._pollId) {\n clearTimeout(this._pollId)\n this._pollId = undefined\n }\n return await super.stopHandler()\n }\n\n private poll() {\n this._pollId = setTimeout(async () => {\n try {\n await this.backgroundDivine()\n } catch (e) {\n console.log(e)\n } finally {\n if (this._pollId) clearTimeout(this._pollId)\n this._pollId = undefined\n this.poll()\n }\n }, this.pollFrequency)\n }\n}\n"],"mappings":";AAAA,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,qBAAqB,2BAA2B;AACzD,SAAS,wBAAwB;AACjC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAA0C,sCAAsC;AAChF,SAAS,mBAAmB,2BAA2B;AACvD,SAAqC,iCAAiC;AACtE,SAAS,sBAAsB;AAC/B;AAAA,EAGE;AAAA,EAGA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,eAA4B,yBAA0C;AAC/E,SAAS,sBAAsB;AAE/B,SAAS,aAAwB,uBAAuB;AAuBxD,IAAM,aAAa;AAEZ,IAAM,wBAAN,cAA+G,gBAAyB;AAAA,EAC7I,OAAgB,gBAAgB,CAAC,mCAAmC,mBAAmB;AAAA,EAE/E;AAAA,EAER,IAAI,sBAAsB;AACxB,WAAO,KAAK,OAAO,uBAAuB;AAAA,EAC5C;AAAA,EAEA,IAAI,gBAAgB;AAClB,WAAO,KAAK,OAAO,iBAAiB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,mBAAmB,YAA2B;AAEtD,UAAM,YAAa,MAAM,KAAK,cAAc,KAAM,EAAE,QAAQ,EAAE;AAC9D,UAAM,EAAE,OAAO,IAAI;AAEnB,UAAM,sBAAsB,MAAM,KAAK,+BAA+B,gBAAgB;AACtF,UAAM,QAAQ,IAAI,eAAgD,EAAE,QAAQ,+BAA+B,CAAC,EAAE,OAAO;AAAA,MACnH,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,MACP,iBAAiB,CAAC,sBAAsB,eAAe;AAAA,IACzD,CAAC;AACD,UAAM,QAAQ,MAAM,oBAAoB,OAAO,CAAC,KAAK,CAAC;AACtD,QAAI,MAAM,WAAW;AAAG;AAGxB,UAAM,mBACJ,MAAM,QAAQ;AAAA,MACZ,MAAM,OAAO,cAAc,EAAE,IAAI,OAAO,OAAO;AAC7C,cAAM,wBAAwB,GAAG,iBAC7B,IAAI,CAAC,QAAQ,UAAW,WAAW,uBAAuB,QAAQ,MAAU,EAC7E,OAAO,MAAM;AAChB,cAAM,iBAAiB,GAAG,iBAAiB,UAAU,CAAC,WAAW,WAAW,eAAe;AAC3F,YAAI,CAAC,sBAAsB,UAAU,mBAAmB;AAAI,iBAAO;AACnE,cAAM,kBAAkB,GAAG,eAAe,IAAI,CAAC,MAAM,UAAW,sBAAsB,SAAS,KAAK,IAAI,OAAO,MAAU,EAAE,OAAO,MAAM;AACxI,cAAM,gBAAgB,GAAG,iBAAiB,cAAc;AACxD,cAAM,mBAAmB,MAAM,cAAc,UAAU,EAAE;AACzD,eAAO,gBAAgB,IAAI,CAAC,uBAAuB,CAAC,kBAAkB,oBAAoB,aAAa,CAAU;AAAA,MACnH,CAAC;AAAA,IACH,GAEC,KAAK,EACL,OAAO,MAAM;AAChB,UAAM,YAAY,MAAM,KAAK,qBAAqB,gBAAgB;AAWlE,UAAM,iBACJ,MAAM,QAAQ;AAAA,MACZ,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,oBAAoB,aAAa,MAAM;AACnF,cAAM,UAAU,MAAM,UAAU,IAAI,CAAC,oBAAoB,aAAa,CAAC;AACvE,cAAM,wBAAwB,QAAQ,KAAK,gBAAgB;AAC3D,cAAM,mBAAmB,QAAQ,KAAK,WAAW;AACjD,YAAI,CAAC,yBAAyB,CAAC;AAAkB,iBAAO;AACxD,cAAM,+BAA+B,MAAM,cAAc,UAAU,qBAAqB;AACxF,cAAM,0BAA0B,MAAM,cAAc,UAAU,gBAAgB;AAC9E,YAAI,uBAAuB,gCAAgC,kBAAkB;AAAyB,iBAAO;AAC7G,eAAO,CAAC,kBAAkB,oBAAoB,uBAAuB,eAAe,gBAAgB;AAAA,MACtG,CAAC;AAAA,IACH,GACA,OAAO,MAAM;AAEf,UAAM,UAAkC,cAAc;AAAA,MACpD,CAAC,CAAC,kBAAkB,eAAe,kBAAkB,eAAe,gBAAgB,MAAM;AACxF,cAAM,EAAE,WAAW,IAAI,IAAI;AAC3B,cAAM,EAAE,UAAU,IAAI;AACtB,cAAM,SAAS,iBAAiB,MAAM;AACtC,cAAM,UAAU,iBAAiB,MAAM,SAAS,OAAO;AACvD,cAAM,UAAU,CAAC,kBAAkB,eAAe,aAAa;AAC/D,cAAM,SAAS,SAAS,EAAE,SAAS,QAAQ,SAAS,WAAW,IAAI,IAAI,EAAE,SAAS,SAAS,WAAW,IAAI;AAC1G,cAAM,SAAS,IAAI,eAAqC,EAAE,QAAQ,gCAAgC,CAAC,EAAE,OAAO,MAAM,EAAE,MAAM;AAC1H,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,KAAK,qBAAqB,YAAY;AACnE,UAAM,eAAe,OAAO,OAAO;AAEnC,UAAM,aAAa,SAAS,MAAM,SAAS;AAC3C,UAAM,eAAe,EAAE,GAAG,WAAW,QAAQ,WAAW;AACxD,UAAM,KAAK,YAAY,YAAY;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAgB,YAAY,OAAmC;AAC7D,UAAM,aAAa,SAAS,KAAK,OAAO,YAAY,WAAW,GAAG,UAAU,4BAA4B;AACxG,UAAM,SAAS,SAAS,MAAM,KAAK,QAAQ,UAAU,GAAG,GAAG,UAAU,gCAAgC;AACrG,UAAM,oBAAoB,QAAQ,OAAO,cAAc;AACrD,YAAM,MAAM,iBAAiB,KAAK,WAAW,KAAK,OAAO;AACzD,YAAM,UAAU,IAAI,eAAwD,EAAE,QAAQ,kBAAkB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM;AACnI,YAAM,IAAI,OAAO,CAAC,OAAO,CAAC;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,MAAyB,cAAc,WAAsB,CAAC,GAAoC;AAChG,UAAM,OAAO,SAAS,OAAO,4BAA4B;AACzD,UAAM,UAAU,MAAM,KAAK,0BAA0B,YAAY;AACjE,UAAM,WACJ,MAAM,QAAQ;AAAA,MACZ,KAAK,IAAI,OAAO,YAAY;AAC1B,cAAM,EAAE,OAAO,cAAc,QAAQ,eAAe,OAAO,cAAc,QAAQ,eAAe,SAAS,gBAAgB,IAAI,IAAI;AACjI,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,SAAS,iBAAiB;AAChC,cAAM,UAAU,kBAAkB;AAClC,cAAM,SAA6C,EAAE,OAAO,QAAQ,OAAO,SAAS,IAAI;AAExF,YAAI,mBAAmB;AAAW,iBAAO,SAAS,iBAAiB;AAEnE,YAAI,YAAY,QAAQ,kBAAkB;AAAW,iBAAO,SAAS;AACrE,cAAM,QAAQ,IAAI,eAA0C,EAAE,QAAQ,0BAA0B,CAAC,EAAE,OAAO,MAAM,EAAE,MAAM;AACxH,eAAO,MAAM,QAAQ,OAAO,CAAC,KAAK,CAAC;AAAA,MACrC,CAAC;AAAA,IACH,GAEC,KAAK,EACL,OAAO,sBAAsB;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,qBAAqB,OAAoB,MAAgB;AACvE,UAAM,OAAO,SAAS,KAAK,SAAS,KAAK,GAAG,WAAW,MAAM,GAAG,UAAU,gBAAgB,KAAK,0BAA0B;AACzH,UAAM,MAAM,SAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,YAAY;AAC1G,WAAO,OAAO,iBAAiB,KAAK,KAAK,KAAK,OAAO,IAAI,oBAAoB,KAAK,MAAM,GAAG,UAAU,KAAK,KAAK,gCAAgC;AAAA,EACjJ;AAAA,EAEA,MAAgB,+BAA+B,OAAoB,MAAgB;AACjF,UAAM,OAAO,SAAS,KAAK,SAAS,KAAK,GAAG,qBAAqB,MAAM,GAAG,UAAU,gBAAgB,KAAK,oCAAoC;AAC7I,UAAM,MAAM,SAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,sBAAsB;AACpH,WAAO,OACH,eAAe,KAAK,KAAK,KAAK,OAAO,IACrC,kBAAkB,KAAK,MAAM,GAAG,UAAU,KAAK,KAAK,uCAAuC;AAAA,EACjG;AAAA,EAEA,MAAgB,0BAA0B,OAAoB,MAAgB;AAC5E,UAAM,OAAO,SAAS,KAAK,SAAS,KAAK,GAAG,gBAAgB,MAAM,GAAG,UAAU,gBAAgB,KAAK,+BAA+B;AACnI,UAAM,MAAM,SAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,iBAAiB;AAC/G,WAAO,OAAO,eAAe,KAAK,KAAK,KAAK,OAAO,IAAI,kBAAkB,KAAK,MAAM,GAAG,UAAU,KAAK,KAAK,kCAAkC;AAAA,EAC/I;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAgB,gBAAiE;AAC/E,QAAI,OAAe;AACnB,UAAM,UAAU,MAAM,KAAK,+BAA+B,YAAY;AACtE,UAAM,QAAQ,IAAI,eAAgD,EAAE,QAAQ,+BAA+B,CAAC,EAAE,OAAO;AAAA,MACnH,SAAS,KAAK,QAAQ;AAAA,MACtB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,iBAAiB,CAAC,iBAAiB;AAAA,IACrC,CAAC;AACD,UAAM,iBAAiB,MAAM,QAAQ,OAAO,CAAC,KAAK,CAAC;AACnD,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,eAAe,eAAe,CAAC;AACrC,UAAI,eAAe,YAAY,GAAG;AAEhC,eAAO,aAAa,UACjB,IAAI,CAAC,SAAS,WAAW,EAAE,SAAS,MAAM,EAAE,EAC5C,OAAO,CAAC,EAAE,QAAQ,MAAM,YAAY,KAAK,QAAQ,OAAO,EACxD;AAAA,UACC,CAAC,MAAM,SAAU,aAAa,kBAAkB,MAAM,KAAK,MAAM,oBAAoB,aAAa,eAAe,MAAM,KAAK,IAAI;AAAA,UAChI;AAAA,QACF;AAAA,MACJ;AAAA,IACF;AAGA,QAAI,MAAM;AAER,YAAM,sBAAsB,SAAS,KAAK,OAAO,YAAY,WAAW,GAAG,UAAU,sCAAsC;AAC3H,YAAM;AAAA,QACJ,SAAS,MAAM,KAAK,QAAQ,mBAAmB,GAAG,GAAG,UAAU,0CAA0C;AAAA,QACzG,OAAO,QAAQ;AACb,gBAAM,YAAY,iBAAiB,KAAK,KAAK,KAAK,OAAO;AACzD,gBAAM,WAAW,MAAM,UAAU,IAAI,CAAC,IAAI,CAAC;AAC3C,cAAI,SAAS,SAAS,GAAG;AACvB,kBAAM,UAAU,SAAS,CAAC;AAC1B,gBAAI,cAAc,OAAO,GAAG;AAC1B,qBAAO,QAAQ;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAyB,eAAiC;AACxD,UAAM,MAAM,aAAa;AACzB,SAAK,KAAK;AACV,WAAO;AAAA,EACT;AAAA,EAEA,MAAyB,YAAY,UAAiD;AACpF,QAAI,KAAK,SAAS;AAChB,mBAAa,KAAK,OAAO;AACzB,WAAK,UAAU;AAAA,IACjB;AACA,WAAO,MAAM,MAAM,YAAY;AAAA,EACjC;AAAA,EAEQ,OAAO;AACb,SAAK,UAAU,WAAW,YAAY;AACpC,UAAI;AACF,cAAM,KAAK,iBAAiB;AAAA,MAC9B,SAAS,GAAG;AACV,gBAAQ,IAAI,CAAC;AAAA,MACf,UAAE;AACA,YAAI,KAAK;AAAS,uBAAa,KAAK,OAAO;AAC3C,aAAK,UAAU;AACf,aAAK,KAAK;AAAA,MACZ;AAAA,IACF,GAAG,KAAK,aAAa;AAAA,EACvB;AACF;","names":[]}
|