@xyo-network/diviner-image-thumbnail 2.75.11 → 2.75.13

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.
@@ -37,7 +37,6 @@ var import_diviner_wrapper = require("@xyo-network/diviner-wrapper");
37
37
  var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
38
38
  var import_module_model = require("@xyo-network/module-model");
39
39
  var import_payload_builder = require("@xyo-network/payload-builder");
40
- var import_url_payload_plugin = require("@xyo-network/url-payload-plugin");
41
40
  var import_witness_timestamp = require("@xyo-network/witness-timestamp");
42
41
  var moduleName = "ImageThumbnailDiviner";
43
42
  var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDiviner {
@@ -125,17 +124,11 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
125
124
  });
126
125
  }
127
126
  async divineHandler(payloads = []) {
128
- const urls = payloads.filter(import_url_payload_plugin.isUrlPayload);
127
+ const urls = payloads.filter(import_image_thumbnail_payload_plugin.isImageThumbnailDivinerQuery);
129
128
  const diviner = await this.getPayloadDivinerForStore("indexStore");
130
129
  const results = (await Promise.all(
131
130
  urls.map(async (payload) => {
132
- const {
133
- limit: payloadLimit,
134
- offset: payloadOffset,
135
- order: payloadOrder,
136
- status: payloadStatus,
137
- url
138
- } = payload;
131
+ const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, url } = payload;
139
132
  const limit = payloadLimit ?? 1;
140
133
  const order = payloadOrder ?? "desc";
141
134
  const offset = payloadOffset ?? 0;
@@ -1 +1 @@
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, SortDirection } 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 ImageThumbnailSchema,\n isImageThumbnail,\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 { isUrlPayload, UrlPayload } from '@xyo-network/url-payload-plugin'\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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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(isUrlPayload)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const {\n limit: payloadLimit,\n offset: payloadOffset,\n order: payloadOrder,\n status: payloadStatus,\n url,\n } = payload as UrlPayload & { limit: number; offset: number; order: SortDirection; status: boolean }\n // TODO: Expose status, limit (and possibly offset) to caller. Currently only exposing URL\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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
+ {"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 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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyB;AACzB,oBAAuB;AACvB,8BAAgC;AAChC,6BAAyD;AACzD,+BAAiC;AACjC,gCAA+B;AAC/B,kBAA8B;AAC9B,wCAAgF;AAChF,2BAAuD;AACvD,mCAAsE;AACtE,6BAA+B;AAC/B,4CAWO;AACP,0BAA+E;AAC/E,6BAA+B;AAE/B,+BAAwD;AAuBxD,IAAM,aAAa;AAEZ,IAAM,wBAAN,cAA+G,wCAAyB;AAAA,EAC7I,OAAgB,gBAAgB,CAAC,yEAAmC,wCAAmB;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,sCAAgD,EAAE,QAAQ,iEAA+B,CAAC,EAAE,OAAO;AAAA,MACnH,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,MACP,iBAAiB,CAAC,4DAAsB,wCAAe;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,wCAAc,EAAE,IAAI,OAAO,OAAO;AAC7C,cAAM,wBAAwB,GAAG,iBAC7B,IAAI,CAAC,QAAQ,UAAW,WAAW,6DAAuB,QAAQ,MAAU,EAC7E,OAAO,oBAAM;AAChB,cAAM,iBAAiB,GAAG,iBAAiB,UAAU,CAAC,WAAW,WAAW,wCAAe;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,oBAAM;AACxI,cAAM,gBAAgB,GAAG,iBAAiB,cAAc;AACxD,cAAM,mBAAmB,MAAM,0BAAc,UAAU,EAAE;AACzD,eAAO,gBAAgB,IAAI,CAAC,uBAAuB,CAAC,kBAAkB,oBAAoB,aAAa,CAAU;AAAA,MACnH,CAAC;AAAA,IACH,GAEC,KAAK,EACL,OAAO,oBAAM;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,sDAAgB;AAC3D,cAAM,mBAAmB,QAAQ,KAAK,oCAAW;AACjD,YAAI,CAAC,yBAAyB,CAAC;AAAkB,iBAAO;AACxD,cAAM,+BAA+B,MAAM,0BAAc,UAAU,qBAAqB;AACxF,cAAM,0BAA0B,MAAM,0BAAc,UAAU,gBAAgB;AAC9E,YAAI,uBAAuB,gCAAgC,kBAAkB;AAAyB,iBAAO;AAC7G,eAAO,CAAC,kBAAkB,oBAAoB,uBAAuB,eAAe,gBAAgB;AAAA,MACtG,CAAC;AAAA,IACH,GACA,OAAO,oBAAM;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,SAAS,OAAO;AACtD,cAAM,UAAU,CAAC,kBAAkB,eAAe,aAAa;AAC/D,cAAM,SAAS,IAAI,sCAAqC,EAAE,QAAQ,sEAAgC,CAAC,EAChG,OAAO,EAAE,SAAS,QAAQ,WAAW,IAAI,CAAC,EAC1C,MAAM;AACT,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,iBAAa,wBAAS,KAAK,OAAO,YAAY,WAAW,GAAG,UAAU,4BAA4B;AACxG,UAAMA,cAAS,wBAAS,MAAM,KAAK,QAAQ,UAAU,GAAG,GAAG,UAAU,gCAAgC;AACrG,cAAM,4CAAoBA,SAAQ,OAAO,cAAc;AACrD,YAAM,MAAM,0CAAiB,KAAK,WAAW,KAAK,OAAO;AACzD,YAAM,UAAU,IAAI,sCAAwD,EAAE,QAAQ,sCAAkB,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,kEAA4B;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,IAAI,IAAI;AACxG,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,SAAS,iBAAiB;AAChC,cAAM,SAAS,iBAAiB;AAChC,cAAM,QAAQ,IAAI,sCAA0C,EAAE,QAAQ,uDAA0B,CAAC,EAC9F,OAAO,EAAE,OAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC,EAC5C,MAAM;AACT,eAAO,MAAM,QAAQ,OAAO,CAAC,KAAK,CAAC;AAAA,MACrC,CAAC;AAAA,IACH,GAEC,KAAK,EACL,OAAO,4DAAsB;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,qBAAqB,OAAoB,MAAgB;AACvE,UAAM,WAAO,wBAAS,KAAK,SAAS,KAAK,GAAG,WAAW,MAAM,GAAG,UAAU,gBAAgB,KAAK,0BAA0B;AACzH,UAAM,UAAM,wBAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,YAAY;AAC1G,WAAO,OAAO,0CAAiB,KAAK,KAAK,KAAK,OAAO,QAAI,4CAAoB,KAAK,MAAM,GAAG,UAAU,KAAK,KAAK,gCAAgC;AAAA,EACjJ;AAAA,EAEA,MAAgB,+BAA+B,OAAoB,MAAgB;AACjF,UAAM,WAAO,wBAAS,KAAK,SAAS,KAAK,GAAG,qBAAqB,MAAM,GAAG,UAAU,gBAAgB,KAAK,oCAAoC;AAC7I,UAAM,UAAM,wBAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,sBAAsB;AACpH,WAAO,OACH,sCAAe,KAAK,KAAK,KAAK,OAAO,QACrC,wCAAkB,KAAK,MAAM,GAAG,UAAU,KAAK,KAAK,uCAAuC;AAAA,EACjG;AAAA,EAEA,MAAgB,0BAA0B,OAAoB,MAAgB;AAC5E,UAAM,WAAO,wBAAS,KAAK,SAAS,KAAK,GAAG,gBAAgB,MAAM,GAAG,UAAU,gBAAgB,KAAK,+BAA+B;AACnI,UAAM,UAAM,wBAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,iBAAiB;AAC/G,WAAO,OAAO,sCAAe,KAAK,KAAK,KAAK,OAAO,QAAI,wCAAkB,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,sCAAgD,EAAE,QAAQ,iEAA+B,CAAC,EAAE,OAAO;AAAA,MACnH,SAAS,KAAK,QAAQ;AAAA,MACtB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,iBAAiB,CAAC,qCAAiB;AAAA,IACrC,CAAC;AACD,UAAM,iBAAiB,MAAM,QAAQ,OAAO,CAAC,KAAK,CAAC;AACnD,QAAI,eAAe,SAAS,GAAG;AAC7B,YAAM,eAAe,eAAe,CAAC;AACrC,cAAI,0CAAe,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,wCAAoB,aAAa,eAAe,MAAM,KAAK,IAAI;AAAA,UAChI;AAAA,QACF;AAAA,MACJ;AAAA,IACF;AAGA,QAAI,MAAM;AAER,YAAM,0BAAsB,wBAAS,KAAK,OAAO,YAAY,WAAW,GAAG,UAAU,sCAAsC;AAC3H,gBAAM;AAAA,YACJ,wBAAS,MAAM,KAAK,QAAQ,mBAAmB,GAAG,GAAG,UAAU,0CAA0C;AAAA,QACzG,OAAO,QAAQ;AACb,gBAAM,YAAY,0CAAiB,KAAK,KAAK,KAAK,OAAO;AACzD,gBAAM,WAAW,MAAM,UAAU,IAAI,CAAC,IAAI,CAAC;AAC3C,cAAI,SAAS,SAAS,GAAG;AACvB,kBAAM,UAAU,SAAS,CAAC;AAC1B,oBAAI,mCAAc,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":["module"]}
@@ -1 +1 @@
1
- {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAKrB,MAAM,6CAA6C,CAAA;AACpD,OAAO,EAAiD,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAIpD,MAAM,MAAM,0BAA0B,GAAG,eAAe,GAAG;IACzD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAEpE,KAAK,WAAW,GAAG,OAAO,CAAC,MAAM,2BAA2B,EAAE,cAAc,CAAC,CAAA;AAiB7E,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,kFAA2D;IAExF,OAAO,CAAC,OAAO,CAAC,CAAkC;IAElD,IAAI,mBAAmB,WAEtB;IAED,IAAI,aAAa,WAEhB;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,QAAa,QAAQ,IAAI,CAAC,CA8EnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAUpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cA8BjF,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAMvD,8BAA8B,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAQjE,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;IAM5E;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cA8CvD,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;cAMhC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF,OAAO,CAAC,IAAI;CAab"}
1
+ {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAMrB,MAAM,6CAA6C,CAAA;AACpD,OAAO,EAAiD,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAGpD,MAAM,MAAM,0BAA0B,GAAG,eAAe,GAAG;IACzD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAEpE,KAAK,WAAW,GAAG,OAAO,CAAC,MAAM,2BAA2B,EAAE,cAAc,CAAC,CAAA;AAiB7E,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,kFAA2D;IAExF,OAAO,CAAC,OAAO,CAAC,CAAkC;IAElD,IAAI,mBAAmB,WAEtB;IAED,IAAI,aAAa,WAEhB;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,QAAa,QAAQ,IAAI,CAAC,CA8EnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAUpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAMvD,8BAA8B,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAQjE,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;IAM5E;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cA8CvD,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;cAMhC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF,OAAO,CAAC,IAAI;CAab"}
@@ -1 +1 @@
1
- {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAKrB,MAAM,6CAA6C,CAAA;AACpD,OAAO,EAAiD,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAIpD,MAAM,MAAM,0BAA0B,GAAG,eAAe,GAAG;IACzD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAEpE,KAAK,WAAW,GAAG,OAAO,CAAC,MAAM,2BAA2B,EAAE,cAAc,CAAC,CAAA;AAiB7E,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,kFAA2D;IAExF,OAAO,CAAC,OAAO,CAAC,CAAkC;IAElD,IAAI,mBAAmB,WAEtB;IAED,IAAI,aAAa,WAEhB;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,QAAa,QAAQ,IAAI,CAAC,CA8EnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAUpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cA8BjF,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAMvD,8BAA8B,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAQjE,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;IAM5E;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cA8CvD,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;cAMhC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF,OAAO,CAAC,IAAI;CAab"}
1
+ {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAMrB,MAAM,6CAA6C,CAAA;AACpD,OAAO,EAAiD,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAGpD,MAAM,MAAM,0BAA0B,GAAG,eAAe,GAAG;IACzD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAEpE,KAAK,WAAW,GAAG,OAAO,CAAC,MAAM,2BAA2B,EAAE,cAAc,CAAC,CAAA;AAiB7E,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,kFAA2D;IAExF,OAAO,CAAC,OAAO,CAAC,CAAkC;IAElD,IAAI,mBAAmB,WAEtB;IAED,IAAI,aAAa,WAEhB;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,QAAa,QAAQ,IAAI,CAAC,CA8EnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAUpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAMvD,8BAA8B,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAQjE,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;IAM5E;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cA8CvD,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;cAMhC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF,OAAO,CAAC,IAAI;CAab"}
@@ -1 +1 @@
1
- {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAKrB,MAAM,6CAA6C,CAAA;AACpD,OAAO,EAAiD,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAIpD,MAAM,MAAM,0BAA0B,GAAG,eAAe,GAAG;IACzD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAEpE,KAAK,WAAW,GAAG,OAAO,CAAC,MAAM,2BAA2B,EAAE,cAAc,CAAC,CAAA;AAiB7E,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,kFAA2D;IAExF,OAAO,CAAC,OAAO,CAAC,CAAkC;IAElD,IAAI,mBAAmB,WAEtB;IAED,IAAI,aAAa,WAEhB;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,QAAa,QAAQ,IAAI,CAAC,CA8EnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAUpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cA8BjF,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAMvD,8BAA8B,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAQjE,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;IAM5E;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cA8CvD,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;cAMhC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF,OAAO,CAAC,IAAI;CAab"}
1
+ {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAMjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAMrB,MAAM,6CAA6C,CAAA;AACpD,OAAO,EAAiD,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE1G,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAGpD,MAAM,MAAM,0BAA0B,GAAG,eAAe,GAAG;IACzD,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG,YAAY,GAAG,YAAY,GAAG,gBAAgB,CAAA;AAEpE,KAAK,WAAW,GAAG,OAAO,CAAC,MAAM,2BAA2B,EAAE,cAAc,CAAC,CAAA;AAiB7E,qBAAa,qBAAqB,CAAC,OAAO,SAAS,2BAA2B,GAAG,2BAA2B,CAAE,SAAQ,eAAe,CAAC,OAAO,CAAC;IAC5I,OAAgB,aAAa,kFAA2D;IAExF,OAAO,CAAC,OAAO,CAAC,CAAkC;IAElD,IAAI,mBAAmB,WAEtB;IAED,IAAI,aAAa,WAEhB;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,QAAa,QAAQ,IAAI,CAAC,CA8EnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAUpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAMvD,8BAA8B,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;cAQjE,yBAAyB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO;IAM5E;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cA8CvD,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;cAMhC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAQrF,OAAO,CAAC,IAAI;CAab"}
@@ -15,11 +15,11 @@ import {
15
15
  ImageThumbnailResultIndexSchema,
16
16
  ImageThumbnailSchema,
17
17
  isImageThumbnail,
18
+ isImageThumbnailDivinerQuery,
18
19
  isImageThumbnailResult
19
20
  } from "@xyo-network/image-thumbnail-payload-plugin";
20
21
  import { isModuleState, ModuleStateSchema } from "@xyo-network/module-model";
21
22
  import { PayloadBuilder } from "@xyo-network/payload-builder";
22
- import { isUrlPayload } from "@xyo-network/url-payload-plugin";
23
23
  import { isTimestamp, TimestampSchema } from "@xyo-network/witness-timestamp";
24
24
  var moduleName = "ImageThumbnailDiviner";
25
25
  var ImageThumbnailDiviner = class extends AbstractDiviner {
@@ -107,17 +107,11 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
107
107
  });
108
108
  }
109
109
  async divineHandler(payloads = []) {
110
- const urls = payloads.filter(isUrlPayload);
110
+ const urls = payloads.filter(isImageThumbnailDivinerQuery);
111
111
  const diviner = await this.getPayloadDivinerForStore("indexStore");
112
112
  const results = (await Promise.all(
113
113
  urls.map(async (payload) => {
114
- const {
115
- limit: payloadLimit,
116
- offset: payloadOffset,
117
- order: payloadOrder,
118
- status: payloadStatus,
119
- url
120
- } = payload;
114
+ const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, url } = payload;
121
115
  const limit = payloadLimit ?? 1;
122
116
  const order = payloadOrder ?? "desc";
123
117
  const offset = payloadOffset ?? 0;
@@ -1 +1 @@
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, SortDirection } 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 ImageThumbnailSchema,\n isImageThumbnail,\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 { isUrlPayload, UrlPayload } from '@xyo-network/url-payload-plugin'\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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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(isUrlPayload)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const {\n limit: payloadLimit,\n offset: payloadOffset,\n order: payloadOrder,\n status: payloadStatus,\n url,\n } = payload as UrlPayload & { limit: number; offset: number; order: SortDirection; status: boolean }\n // TODO: Expose status, limit (and possibly offset) to caller. Currently only exposing URL\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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":[]}
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 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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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":[]}
@@ -39,7 +39,6 @@ var import_diviner_wrapper = require("@xyo-network/diviner-wrapper");
39
39
  var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
40
40
  var import_module_model = require("@xyo-network/module-model");
41
41
  var import_payload_builder = require("@xyo-network/payload-builder");
42
- var import_url_payload_plugin = require("@xyo-network/url-payload-plugin");
43
42
  var import_witness_timestamp = require("@xyo-network/witness-timestamp");
44
43
  var moduleName = "ImageThumbnailDiviner";
45
44
  var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDiviner {
@@ -127,17 +126,11 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
127
126
  });
128
127
  }
129
128
  async divineHandler(payloads = []) {
130
- const urls = payloads.filter(import_url_payload_plugin.isUrlPayload);
129
+ const urls = payloads.filter(import_image_thumbnail_payload_plugin.isImageThumbnailDivinerQuery);
131
130
  const diviner = await this.getPayloadDivinerForStore("indexStore");
132
131
  const results = (await Promise.all(
133
132
  urls.map(async (payload) => {
134
- const {
135
- limit: payloadLimit,
136
- offset: payloadOffset,
137
- order: payloadOrder,
138
- status: payloadStatus,
139
- url
140
- } = payload;
133
+ const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, url } = payload;
141
134
  const limit = payloadLimit ?? 1;
142
135
  const order = payloadOrder ?? "desc";
143
136
  const offset = payloadOffset ?? 0;
@@ -1 +1 @@
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, SortDirection } 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 ImageThumbnailSchema,\n isImageThumbnail,\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 { isUrlPayload, UrlPayload } from '@xyo-network/url-payload-plugin'\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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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(isUrlPayload)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const {\n limit: payloadLimit,\n offset: payloadOffset,\n order: payloadOrder,\n status: payloadStatus,\n url,\n } = payload as UrlPayload & { limit: number; offset: number; order: SortDirection; status: boolean }\n // TODO: Expose status, limit (and possibly offset) to caller. Currently only exposing URL\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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
+ {"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 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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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"]}
@@ -15,11 +15,11 @@ import {
15
15
  ImageThumbnailResultIndexSchema,
16
16
  ImageThumbnailSchema,
17
17
  isImageThumbnail,
18
+ isImageThumbnailDivinerQuery,
18
19
  isImageThumbnailResult
19
20
  } from "@xyo-network/image-thumbnail-payload-plugin";
20
21
  import { isModuleState, ModuleStateSchema } from "@xyo-network/module-model";
21
22
  import { PayloadBuilder } from "@xyo-network/payload-builder";
22
- import { isUrlPayload } from "@xyo-network/url-payload-plugin";
23
23
  import { isTimestamp, TimestampSchema } from "@xyo-network/witness-timestamp";
24
24
  var moduleName = "ImageThumbnailDiviner";
25
25
  var ImageThumbnailDiviner = class extends AbstractDiviner {
@@ -107,17 +107,11 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
107
107
  });
108
108
  }
109
109
  async divineHandler(payloads = []) {
110
- const urls = payloads.filter(isUrlPayload);
110
+ const urls = payloads.filter(isImageThumbnailDivinerQuery);
111
111
  const diviner = await this.getPayloadDivinerForStore("indexStore");
112
112
  const results = (await Promise.all(
113
113
  urls.map(async (payload) => {
114
- const {
115
- limit: payloadLimit,
116
- offset: payloadOffset,
117
- order: payloadOrder,
118
- status: payloadStatus,
119
- url
120
- } = payload;
114
+ const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, url } = payload;
121
115
  const limit = payloadLimit ?? 1;
122
116
  const order = payloadOrder ?? "desc";
123
117
  const offset = payloadOffset ?? 0;
@@ -1 +1 @@
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, SortDirection } 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 ImageThumbnailSchema,\n isImageThumbnail,\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 { isUrlPayload, UrlPayload } from '@xyo-network/url-payload-plugin'\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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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(isUrlPayload)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const {\n limit: payloadLimit,\n offset: payloadOffset,\n order: payloadOrder,\n status: payloadStatus,\n url,\n } = payload as UrlPayload & { limit: number; offset: number; order: SortDirection; status: boolean }\n // TODO: Expose status, limit (and possibly offset) to caller. Currently only exposing URL\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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":[]}
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 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 ImageThumbnailResult, 'url' | 'timestamp' | 'status'>\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 ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })\n .fields({ sources, status, timestamp, url })\n .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, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const status = payloadStatus ?? true\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })\n .fields({ limit, offset, order, status, url })\n .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,EACA;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,SAAS,OAAO;AACtD,cAAM,UAAU,CAAC,kBAAkB,eAAe,aAAa;AAC/D,cAAM,SAAS,IAAI,eAAqC,EAAE,QAAQ,gCAAgC,CAAC,EAChG,OAAO,EAAE,SAAS,QAAQ,WAAW,IAAI,CAAC,EAC1C,MAAM;AACT,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,IAAI,IAAI;AACxG,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,SAAS,iBAAiB;AAChC,cAAM,SAAS,iBAAiB;AAChC,cAAM,QAAQ,IAAI,eAA0C,EAAE,QAAQ,0BAA0B,CAAC,EAC9F,OAAO,EAAE,OAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC,EAC5C,MAAM;AACT,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":[]}
@@ -39,7 +39,6 @@ var import_diviner_wrapper = require("@xyo-network/diviner-wrapper");
39
39
  var import_image_thumbnail_payload_plugin = require("@xyo-network/image-thumbnail-payload-plugin");
40
40
  var import_module_model = require("@xyo-network/module-model");
41
41
  var import_payload_builder = require("@xyo-network/payload-builder");
42
- var import_url_payload_plugin = require("@xyo-network/url-payload-plugin");
43
42
  var import_witness_timestamp = require("@xyo-network/witness-timestamp");
44
43
  var moduleName = "ImageThumbnailDiviner";
45
44
  var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDiviner {
@@ -127,17 +126,11 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
127
126
  });
128
127
  }
129
128
  async divineHandler(payloads = []) {
130
- const urls = payloads.filter(import_url_payload_plugin.isUrlPayload);
129
+ const urls = payloads.filter(import_image_thumbnail_payload_plugin.isImageThumbnailDivinerQuery);
131
130
  const diviner = await this.getPayloadDivinerForStore("indexStore");
132
131
  const results = (await Promise.all(
133
132
  urls.map(async (payload) => {
134
- const {
135
- limit: payloadLimit,
136
- offset: payloadOffset,
137
- order: payloadOrder,
138
- status: payloadStatus,
139
- url
140
- } = payload;
133
+ const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, url } = payload;
141
134
  const limit = payloadLimit ?? 1;
142
135
  const order = payloadOrder ?? "desc";
143
136
  const offset = payloadOffset ?? 0;