@xyo-network/image-thumbnail-plugin 2.75.8 → 2.75.11

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.
Files changed (83) hide show
  1. package/dist/docs.json +17210 -7942
  2. package/dist/node/Plugin.d.cts +4 -4
  3. package/dist/node/Plugin.d.cts.map +1 -1
  4. package/dist/node/Plugin.d.mts +4 -4
  5. package/dist/node/Plugin.d.mts.map +1 -1
  6. package/dist/node/Plugin.d.ts +4 -4
  7. package/dist/node/Plugin.d.ts.map +1 -1
  8. package/dist/node/Plugin.js +27 -256
  9. package/dist/node/Plugin.js.map +1 -1
  10. package/dist/node/Plugin.mjs +21 -250
  11. package/dist/node/Plugin.mjs.map +1 -1
  12. package/dist/node/Witness/Witness.d.cts +0 -25
  13. package/dist/node/Witness/Witness.d.cts.map +1 -1
  14. package/dist/node/Witness/Witness.d.mts +0 -25
  15. package/dist/node/Witness/Witness.d.mts.map +1 -1
  16. package/dist/node/Witness/Witness.d.ts +0 -25
  17. package/dist/node/Witness/Witness.d.ts.map +1 -1
  18. package/dist/node/Witness/Witness.js +7 -30
  19. package/dist/node/Witness/Witness.js.map +1 -1
  20. package/dist/node/Witness/Witness.mjs +7 -30
  21. package/dist/node/Witness/Witness.mjs.map +1 -1
  22. package/dist/node/Witness/index.js +7 -30
  23. package/dist/node/Witness/index.js.map +1 -1
  24. package/dist/node/Witness/index.mjs +7 -30
  25. package/dist/node/Witness/index.mjs.map +1 -1
  26. package/dist/node/index.d.cts +1 -1
  27. package/dist/node/index.d.cts.map +1 -1
  28. package/dist/node/index.d.mts +1 -1
  29. package/dist/node/index.d.mts.map +1 -1
  30. package/dist/node/index.d.ts +1 -1
  31. package/dist/node/index.d.ts.map +1 -1
  32. package/dist/node/index.js +31 -261
  33. package/dist/node/index.js.map +1 -1
  34. package/dist/node/index.mjs +22 -252
  35. package/dist/node/index.mjs.map +1 -1
  36. package/package.json +19 -24
  37. package/src/Plugin.ts +1 -1
  38. package/src/Witness/Witness.ts +5 -30
  39. package/src/index.ts +1 -1
  40. package/dist/node/Diviner/Config.d.cts +0 -34
  41. package/dist/node/Diviner/Config.d.cts.map +0 -1
  42. package/dist/node/Diviner/Config.d.mts +0 -34
  43. package/dist/node/Diviner/Config.d.mts.map +0 -1
  44. package/dist/node/Diviner/Config.d.ts +0 -34
  45. package/dist/node/Diviner/Config.d.ts.map +0 -1
  46. package/dist/node/Diviner/Config.js +0 -32
  47. package/dist/node/Diviner/Config.js.map +0 -1
  48. package/dist/node/Diviner/Config.mjs +0 -7
  49. package/dist/node/Diviner/Config.mjs.map +0 -1
  50. package/dist/node/Diviner/Diviner.d.cts +0 -48
  51. package/dist/node/Diviner/Diviner.d.cts.map +0 -1
  52. package/dist/node/Diviner/Diviner.d.mts +0 -48
  53. package/dist/node/Diviner/Diviner.d.mts.map +0 -1
  54. package/dist/node/Diviner/Diviner.d.ts +0 -48
  55. package/dist/node/Diviner/Diviner.d.ts.map +0 -1
  56. package/dist/node/Diviner/Diviner.js +0 -237
  57. package/dist/node/Diviner/Diviner.js.map +0 -1
  58. package/dist/node/Diviner/Diviner.mjs +0 -212
  59. package/dist/node/Diviner/Diviner.mjs.map +0 -1
  60. package/dist/node/Diviner/Params.d.cts +0 -5
  61. package/dist/node/Diviner/Params.d.cts.map +0 -1
  62. package/dist/node/Diviner/Params.d.mts +0 -5
  63. package/dist/node/Diviner/Params.d.mts.map +0 -1
  64. package/dist/node/Diviner/Params.d.ts +0 -5
  65. package/dist/node/Diviner/Params.d.ts.map +0 -1
  66. package/dist/node/Diviner/Params.js +0 -19
  67. package/dist/node/Diviner/Params.js.map +0 -1
  68. package/dist/node/Diviner/Params.mjs +0 -1
  69. package/dist/node/Diviner/Params.mjs.map +0 -1
  70. package/dist/node/Diviner/index.d.cts +0 -4
  71. package/dist/node/Diviner/index.d.cts.map +0 -1
  72. package/dist/node/Diviner/index.d.mts +0 -4
  73. package/dist/node/Diviner/index.d.mts.map +0 -1
  74. package/dist/node/Diviner/index.d.ts +0 -4
  75. package/dist/node/Diviner/index.d.ts.map +0 -1
  76. package/dist/node/Diviner/index.js +0 -239
  77. package/dist/node/Diviner/index.js.map +0 -1
  78. package/dist/node/Diviner/index.mjs +0 -211
  79. package/dist/node/Diviner/index.mjs.map +0 -1
  80. package/src/Diviner/Config.ts +0 -37
  81. package/src/Diviner/Diviner.ts +0 -280
  82. package/src/Diviner/Params.ts +0 -6
  83. package/src/Diviner/index.ts +0 -3
