@xyo-network/diviner-image-thumbnail 2.77.3 → 2.77.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/Diviner/Diviner.d.cts.map +1 -1
- package/dist/browser/Diviner/Diviner.d.mts.map +1 -1
- package/dist/browser/Diviner/Diviner.d.ts.map +1 -1
- package/dist/browser/index.cjs +7 -8
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.js +7 -8
- package/dist/browser/index.js.map +1 -1
- package/dist/node/Diviner/Diviner.d.cts.map +1 -1
- package/dist/node/Diviner/Diviner.d.mts.map +1 -1
- package/dist/node/Diviner/Diviner.d.ts.map +1 -1
- package/dist/node/index.js +8 -9
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +8 -9
- package/dist/node/index.mjs.map +1 -1
- package/package.json +20 -20
- package/src/Diviner/Diviner.ts +9 -8
|
@@ -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;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,
|
|
1
|
+
{"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,CAoFnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAOpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW;cAMvC,8BAA8B,CAAC,KAAK,EAAE,WAAW;cAMjD,yBAAyB,CAAC,KAAK,EAAE,WAAW;IAM5D;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cAuCvD,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;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,
|
|
1
|
+
{"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,CAoFnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAOpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW;cAMvC,8BAA8B,CAAC,KAAK,EAAE,WAAW;cAMjD,yBAAyB,CAAC,KAAK,EAAE,WAAW;IAM5D;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cAuCvD,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;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,
|
|
1
|
+
{"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,CAoFnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAOpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW;cAMvC,8BAA8B,CAAC,KAAK,EAAE,WAAW;cAMjD,yBAAyB,CAAC,KAAK,EAAE,WAAW;IAM5D;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cAuCvD,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"}
|
package/dist/browser/index.cjs
CHANGED
|
@@ -85,8 +85,10 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
85
85
|
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
86
86
|
const imageThumbnailPayload = results.find(import_image_thumbnail_payload_plugin.isImageThumbnail);
|
|
87
87
|
const timestampPayload = results.find(import_witness_timestamp.isTimestamp);
|
|
88
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
88
|
+
if (!imageThumbnailPayload || !timestampPayload) {
|
|
89
|
+
console.log("Could not find payload from hash to index");
|
|
89
90
|
return void 0;
|
|
91
|
+
}
|
|
90
92
|
const calculatedImageThumbnailHash = await import_core.PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
91
93
|
const calculatedTimestampHash = await import_core.PayloadHasher.hashAsync(timestampPayload);
|
|
92
94
|
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
@@ -99,9 +101,9 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
99
101
|
const { sourceUrl: url } = thumbnailPayload;
|
|
100
102
|
const { timestamp } = timestampPayload;
|
|
101
103
|
const status = thumbnailPayload.http?.status;
|
|
102
|
-
const success = thumbnailPayload.
|
|
104
|
+
const success = !!thumbnailPayload.url;
|
|
103
105
|
const sources = [boundWitnessHash, thumbnailHash, timestampHash];
|
|
104
|
-
const fields =
|
|
106
|
+
const fields = { sources, status, success, timestamp, url };
|
|
105
107
|
const result = new import_payload_builder.PayloadBuilder({ schema: import_image_thumbnail_payload_plugin.ImageThumbnailResultIndexSchema }).fields(fields).build();
|
|
106
108
|
return result;
|
|
107
109
|
}
|
|
@@ -134,11 +136,8 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
134
136
|
const order = payloadOrder ?? "desc";
|
|
135
137
|
const offset = payloadOffset ?? 0;
|
|
136
138
|
const success = payloadSuccess;
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
fields.status = payloadStatus ?? 200;
|
|
140
|
-
if (success === true && payloadStatus !== void 0)
|
|
141
|
-
fields.status = payloadStatus;
|
|
139
|
+
const status = payloadStatus;
|
|
140
|
+
const fields = { ...{ limit, offset, order, status, success, url } };
|
|
142
141
|
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_payload_model.PayloadDivinerQuerySchema }).fields(fields).build();
|
|
143
142
|
return await diviner.divine([query]);
|
|
144
143
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n // Find all the indexable hashes in this batch\n type IndexableHashes = Readonly<[boundWitnessHash: string, imageThumbnailHash: string, timestampHash: string]>\n const indexableHashes: IndexableHashes[] = (\n await Promise.all(\n batch.filter(isBoundWitness).map(async (bw) => {\n const imageThumbnailIndexes = bw.payload_schemas\n ?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined))\n .filter(exists)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined\n const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)\n const timestampHash = bw.payload_hashes?.[timestampIndex]\n const boundWitnessHash = await PayloadHasher.hashAsync(bw)\n return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash] as const)\n }),\n )\n )\n .flat()\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n // Find all the indexable data associated with the indexable hashes\n type IndexableData = Readonly<\n [\n boundWitnessHash: string,\n imageThumbnailHash: string,\n imageThumbnailPayload: ImageThumbnail,\n timestampHash: string,\n timestampPayload: TimeStamp,\n ]\n >\n const indexableData: IndexableData[] = (\n await Promise.all(\n indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n const success = thumbnailPayload.http?.status ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const fields: Partial<ImageThumbnailResultQuery> = { limit, offset, order, success, url }\n // Default to filtering on 200 status code if success was not supplied\n if (payloadSuccess === true) fields.status = payloadStatus ?? 200\n // If success is true and status was supplied, use it\n if (success === true && payloadStatus !== undefined) fields.status = payloadStatus\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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/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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\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) {\n console.log('Could not find payload from hash to index')\n return undefined\n }\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n //call anything with a thumbnail url a success\n const success = !!thumbnailPayload.url\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = { sources, status, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const status = payloadStatus\n const fields: Partial<ImageThumbnailResultQuery> = { ...{ limit, offset, order, status, success, url } }\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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":[]}
|
package/dist/browser/index.js
CHANGED
|
@@ -66,8 +66,10 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
|
66
66
|
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
67
67
|
const imageThumbnailPayload = results.find(isImageThumbnail);
|
|
68
68
|
const timestampPayload = results.find(isTimestamp);
|
|
69
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
69
|
+
if (!imageThumbnailPayload || !timestampPayload) {
|
|
70
|
+
console.log("Could not find payload from hash to index");
|
|
70
71
|
return void 0;
|
|
72
|
+
}
|
|
71
73
|
const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
72
74
|
const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload);
|
|
73
75
|
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
@@ -80,9 +82,9 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
|
80
82
|
const { sourceUrl: url } = thumbnailPayload;
|
|
81
83
|
const { timestamp } = timestampPayload;
|
|
82
84
|
const status = thumbnailPayload.http?.status;
|
|
83
|
-
const success = thumbnailPayload.
|
|
85
|
+
const success = !!thumbnailPayload.url;
|
|
84
86
|
const sources = [boundWitnessHash, thumbnailHash, timestampHash];
|
|
85
|
-
const fields =
|
|
87
|
+
const fields = { sources, status, success, timestamp, url };
|
|
86
88
|
const result = new PayloadBuilder({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build();
|
|
87
89
|
return result;
|
|
88
90
|
}
|
|
@@ -115,11 +117,8 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
|
115
117
|
const order = payloadOrder ?? "desc";
|
|
116
118
|
const offset = payloadOffset ?? 0;
|
|
117
119
|
const success = payloadSuccess;
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
fields.status = payloadStatus ?? 200;
|
|
121
|
-
if (success === true && payloadStatus !== void 0)
|
|
122
|
-
fields.status = payloadStatus;
|
|
120
|
+
const status = payloadStatus;
|
|
121
|
+
const fields = { ...{ limit, offset, order, status, success, url } };
|
|
123
122
|
const query = new PayloadBuilder({ schema: PayloadDivinerQuerySchema }).fields(fields).build();
|
|
124
123
|
return await diviner.divine([query]);
|
|
125
124
|
})
|
|
@@ -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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n // Find all the indexable hashes in this batch\n type IndexableHashes = Readonly<[boundWitnessHash: string, imageThumbnailHash: string, timestampHash: string]>\n const indexableHashes: IndexableHashes[] = (\n await Promise.all(\n batch.filter(isBoundWitness).map(async (bw) => {\n const imageThumbnailIndexes = bw.payload_schemas\n ?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined))\n .filter(exists)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined\n const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)\n const timestampHash = bw.payload_hashes?.[timestampIndex]\n const boundWitnessHash = await PayloadHasher.hashAsync(bw)\n return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash] as const)\n }),\n )\n )\n .flat()\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n // Find all the indexable data associated with the indexable hashes\n type IndexableData = Readonly<\n [\n boundWitnessHash: string,\n imageThumbnailHash: string,\n imageThumbnailPayload: ImageThumbnail,\n timestampHash: string,\n timestampPayload: TimeStamp,\n ]\n >\n const indexableData: IndexableData[] = (\n await Promise.all(\n indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n const success = thumbnailPayload.http?.status ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const fields: Partial<ImageThumbnailResultQuery> = { limit, offset, order, success, url }\n // Default to filtering on 200 status code if success was not supplied\n if (payloadSuccess === true) fields.status = payloadStatus ?? 200\n // If success is true and status was supplied, use it\n if (success === true && payloadStatus !== undefined) fields.status = payloadStatus\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\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) {\n console.log('Could not find payload from hash to index')\n return undefined\n }\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n //call anything with a thumbnail url a success\n const success = !!thumbnailPayload.url\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = { sources, status, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const status = payloadStatus\n const fields: Partial<ImageThumbnailResultQuery> = { ...{ limit, offset, order, status, success, url } }\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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 +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;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,
|
|
1
|
+
{"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,CAoFnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAOpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW;cAMvC,8BAA8B,CAAC,KAAK,EAAE,WAAW;cAMjD,yBAAyB,CAAC,KAAK,EAAE,WAAW;IAM5D;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cAuCvD,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;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,
|
|
1
|
+
{"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,CAoFnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAOpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW;cAMvC,8BAA8B,CAAC,KAAK,EAAE,WAAW;cAMjD,yBAAyB,CAAC,KAAK,EAAE,WAAW;IAM5D;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cAuCvD,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;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,
|
|
1
|
+
{"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Diviner/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAOjE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,2BAA2B,EAE3B,2BAA2B,EAC3B,oBAAoB,EAOrB,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,CAoFnD;IAED;;;;;OAKG;cACa,WAAW,CAAC,KAAK,EAAE,0BAA0B;cAOpC,aAAa,CAAC,QAAQ,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAuBjF,oBAAoB,CAAC,KAAK,EAAE,WAAW;cAMvC,8BAA8B,CAAC,KAAK,EAAE,WAAW;cAMjD,yBAAyB,CAAC,KAAK,EAAE,WAAW;IAM5D;;;OAGG;cACa,aAAa,IAAI,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;cAuCvD,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"}
|
package/dist/node/index.js
CHANGED
|
@@ -86,8 +86,10 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
86
86
|
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
87
87
|
const imageThumbnailPayload = results.find(import_image_thumbnail_payload_plugin.isImageThumbnail);
|
|
88
88
|
const timestampPayload = results.find(import_witness_timestamp.isTimestamp);
|
|
89
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
89
|
+
if (!imageThumbnailPayload || !timestampPayload) {
|
|
90
|
+
console.log("Could not find payload from hash to index");
|
|
90
91
|
return void 0;
|
|
92
|
+
}
|
|
91
93
|
const calculatedImageThumbnailHash = await import_core.PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
92
94
|
const calculatedTimestampHash = await import_core.PayloadHasher.hashAsync(timestampPayload);
|
|
93
95
|
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
@@ -97,13 +99,13 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
97
99
|
)).filter(import_exists.exists);
|
|
98
100
|
const indexes = indexableData.map(
|
|
99
101
|
([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {
|
|
100
|
-
var _a
|
|
102
|
+
var _a;
|
|
101
103
|
const { sourceUrl: url } = thumbnailPayload;
|
|
102
104
|
const { timestamp } = timestampPayload;
|
|
103
105
|
const status = (_a = thumbnailPayload.http) == null ? void 0 : _a.status;
|
|
104
|
-
const success =
|
|
106
|
+
const success = !!thumbnailPayload.url;
|
|
105
107
|
const sources = [boundWitnessHash, thumbnailHash, timestampHash];
|
|
106
|
-
const fields =
|
|
108
|
+
const fields = { sources, status, success, timestamp, url };
|
|
107
109
|
const result = new import_payload_builder.PayloadBuilder({ schema: import_image_thumbnail_payload_plugin.ImageThumbnailResultIndexSchema }).fields(fields).build();
|
|
108
110
|
return result;
|
|
109
111
|
}
|
|
@@ -136,11 +138,8 @@ var ImageThumbnailDiviner = class extends import_abstract_diviner.AbstractDivine
|
|
|
136
138
|
const order = payloadOrder ?? "desc";
|
|
137
139
|
const offset = payloadOffset ?? 0;
|
|
138
140
|
const success = payloadSuccess;
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
fields.status = payloadStatus ?? 200;
|
|
142
|
-
if (success === true && payloadStatus !== void 0)
|
|
143
|
-
fields.status = payloadStatus;
|
|
141
|
+
const status = payloadStatus;
|
|
142
|
+
const fields = { ...{ limit, offset, order, status, success, url } };
|
|
144
143
|
const query = new import_payload_builder.PayloadBuilder({ schema: import_diviner_payload_model.PayloadDivinerQuerySchema }).fields(fields).build();
|
|
145
144
|
return await diviner.divine([query]);
|
|
146
145
|
})
|
package/dist/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n // Find all the indexable hashes in this batch\n type IndexableHashes = Readonly<[boundWitnessHash: string, imageThumbnailHash: string, timestampHash: string]>\n const indexableHashes: IndexableHashes[] = (\n await Promise.all(\n batch.filter(isBoundWitness).map(async (bw) => {\n const imageThumbnailIndexes = bw.payload_schemas\n ?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined))\n .filter(exists)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined\n const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)\n const timestampHash = bw.payload_hashes?.[timestampIndex]\n const boundWitnessHash = await PayloadHasher.hashAsync(bw)\n return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash] as const)\n }),\n )\n )\n .flat()\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n // Find all the indexable data associated with the indexable hashes\n type IndexableData = Readonly<\n [\n boundWitnessHash: string,\n imageThumbnailHash: string,\n imageThumbnailPayload: ImageThumbnail,\n timestampHash: string,\n timestampPayload: TimeStamp,\n ]\n >\n const indexableData: IndexableData[] = (\n await Promise.all(\n indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n const success = thumbnailPayload.http?.status ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const fields: Partial<ImageThumbnailResultQuery> = { limit, offset, order, success, url }\n // Default to filtering on 200 status code if success was not supplied\n if (payloadSuccess === true) fields.status = payloadStatus ?? 200\n // If success is true and status was supplied, use it\n if (success === true && payloadStatus !== undefined) fields.status = payloadStatus\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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;;;ACAA,oBAAyB;AACzB,oBAAuB;AACvB,8BAAgC;AAChC,+BAAiC;AACjC,kCAAoC;AACpC,gCAA+B;AAC/B,kBAA8B;AAC9B,wCAAgF;AAChF,2BAAoC;AACpC,mCAAsE;AACtE,6BAA+B;AAC/B,4CAYO;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,EACzG,OAAO;AAAA,MACN,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,OAAO;AAAA,MACP,iBAAiB,CAAC,4DAAsB,wCAAe;AAAA,IACzD,CAAC,EACA,MAAM;AACT,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;AAzFvD;AA0FU,cAAM,yBAAwB,QAAG,oBAAH,mBAC1B,IAAI,CAAC,QAAQ,UAAW,WAAW,6DAAuB,QAAQ,QACnE,OAAO;AACV,cAAM,kBAAiB,QAAG,oBAAH,mBAAoB,UAAU,CAAC,WAAW,WAAW;AAC5E,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,iBAAgB,QAAG,mBAAH,mBAAoB;AAC1C,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;AAnIhG;AAoIQ,cAAM,EAAE,WAAW,IAAI,IAAI;AAC3B,cAAM,EAAE,UAAU,IAAI;AACtB,cAAM,UAAS,sBAAiB,SAAjB,mBAAuB;AACtC,cAAM,YAAU,sBAAiB,SAAjB,mBAAuB,UAAS,OAAO;AACvD,cAAM,UAAU,CAAC,kBAAkB,eAAe,aAAa;AAC/D,cAAM,SAAS,SAAS,EAAE,SAAS,QAAQ,SAAS,WAAW,IAAI,IAAI,EAAE,SAAS,SAAS,WAAW,IAAI;AAC1G,cAAM,SAAS,IAAI,sCAAqC,EAAE,QAAQ,sEAAgC,CAAC,EAAE,OAAO,MAAM,EAAE,MAAM;AAC1H,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,KAAK,qBAAqB,YAAY;AACnE,UAAM,eAAe,OAAO,OAAO;AAEnC,UAAM,aAAa,SAAS,MAAM;AAClC,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,YAAY,MAAM,KAAK,qBAAqB,YAAY;AAC9D,UAAM,UAAU,IAAI,sCAAwD,EAAE,QAAQ,sCAAkB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM;AACnI,UAAM,CAAC,EAAE,IAAI,MAAM,IAAI,gDAAoB,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,KAAK,OAAO,EAAE,MAAM;AAC7F,UAAM,UAAU,OAAO,CAAC,IAAI,OAAO,CAAC;AAAA,EACtC;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,SAAS,gBAAgB,IAAI,IAAI;AACjI,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,QAAQ,gBAAgB;AAC9B,cAAM,SAAS,iBAAiB;AAChC,cAAM,UAAU;AAChB,cAAM,SAA6C,EAAE,OAAO,QAAQ,OAAO,SAAS,IAAI;AAExF,YAAI,mBAAmB;AAAM,iBAAO,SAAS,iBAAiB;AAE9D,YAAI,YAAY,QAAQ,kBAAkB;AAAW,iBAAO,SAAS;AACrE,cAAM,QAAQ,IAAI,sCAA0C,EAAE,QAAQ,uDAA0B,CAAC,EAAE,OAAO,MAAM,EAAE,MAAM;AACxH,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;AA9L3D;AA+LI,UAAM,WAAO,yBAAS,gBAAK,WAAL,mBAAc,WAAd,mBAAsB,WAAW,MAAM,GAAG,UAAU,gBAAgB,KAAK,0BAA0B;AACzH,UAAM,UAAM,wBAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,YAAY;AAC1G,WAAO,0CAAiB,KAAK,KAAK,KAAK,OAAO;AAAA,EAChD;AAAA,EAEA,MAAgB,+BAA+B,OAAoB;AApMrE;AAqMI,UAAM,WAAO,yBAAS,gBAAK,WAAL,mBAAc,WAAd,mBAAsB,qBAAqB,MAAM,GAAG,UAAU,gBAAgB,KAAK,oCAAoC;AAC7I,UAAM,UAAM,wBAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,GAAG,UAAU,uBAAuB,KAAK,sBAAsB;AACpH,WAAO,sCAAe,KAAK,KAAK,KAAK,OAAO;AAAA,EAC9C;AAAA,EAEA,MAAgB,0BAA0B,OAAoB;AA1MhE;AA2MI,UAAM,WAAO,yBAAS,gBAAK,WAAL,mBAAc,WAAd,mBAAsB,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,sCAAe,KAAK,KAAK,KAAK,OAAO;AAAA,EAC9C;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,EACzG,OAAO;AAAA,MACN,SAAS,KAAK,QAAQ;AAAA,MACtB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,iBAAiB,CAAC,qCAAiB;AAAA,IACrC,CAAC,EACA,MAAM;AACT,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,SAAM;AAzOzB;AAyO6B,uCAAa,oBAAb,mBAA+B,6BAAM,YAAW,wCAAoB,aAAa,eAAe,6BAAM,KAAK,IAAI;AAAA;AAAA,UAChI;AAAA,QACF;AAAA,MACJ;AAAA,IACF;AAGA,QAAI,MAAM;AAER,YAAM,YAAY,MAAM,KAAK,qBAAqB,YAAY;AAC9D,YAAM,WAAW,MAAM,UAAU,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,iCAAa;AAChE,UAAI,SAAS;AACX,eAAO,QAAQ;AAAA,MACjB;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":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\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) {\n console.log('Could not find payload from hash to index')\n return undefined\n }\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n //call anything with a thumbnail url a success\n const success = !!thumbnailPayload.url\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = { sources, status, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const status = payloadStatus\n const fields: Partial<ImageThumbnailResultQuery> = { ...{ limit, offset, order, status, success, url } }\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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":[]}
|
package/dist/node/index.mjs
CHANGED
|
@@ -67,8 +67,10 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
|
67
67
|
const results = await archivist.get([imageThumbnailHash, timestampHash]);
|
|
68
68
|
const imageThumbnailPayload = results.find(isImageThumbnail);
|
|
69
69
|
const timestampPayload = results.find(isTimestamp);
|
|
70
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
70
|
+
if (!imageThumbnailPayload || !timestampPayload) {
|
|
71
|
+
console.log("Could not find payload from hash to index");
|
|
71
72
|
return void 0;
|
|
73
|
+
}
|
|
72
74
|
const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload);
|
|
73
75
|
const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload);
|
|
74
76
|
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash)
|
|
@@ -78,13 +80,13 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
|
78
80
|
)).filter(exists);
|
|
79
81
|
const indexes = indexableData.map(
|
|
80
82
|
([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {
|
|
81
|
-
var _a
|
|
83
|
+
var _a;
|
|
82
84
|
const { sourceUrl: url } = thumbnailPayload;
|
|
83
85
|
const { timestamp } = timestampPayload;
|
|
84
86
|
const status = (_a = thumbnailPayload.http) == null ? void 0 : _a.status;
|
|
85
|
-
const success =
|
|
87
|
+
const success = !!thumbnailPayload.url;
|
|
86
88
|
const sources = [boundWitnessHash, thumbnailHash, timestampHash];
|
|
87
|
-
const fields =
|
|
89
|
+
const fields = { sources, status, success, timestamp, url };
|
|
88
90
|
const result = new PayloadBuilder({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build();
|
|
89
91
|
return result;
|
|
90
92
|
}
|
|
@@ -117,11 +119,8 @@ var ImageThumbnailDiviner = class extends AbstractDiviner {
|
|
|
117
119
|
const order = payloadOrder ?? "desc";
|
|
118
120
|
const offset = payloadOffset ?? 0;
|
|
119
121
|
const success = payloadSuccess;
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
fields.status = payloadStatus ?? 200;
|
|
123
|
-
if (success === true && payloadStatus !== void 0)
|
|
124
|
-
fields.status = payloadStatus;
|
|
122
|
+
const status = payloadStatus;
|
|
123
|
+
const fields = { ...{ limit, offset, order, status, success, url } };
|
|
125
124
|
const query = new PayloadBuilder({ schema: PayloadDivinerQuerySchema }).fields(fields).build();
|
|
126
125
|
return await diviner.divine([query]);
|
|
127
126
|
})
|
package/dist/node/index.mjs.map
CHANGED
|
@@ -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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\n const batch = await boundWitnessDiviner.divine([query])\n if (batch.length === 0) return\n // Find all the indexable hashes in this batch\n type IndexableHashes = Readonly<[boundWitnessHash: string, imageThumbnailHash: string, timestampHash: string]>\n const indexableHashes: IndexableHashes[] = (\n await Promise.all(\n batch.filter(isBoundWitness).map(async (bw) => {\n const imageThumbnailIndexes = bw.payload_schemas\n ?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined))\n .filter(exists)\n const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)\n if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined\n const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)\n const timestampHash = bw.payload_hashes?.[timestampIndex]\n const boundWitnessHash = await PayloadHasher.hashAsync(bw)\n return imageThumbnails.map((imageThumbnailHash) => [boundWitnessHash, imageThumbnailHash, timestampHash] as const)\n }),\n )\n )\n .flat()\n .filter(exists)\n const archivist = await this.getArchivistForStore('thumbnailStore')\n // Find all the indexable data associated with the indexable hashes\n type IndexableData = Readonly<\n [\n boundWitnessHash: string,\n imageThumbnailHash: string,\n imageThumbnailPayload: ImageThumbnail,\n timestampHash: string,\n timestampPayload: TimeStamp,\n ]\n >\n const indexableData: IndexableData[] = (\n await Promise.all(\n indexableHashes.map(async ([boundWitnessHash, imageThumbnailHash, timestampHash]) => {\n const results = await archivist.get([imageThumbnailHash, timestampHash])\n const imageThumbnailPayload = results.find(isImageThumbnail)\n const timestampPayload = results.find(isTimestamp)\n if (!imageThumbnailPayload || !timestampPayload) return undefined\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n const success = thumbnailPayload.http?.status ? true : false\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = status ? { sources, status, success, timestamp, url } : { sources, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const fields: Partial<ImageThumbnailResultQuery> = { limit, offset, order, success, url }\n // Default to filtering on 200 status code if success was not supplied\n if (payloadSuccess === true) fields.status = payloadStatus ?? 200\n // If success is true and status was supplied, use it\n if (success === true && payloadStatus !== undefined) fields.status = payloadStatus\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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 { ArchivistWrapper } from '@xyo-network/archivist-wrapper'\nimport { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { PayloadHasher } from '@xyo-network/core'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport { DivinerConfigSchema } from '@xyo-network/diviner-model'\nimport { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'\nimport { DivinerWrapper } from '@xyo-network/diviner-wrapper'\nimport {\n ImageThumbnail,\n ImageThumbnailDivinerConfig,\n ImageThumbnailDivinerConfigSchema,\n ImageThumbnailDivinerParams,\n ImageThumbnailResult,\n ImageThumbnailResultIndexSchema,\n ImageThumbnailResultInfo,\n ImageThumbnailSchema,\n isImageThumbnail,\n isImageThumbnailDivinerQuery,\n isImageThumbnailResult,\n} from '@xyo-network/image-thumbnail-payload-plugin'\nimport { isModuleState, ModuleState, ModuleStateSchema, StateDictionary } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport { isTimestamp, TimeStamp, TimestampSchema } from '@xyo-network/witness-timestamp'\n\nexport type ImageThumbnailDivinerState = StateDictionary & {\n offset: number\n}\n\ntype ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'\n\ntype ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>\n\n/**\n * The fields that will need to be indexed on in the underlying store\n */\ntype QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResultInfo, 'status' | 'success' | 'timestamp' | 'url'>\n\n/**\n * The query that will be used to retrieve the results from the underlying store\n */\ntype ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<\n ImageThumbnailResult,\n QueryableImageThumbnailResultProperties\n >\n\nconst moduleName = 'ImageThumbnailDiviner'\n\nexport class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {\n static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]\n\n private _pollId?: string | number | NodeJS.Timeout\n\n get payloadDivinerLimit() {\n return this.config.payloadDivinerLimit ?? 1_0000\n }\n\n get pollFrequency() {\n return this.config.pollFrequency ?? 10_000\n }\n\n /**\n * Works in the background to populate index for the Diviner\n * @returns\n */\n protected backgroundDivine = async (): Promise<void> => {\n // Load last state\n const lastState = (await this.retrieveState()) ?? { offset: 0 }\n const { offset } = lastState\n // Get next batch of results\n const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')\n const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })\n .fields({\n limit: this.payloadDivinerLimit,\n offset,\n order: 'asc',\n payload_schemas: [ImageThumbnailSchema, TimestampSchema],\n })\n .build()\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) {\n console.log('Could not find payload from hash to index')\n return undefined\n }\n const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)\n const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)\n if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined\n return [boundWitnessHash, imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const\n }),\n )\n ).filter(exists)\n // Build index results from the indexable data\n const indexes: ImageThumbnailResult[] = indexableData.map(\n ([boundWitnessHash, thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {\n const { sourceUrl: url } = thumbnailPayload\n const { timestamp } = timestampPayload\n const status = thumbnailPayload.http?.status\n //call anything with a thumbnail url a success\n const success = !!thumbnailPayload.url\n const sources = [boundWitnessHash, thumbnailHash, timestampHash]\n const fields = { sources, status, success, timestamp, url }\n const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()\n return result\n },\n )\n // Insert index results\n const indexArchivist = await this.getArchivistForStore('indexStore')\n await indexArchivist.insert(indexes)\n // Update state\n const nextOffset = offset + batch.length\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = new PayloadBuilder<ModuleState<ImageThumbnailDivinerState>>({ schema: ModuleStateSchema }).fields({ state }).build()\n const [bw] = await new BoundWitnessBuilder().payloads([payload]).witness(this.account).build()\n await archivist.insert([bw, payload])\n }\n\n protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {\n const urls = payloads.filter(isImageThumbnailDivinerQuery)\n const diviner = await this.getPayloadDivinerForStore('indexStore')\n const results = (\n await Promise.all(\n urls.map(async (payload) => {\n const { limit: payloadLimit, offset: payloadOffset, order: payloadOrder, status: payloadStatus, success: payloadSuccess, url } = payload\n const limit = payloadLimit ?? 1\n const order = payloadOrder ?? 'desc'\n const offset = payloadOffset ?? 0\n const success = payloadSuccess\n const status = payloadStatus\n const fields: Partial<ImageThumbnailResultQuery> = { ...{ limit, offset, order, status, success, url } }\n const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()\n return await diviner.divine([query])\n }),\n )\n )\n .flat()\n .filter(isImageThumbnailResult)\n return results\n }\n\n protected async getArchivistForStore(store: ConfigStore) {\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 ArchivistWrapper.wrap(mod, this.account)\n }\n\n protected async getBoundWitnessDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\n }\n\n protected async getPayloadDivinerForStore(store: ConfigStore) {\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 DivinerWrapper.wrap(mod, this.account)\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 })\n .fields({\n address: this.account.address,\n limit: 1,\n offset: 0,\n order: 'desc',\n payload_schemas: [ModuleStateSchema],\n })\n .build()\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 archivist = await this.getArchivistForStore('stateStore')\n const payload = (await archivist.get([hash])).find(isModuleState)\n if (payload) {\n return payload.state as ImageThumbnailDivinerState\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":[]}
|
package/package.json
CHANGED
|
@@ -12,30 +12,30 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@xylabs/assert": "^2.12.30",
|
|
14
14
|
"@xylabs/exists": "^2.12.30",
|
|
15
|
-
"@xyo-network/abstract-diviner": "~2.77.
|
|
16
|
-
"@xyo-network/archivist-wrapper": "~2.77.
|
|
17
|
-
"@xyo-network/boundwitness-model": "~2.77.
|
|
18
|
-
"@xyo-network/core": "~2.77.
|
|
19
|
-
"@xyo-network/diviner-boundwitness-model": "~2.77.
|
|
20
|
-
"@xyo-network/diviner-model": "~2.77.
|
|
21
|
-
"@xyo-network/diviner-payload-model": "~2.77.
|
|
22
|
-
"@xyo-network/diviner-wrapper": "~2.77.
|
|
23
|
-
"@xyo-network/image-thumbnail-payload-plugin": "~2.77.
|
|
24
|
-
"@xyo-network/module-model": "~2.77.
|
|
25
|
-
"@xyo-network/payload-builder": "~2.77.
|
|
26
|
-
"@xyo-network/payload-model": "~2.77.
|
|
27
|
-
"@xyo-network/witness-timestamp": "~2.77.
|
|
15
|
+
"@xyo-network/abstract-diviner": "~2.77.4",
|
|
16
|
+
"@xyo-network/archivist-wrapper": "~2.77.4",
|
|
17
|
+
"@xyo-network/boundwitness-model": "~2.77.4",
|
|
18
|
+
"@xyo-network/core": "~2.77.4",
|
|
19
|
+
"@xyo-network/diviner-boundwitness-model": "~2.77.4",
|
|
20
|
+
"@xyo-network/diviner-model": "~2.77.4",
|
|
21
|
+
"@xyo-network/diviner-payload-model": "~2.77.4",
|
|
22
|
+
"@xyo-network/diviner-wrapper": "~2.77.4",
|
|
23
|
+
"@xyo-network/image-thumbnail-payload-plugin": "~2.77.4",
|
|
24
|
+
"@xyo-network/module-model": "~2.77.4",
|
|
25
|
+
"@xyo-network/payload-builder": "~2.77.4",
|
|
26
|
+
"@xyo-network/payload-model": "~2.77.4",
|
|
27
|
+
"@xyo-network/witness-timestamp": "~2.77.4"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@xylabs/delay": "^2.12.30",
|
|
31
31
|
"@xylabs/ts-scripts-yarn3": "^3.1.12",
|
|
32
32
|
"@xylabs/tsconfig": "^3.1.12",
|
|
33
|
-
"@xyo-network/account": "~2.77.
|
|
34
|
-
"@xyo-network/boundwitness-builder": "~2.77.
|
|
35
|
-
"@xyo-network/diviner-boundwitness-memory": "~2.77.
|
|
36
|
-
"@xyo-network/diviner-payload-memory": "~2.77.
|
|
37
|
-
"@xyo-network/memory-archivist": "~2.77.
|
|
38
|
-
"@xyo-network/node-memory": "~2.77.
|
|
33
|
+
"@xyo-network/account": "~2.77.4",
|
|
34
|
+
"@xyo-network/boundwitness-builder": "~2.77.4",
|
|
35
|
+
"@xyo-network/diviner-boundwitness-memory": "~2.77.4",
|
|
36
|
+
"@xyo-network/diviner-payload-memory": "~2.77.4",
|
|
37
|
+
"@xyo-network/memory-archivist": "~2.77.4",
|
|
38
|
+
"@xyo-network/node-memory": "~2.77.4",
|
|
39
39
|
"typescript": "^5.2.2"
|
|
40
40
|
},
|
|
41
41
|
"description": "Primary SDK for using XYO Protocol 2.0",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js.git"
|
|
79
79
|
},
|
|
80
80
|
"sideEffects": false,
|
|
81
|
-
"version": "2.77.
|
|
81
|
+
"version": "2.77.4"
|
|
82
82
|
}
|
package/src/Diviner/Diviner.ts
CHANGED
|
@@ -119,7 +119,10 @@ export class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams =
|
|
|
119
119
|
const results = await archivist.get([imageThumbnailHash, timestampHash])
|
|
120
120
|
const imageThumbnailPayload = results.find(isImageThumbnail)
|
|
121
121
|
const timestampPayload = results.find(isTimestamp)
|
|
122
|
-
if (!imageThumbnailPayload || !timestampPayload)
|
|
122
|
+
if (!imageThumbnailPayload || !timestampPayload) {
|
|
123
|
+
console.log('Could not find payload from hash to index')
|
|
124
|
+
return undefined
|
|
125
|
+
}
|
|
123
126
|
const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)
|
|
124
127
|
const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)
|
|
125
128
|
if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined
|
|
@@ -133,9 +136,10 @@ export class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams =
|
|
|
133
136
|
const { sourceUrl: url } = thumbnailPayload
|
|
134
137
|
const { timestamp } = timestampPayload
|
|
135
138
|
const status = thumbnailPayload.http?.status
|
|
136
|
-
|
|
139
|
+
//call anything with a thumbnail url a success
|
|
140
|
+
const success = !!thumbnailPayload.url
|
|
137
141
|
const sources = [boundWitnessHash, thumbnailHash, timestampHash]
|
|
138
|
-
const fields =
|
|
142
|
+
const fields = { sources, status, success, timestamp, url }
|
|
139
143
|
const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema }).fields(fields).build()
|
|
140
144
|
return result
|
|
141
145
|
},
|
|
@@ -173,11 +177,8 @@ export class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams =
|
|
|
173
177
|
const order = payloadOrder ?? 'desc'
|
|
174
178
|
const offset = payloadOffset ?? 0
|
|
175
179
|
const success = payloadSuccess
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
if (payloadSuccess === true) fields.status = payloadStatus ?? 200
|
|
179
|
-
// If success is true and status was supplied, use it
|
|
180
|
-
if (success === true && payloadStatus !== undefined) fields.status = payloadStatus
|
|
180
|
+
const status = payloadStatus
|
|
181
|
+
const fields: Partial<ImageThumbnailResultQuery> = { ...{ limit, offset, order, status, success, url } }
|
|
181
182
|
const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema }).fields(fields).build()
|
|
182
183
|
return await diviner.divine([query])
|
|
183
184
|
}),
|