@@ -1,280 +0,0 @@
1
- import { assertEx } from '@xylabs/assert'
2
- import { exists } from '@xylabs/exists'
3
- import { AbstractDiviner } from '@xyo-network/abstract-diviner'
4
- import { asArchivistInstance, withArchivistModule } from '@xyo-network/archivist-model'
5
- import { ArchivistWrapper } from '@xyo-network/archivist-wrapper'
6
- import { isBoundWitness } from '@xyo-network/boundwitness-model'
7
- import { PayloadHasher } from '@xyo-network/core'
8
- import { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
9
- import { asDivinerInstance, DivinerConfigSchema } from '@xyo-network/diviner-model'
10
- import { PayloadDivinerQueryPayload, PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'
11
- import { DivinerWrapper } from '@xyo-network/diviner-wrapper'
12
- import { ImageThumbnailSchema, isImageThumbnail } from '@xyo-network/image-thumbnail-payload-plugin'
13
- import { PayloadBuilder } from '@xyo-network/payload-builder'
14
- import { isPayloadOfSchemaType, Payload } from '@xyo-network/payload-model'
15
- import { isUrlPayload } from '@xyo-network/url-payload-plugin'
16
- import { isTimestamp, TimestampSchema } from '@xyo-network/witness-timestamp'
17
-
18
- import { ImageThumbnailDivinerConfig, ImageThumbnailDivinerConfigSchema } from './Config'
19
- import { ImageThumbnailDivinerParams } from './Params'
20
-
21
- /**
22
- * TODO: Once the shape settles, make a generic payload so that it
23
- * can be used for other modules
24
- */
25
- interface State<T> {
26
- state: T
27
- }
28
-
29
- interface ImageThumbnailDivinerState {
30
- offset: number
31
- }
32
-
33
- const ModuleStateSchema = 'network.xyo.module.state' as const
34
- type ModuleStateSchema = typeof ModuleStateSchema
35
-
36
- type ModuleState = Payload<State<ImageThumbnailDivinerState>, ModuleStateSchema>
37
-
38
- const isModuleState = isPayloadOfSchemaType<ModuleState>(ModuleStateSchema)
39
-
40
- type ConfigStoreKey = 'indexStore' | 'stateStore' | 'thumbnailStore'
41
-
42
- type ConfigStore = Extract<keyof ImageThumbnailDivinerConfig, ConfigStoreKey>
43
-
44
- const ImageThumbnailResultIndexSchema = `${ImageThumbnailSchema}.index` as const
45
- type ImageThumbnailResultIndexSchema = typeof ImageThumbnailResultIndexSchema
46
-
47
- interface ImageThumbnailResultInfo {
48
- sources: string[]
49
- // TODO: Something richer than HTTP status code that allows for info about failure modes
50
- status: number
51
- timestamp: number
52
- url: string
53
- }
54
-
55
- type ImageThumbnailResult = Payload<ImageThumbnailResultInfo, ImageThumbnailResultIndexSchema>
56
-
57
- const isImageThumbnailResult = isPayloadOfSchemaType<ImageThumbnailResult>(ImageThumbnailResultIndexSchema)
58
-
59
- /**
60
- * The fields that will need to be indexed on in the underlying store
61
- */
62
- type QueryableImageThumbnailResultProperties = Extract<keyof ImageThumbnailResult, 'url' | 'timestamp' | 'status'>
63
-
64
- /**
65
- * The query that will be used to retrieve the results from the underlying store
66
- */
67
- type ImageThumbnailResultQuery = PayloadDivinerQueryPayload & { schemas: [ImageThumbnailSchema] } & Pick<
68
- ImageThumbnailResult,
69
- QueryableImageThumbnailResultProperties
70
- >
71
-
72
- const moduleName = 'ImageThumbnailDiviner'
73
-
74
- export class ImageThumbnailDiviner<TParams extends ImageThumbnailDivinerParams = ImageThumbnailDivinerParams> extends AbstractDiviner<TParams> {
75
- static override configSchemas = [ImageThumbnailDivinerConfigSchema, DivinerConfigSchema]
76
-
77
- private _pollId?: string | number | NodeJS.Timeout
78
-
79
- get payloadDivinerLimit() {
80
- return this.config.payloadDivinerLimit ?? 1_0000
81
- }
82
-
83
- get pollFrequency() {
84
- return this.config.pollFrequency ?? 10_000
85
- }
86
-
87
- protected backgroundDivine = async (): Promise<void> => {
88
- // Load last state
89
- const lastState = (await this.retrieveState()) ?? { offset: 0 }
90
- const { offset } = lastState
91
- // Get next batch of results
92
- const boundWitnessDiviner = await this.getBoundWitnessDivinerForStore('thumbnailStore')
93
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({
94
- limit: this.payloadDivinerLimit,
95
- offset,
96
- order: 'asc',
97
- payload_schemas: [ImageThumbnailSchema, TimestampSchema],
98
- })
99
- const batch = await boundWitnessDiviner.divine([query])
100
- if (batch.length === 0) return
101
- const imageThumbnailTimestampTuples = batch
102
- .filter(isBoundWitness)
103
- .map((bw) => {
104
- const imageThumbnailIndexes = bw.payload_schemas?.map((schema, index) => (schema === ImageThumbnailSchema ? index : undefined)).filter(exists)
105
- const timestampIndex = bw.payload_schemas?.findIndex((schema) => schema === TimestampSchema)
106
- if (!imageThumbnailIndexes.length || timestampIndex === -1) return undefined
107
- const imageThumbnails = bw.payload_hashes.map((hash, index) => (imageThumbnailIndexes.includes(index) ? hash : undefined)).filter(exists)
108
- const timestamp = bw.payload_hashes?.[timestampIndex]
109
- return imageThumbnails.map((imageThumbnail) => [imageThumbnail, timestamp] as const)
110
- })
111
- .flat()
112
- .filter(exists)
113
- const archivist = await this.getArchivistForStore('thumbnailStore')
114
- const payloadTuples = (
115
- await Promise.all(
116
- imageThumbnailTimestampTuples.map(async ([imageThumbnailHash, timestampHash]) => {
117
- const results = await archivist.get([imageThumbnailHash, timestampHash])
118
- const imageThumbnailPayload = results.find(isImageThumbnail)
119
- const timestampPayload = results.find(isTimestamp)
120
- if (!imageThumbnailPayload || !timestampPayload) return undefined
121
- const calculatedImageThumbnailHash = await PayloadHasher.hashAsync(imageThumbnailPayload)
122
- const calculatedTimestampHash = await PayloadHasher.hashAsync(timestampPayload)
123
- if (imageThumbnailHash !== calculatedImageThumbnailHash || timestampHash !== calculatedTimestampHash) return undefined
124
- return [imageThumbnailHash, imageThumbnailPayload, timestampHash, timestampPayload] as const
125
- }),
126
- )
127
- ).filter(exists)
128
- // Build index results
129
- const indexedResults = payloadTuples.map(([thumbnailHash, thumbnailPayload, timestampHash, timestampPayload]) => {
130
- const { sourceUrl: url } = thumbnailPayload
131
- const { timestamp } = timestampPayload
132
- const status = thumbnailPayload.http?.status ?? -1
133
- const sources = [thumbnailHash, timestampHash]
134
- const result = new PayloadBuilder<ImageThumbnailResult>({ schema: ImageThumbnailResultIndexSchema })
135
- .fields({ sources, status, timestamp, url })
136
- .build()
137
- return result
138
- })
139
- // Insert index results
140
- const indexArchivist = await this.getArchivistForStore('indexStore')
141
- await indexArchivist.insert(indexedResults)
142
- // Update state
143
- const nextOffset = offset + batch.length + 1
144
- const currentState = { ...lastState, offset: nextOffset }
145
- await this.commitState(currentState)
146
- }
147
-
148
- /**
149
- * Commit the internal state of the Diviner process. This is similar
150
- * to a transaction completion in a database and should only be called
151
- * when results have been successfully persisted to the appropriate
152
- * external stores.
153
- */
154
- protected async commitState(state: ImageThumbnailDivinerState) {
155
- const stateStore = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore configured`)
156
- const module = assertEx(await this.resolve(stateStore), `${moduleName}: Failed to resolve stateStore`)
157
- await withArchivistModule(module, async (archivist) => {
158
- const mod = ArchivistWrapper.wrap(archivist, this.account)
159
- const payload = new PayloadBuilder<ModuleState>({ schema: ModuleStateSchema }).fields({ state }).build()
160
- await mod.insert([payload])
161
- })
162
- }
163
-
164
- protected override async divineHandler(payloads: Payload[] = []): Promise<ImageThumbnailResult[]> {
165
- const urls = payloads.filter(isUrlPayload).map((urlPayload) => urlPayload.url)
166
- const diviner = await this.getPayloadDivinerForStore('indexStore')
167
- const results = (
168
- await Promise.all(
169
- urls.map(async (url) => {
170
- const query = new PayloadBuilder<ImageThumbnailResultQuery>({ schema: PayloadDivinerQuerySchema })
171
- // TODO: Expose status, limit (and possibly offset) to caller. Currently only exposing URL
172
- .fields({ limit: 1, offset: 0, order: 'desc', url })
173
- .build()
174
- return await diviner.divine([query])
175
- }),
176
- )
177
- )
178
- .flat()
179
- .filter(isImageThumbnailResult)
180
- return results
181
- }
182
-
183
- protected async getArchivistForStore(store: ConfigStore, wrap?: boolean) {
184
- const name = assertEx(this.config?.[store]?.archivist, () => `${moduleName}: Config for ${store}.archivist not specified`)
185
- const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.archivist`)
186
- return wrap ? ArchivistWrapper.wrap(mod, this.account) : asArchivistInstance(mod, () => `${moduleName}: ${store}.archivist is not an Archivist`)
187
- }
188
-
189
- protected async getBoundWitnessDivinerForStore(store: ConfigStore, wrap?: boolean) {
190
- const name = assertEx(this.config?.[store]?.boundWitnessDiviner, () => `${moduleName}: Config for ${store}.boundWitnessDiviner not specified`)
191
- const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.boundWitnessDiviner`)
192
- return wrap
193
- ? DivinerWrapper.wrap(mod, this.account)
194
- : asDivinerInstance(mod, () => `${moduleName}: ${store}.boundWitnessDiviner is not a Diviner`)
195
- }
196
-
197
- protected async getPayloadDivinerForStore(store: ConfigStore, wrap?: boolean) {
198
- const name = assertEx(this.config?.[store]?.payloadDiviner, () => `${moduleName}: Config for ${store}.payloadDiviner not specified`)
199
- const mod = assertEx(await this.resolve(name), () => `${moduleName}: Failed to resolve ${store}.payloadDiviner`)
200
- return wrap ? DivinerWrapper.wrap(mod, this.account) : asDivinerInstance(mod, () => `${moduleName}: ${store}.payloadDiviner is not a Diviner`)
201
- }
202
-
203
- /**
204
- * Retrieves the last state of the Diviner process. Used to recover state after
205
- * preemptions, reboots, etc.
206
- */
207
- protected async retrieveState(): Promise<ImageThumbnailDivinerState | undefined> {
208
- let hash: string = ''
209
- const diviner = await this.getBoundWitnessDivinerForStore('stateStore')
210
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).fields({
211
- address: this.account.address,
212
- limit: 1,
213
- offset: 0,
214
- order: 'desc',
215
- payload_schemas: [ModuleStateSchema],
216
- })
217
- const boundWitnesses = await diviner.divine([query])
218
- if (boundWitnesses.length > 0) {
219
- const boundWitness = boundWitnesses[0]
220
- if (isBoundWitness(boundWitness)) {
221
- // Find the index for this address in the BoundWitness that is a ModuleState
222
- hash = boundWitness.addresses
223
- .map((address, index) => ({ address, index }))
224
- .filter(({ address }) => address === this.account.address)
225
- .reduce(
226
- (prev, curr) => (boundWitness.payload_schemas?.[curr?.index] === ModuleStateSchema ? boundWitness.payload_hashes[curr?.index] : prev),
227
- '',
228
- )
229
- }
230
- }
231
-
232
- // If we able to located the last state
233
- if (hash) {
234
- // Get last state
235
- const stateStoreArchivist = assertEx(this.config.stateStore?.archivist, `${moduleName}: No stateStore archivist configured`)
236
- await withArchivistModule(
237
- assertEx(await this.resolve(stateStoreArchivist), `${moduleName}: Failed to resolve stateStore archivist`),
238
- async (mod) => {
239
- const archivist = ArchivistWrapper.wrap(mod, this.account)
240
- const payloads = await archivist.get([hash])
241
- if (payloads.length > 0) {
242
- const payload = payloads[0]
243
- if (isModuleState(payload)) {
244
- return payload.state
245
- }
246
- }
247
- },
248
- )
249
- }
250
- return undefined
251
- }
252
-
253
- protected override async startHandler(): Promise<boolean> {
254
- await super.startHandler()
255
- this.poll()
256
- return true
257
- }
258
-
259
- protected override async stopHandler(_timeout?: number | undefined): Promise<boolean> {
260
- if (this._pollId) {
261
- clearTimeout(this._pollId)
262
- this._pollId = undefined
263
- }
264
- return await super.stopHandler()
265
- }
266
-
267
- private poll() {
268
- this._pollId = setTimeout(async () => {
269
- try {
270
- await this.backgroundDivine()
271
- } catch (e) {
272
- console.log(e)
273
- } finally {
274
- if (this._pollId) clearTimeout(this._pollId)
275
- this._pollId = undefined
276
- this.poll()
277
- }
278
- }, this.pollFrequency)
279
- }
280
- }
@@ -1,6 +0,0 @@
1
- import { DivinerParams } from '@xyo-network/diviner-model'
2
- import { AnyConfigSchema } from '@xyo-network/module'
3
-
4
- import { ImageThumbnailDivinerConfig } from './Config'
5
-
6
- export type ImageThumbnailDivinerParams = DivinerParams<AnyConfigSchema<ImageThumbnailDivinerConfig>>
@@ -1,3 +0,0 @@
1
- export * from './Config'
2
- export * from './Diviner'
3
- export * from './Params'