@seedprotocol/sdk 0.7.3-next.613.g79a8dfd → 0.7.3-next.654.g52217f6
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/{BasePathResolver-BdxCSIzn.js → BasePathResolver-CfSfMW5_.js} +7 -10
- package/dist/BasePathResolver-CfSfMW5_.js.map +1 -0
- package/dist/{ClientManager-DDA9956Y.js → ClientManager-C-QXqUK9.js} +438 -153
- package/dist/ClientManager-C-QXqUK9.js.map +1 -0
- package/dist/{Item-D4FigtYS.js → Item-C7sUUu2B.js} +291 -105
- package/dist/Item-C7sUUu2B.js.map +1 -0
- package/dist/{ModelProperty-BDt6AU2h.js → ModelProperty-DJxeOOrc.js} +28 -27
- package/dist/ModelProperty-DJxeOOrc.js.map +1 -0
- package/dist/{Schema-B8xqLWkL.js → Schema-fXtvd-yL.js} +30 -30
- package/dist/{Schema-B8xqLWkL.js.map → Schema-fXtvd-yL.js.map} +1 -1
- package/dist/{SchemaValidationService-BPxkfDLU.js → SchemaValidationService-CvRS2HSO.js} +10 -9
- package/dist/{SchemaValidationService-BPxkfDLU.js.map → SchemaValidationService-CvRS2HSO.js.map} +1 -1
- package/dist/{backfillMetadataPropertyIds-DuTPcv8t.js → backfillMetadataPropertyIds-SXW-8C64.js} +4 -4
- package/dist/{backfillMetadataPropertyIds-DuTPcv8t.js.map → backfillMetadataPropertyIds-SXW-8C64.js.map} +1 -1
- package/dist/cjs/{ModelProperty-B-cZm1yU.js → ModelProperty-DXZ39Wyv.js} +24 -23
- package/dist/cjs/{ModelProperty-B-cZm1yU.js.map → ModelProperty-DXZ39Wyv.js.map} +1 -1
- package/dist/cjs/{Schema-STP972Xw.js → Schema-DdP109QD.js} +26 -25
- package/dist/cjs/{Schema-STP972Xw.js.map → Schema-DdP109QD.js.map} +1 -1
- package/dist/cjs/{SchemaValidationService-CKNW1bKg.js → SchemaValidationService-CSXxx7sQ.js} +5 -4
- package/dist/cjs/{SchemaValidationService-CKNW1bKg.js.map → SchemaValidationService-CSXxx7sQ.js.map} +1 -1
- package/dist/cjs/{backfillMetadataPropertyIds-CP3y1skt.js → backfillMetadataPropertyIds-CPYoaMl4.js} +6 -5
- package/dist/cjs/{backfillMetadataPropertyIds-CP3y1skt.js.map → backfillMetadataPropertyIds-CPYoaMl4.js.map} +1 -1
- package/dist/cjs/{eas-CAnUC4wd.js → eas-B2YDQssV.js} +6 -5
- package/dist/cjs/{eas-CAnUC4wd.js.map → eas-B2YDQssV.js.map} +1 -1
- package/dist/cjs/{getItem-CWgb3e9G.js → getItem-DgnaQzbE.js} +5 -4
- package/dist/cjs/{getItem-CWgb3e9G.js.map → getItem-DgnaQzbE.js.map} +1 -1
- package/dist/cjs/{getPublishPayload-BsZWiJ03.js → getPublishPayload-CqlqRdot.js} +12 -11
- package/dist/cjs/{getPublishPayload-BsZWiJ03.js.map → getPublishPayload-CqlqRdot.js.map} +1 -1
- package/dist/cjs/getPublishUploads-DsXY9S4U.js +872 -0
- package/dist/cjs/getPublishUploads-DsXY9S4U.js.map +1 -0
- package/dist/cjs/{index-nA5PxBSs.js → index-BHaWOwNF.js} +6 -5
- package/dist/cjs/index-BHaWOwNF.js.map +1 -0
- package/dist/cjs/{index-usKaANAq.js → index-C4XlgCJ4.js} +1156 -526
- package/dist/cjs/index-C4XlgCJ4.js.map +1 -0
- package/dist/cjs/{property-xMwPhQ5N.js → property-fa0iju0J.js} +8 -7
- package/dist/cjs/{property-xMwPhQ5N.js.map → property-fa0iju0J.js.map} +1 -1
- package/dist/cjs/{publishDraftGraph-BRWlR1KO.js → publishDraftGraph-3ASwAlD7.js} +4 -4
- package/dist/cjs/{publishDraftGraph-BRWlR1KO.js.map → publishDraftGraph-3ASwAlD7.js.map} +1 -1
- package/dist/cjs/{resetAmbiguousLegacyItemData-8nfkj9rz.js → resetAmbiguousLegacyItemData-Bu_MBBYt.js} +5 -4
- package/dist/cjs/{resetAmbiguousLegacyItemData-8nfkj9rz.js.map → resetAmbiguousLegacyItemData-Bu_MBBYt.js.map} +1 -1
- package/dist/cjs/{resolveModelForSyncedSeed-kYRuDWYw.js → resolveModelForSyncedSeed-BANIiuFU.js} +2 -2
- package/dist/cjs/{resolveModelForSyncedSeed-kYRuDWYw.js.map → resolveModelForSyncedSeed-BANIiuFU.js.map} +1 -1
- package/dist/cjs/{syncDbWithEas-DqRhV8o2.js → syncDbWithEas-CrmxxmUW.js} +10 -9
- package/dist/cjs/{syncDbWithEas-DqRhV8o2.js.map → syncDbWithEas-CrmxxmUW.js.map} +1 -1
- package/dist/{configurePlatform-YcOiDQBZ.js → configurePlatform-BRw2j0ZN.js} +7 -4
- package/dist/{configurePlatform-YcOiDQBZ.js.map → configurePlatform-BRw2j0ZN.js.map} +1 -1
- package/dist/{db-CQt-gcAl.js → db-D9K_f5cF.js} +14 -14
- package/dist/{db-CQt-gcAl.js.map → db-D9K_f5cF.js.map} +1 -1
- package/dist/{eas-CpOD74Ke.js → eas-DHxfswCt.js} +8 -5
- package/dist/eas-DHxfswCt.js.map +1 -0
- package/dist/{getItem-B_OoFkd7.js → getItem-d6N_aM6S.js} +8 -5
- package/dist/{getItem-B_OoFkd7.js.map → getItem-d6N_aM6S.js.map} +1 -1
- package/dist/{getPublishPayload-Xl3sRkR-.js → getPublishPayload-BHrxVtzY.js} +16 -16
- package/dist/{getPublishPayload-Xl3sRkR-.js.map → getPublishPayload-BHrxVtzY.js.map} +1 -1
- package/dist/getPublishUploads-BEqRiKIS.js +657 -0
- package/dist/getPublishUploads-BEqRiKIS.js.map +1 -0
- package/dist/{index-BGt4_oPO.js → index-CiMEoGu3.js} +12 -11
- package/dist/index-CiMEoGu3.js.map +1 -0
- package/dist/{index-CSOQFAOn.js → index-DglvthOk.js} +2 -2
- package/dist/index-DglvthOk.js.map +1 -0
- package/dist/{index-Xl1_4Lmb.js → index-s15q14rm.js} +29 -29
- package/dist/{index-Xl1_4Lmb.js.map → index-s15q14rm.js.map} +1 -1
- package/dist/{index.browser-CjTe0vt1.js → index.browser-Cm06tP4X.js} +553 -165
- package/dist/index.browser-Cm06tP4X.js.map +1 -0
- package/dist/{index.node-Cfa7npS6.js → index.node-C30dmFgn.js} +5 -5
- package/dist/{index.node-Cfa7npS6.js.map → index.node-C30dmFgn.js.map} +1 -1
- package/dist/main.cjs +4 -3
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +32 -44
- package/dist/main.js.map +1 -1
- package/dist/mimeTypes-DHAHC4eZ.js +204 -0
- package/dist/mimeTypes-DHAHC4eZ.js.map +1 -0
- package/dist/node.js +13 -12
- package/dist/node.js.map +1 -1
- package/dist/platform.browser.js +9 -7
- package/dist/platform.browser.js.map +1 -1
- package/dist/platform.node.js +3 -3
- package/dist/{property-BrXkY1Rg.js → property-DhmmYAvQ.js} +12 -9
- package/dist/property-DhmmYAvQ.js.map +1 -0
- package/dist/{publishDraftGraph-X0Wr9txE.js → publishDraftGraph-yYP74WRt.js} +8 -8
- package/dist/{publishDraftGraph-X0Wr9txE.js.map → publishDraftGraph-yYP74WRt.js.map} +1 -1
- package/dist/{resetAmbiguousLegacyItemData-Ci6PM_vC.js → resetAmbiguousLegacyItemData-Bk0QyDW8.js} +2 -2
- package/dist/{resetAmbiguousLegacyItemData-Ci6PM_vC.js.map → resetAmbiguousLegacyItemData-Bk0QyDW8.js.map} +1 -1
- package/dist/{resolveModelForSyncedSeed-DFVdnYq8.js → resolveModelForSyncedSeed-8cAzvUFd.js} +2 -2
- package/dist/{resolveModelForSyncedSeed-DFVdnYq8.js.map → resolveModelForSyncedSeed-8cAzvUFd.js.map} +1 -1
- package/dist/src/Item/Item.d.ts +1 -1
- package/dist/src/Item/Item.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveItemStorage.d.ts.map +1 -1
- package/dist/src/browser/helpers/FileManager.d.ts +4 -1
- package/dist/src/browser/helpers/FileManager.d.ts.map +1 -1
- package/dist/src/browser/helpers/tolerantWebAccess.d.ts +79 -4
- package/dist/src/browser/helpers/tolerantWebAccess.d.ts.map +1 -1
- package/dist/src/browser/workers/FileDownloader.d.ts +19 -4
- package/dist/src/browser/workers/FileDownloader.d.ts.map +1 -1
- package/dist/src/browser/workers/filesDownload.d.ts.map +1 -1
- package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
- package/dist/src/db/migrateLegacyItemStorageRows.d.ts +57 -0
- package/dist/src/db/migrateLegacyItemStorageRows.d.ts.map +1 -0
- package/dist/src/db/read/getCompositeChildPaths.d.ts +13 -0
- package/dist/src/db/read/getCompositeChildPaths.d.ts.map +1 -0
- package/dist/src/db/read/getItems.d.ts.map +1 -1
- package/dist/src/db/read/getPublishUploads.d.ts +32 -3
- package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
- package/dist/src/db/read/summarizePublishWork.d.ts.map +1 -1
- package/dist/src/db/write/convertVerbatimItemStorageRow.d.ts +44 -0
- package/dist/src/db/write/convertVerbatimItemStorageRow.d.ts.map +1 -0
- package/dist/src/db/write/createNewItem.d.ts.map +1 -1
- package/dist/src/events/files/download.d.ts.map +1 -1
- package/dist/src/helpers/FileManager/BaseFileManager.d.ts +3 -3
- package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
- package/dist/src/helpers/FileManager/IFileManager.d.ts +25 -1
- package/dist/src/helpers/FileManager/IFileManager.d.ts.map +1 -1
- package/dist/src/helpers/arweaveContentTags.d.ts +33 -0
- package/dist/src/helpers/arweaveContentTags.d.ts.map +1 -0
- package/dist/src/helpers/compositeUpload.d.ts +28 -0
- package/dist/src/helpers/compositeUpload.d.ts.map +1 -0
- package/dist/src/helpers/itemStorageFile.d.ts +57 -0
- package/dist/src/helpers/itemStorageFile.d.ts.map +1 -0
- package/dist/src/helpers/mapWithConcurrency.d.ts +7 -0
- package/dist/src/helpers/mapWithConcurrency.d.ts.map +1 -0
- package/dist/src/helpers/mimeTypes.d.ts +43 -0
- package/dist/src/helpers/mimeTypes.d.ts.map +1 -0
- package/dist/src/helpers/ownership.d.ts +19 -3
- package/dist/src/helpers/ownership.d.ts.map +1 -1
- package/dist/src/helpers/storageDir.d.ts +16 -0
- package/dist/src/helpers/storageDir.d.ts.map +1 -0
- package/dist/src/helpers/tabCoordinator.d.ts +5 -1
- package/dist/src/helpers/tabCoordinator.d.ts.map +1 -1
- package/dist/src/helpers/tabEvents.d.ts +23 -2
- package/dist/src/helpers/tabEvents.d.ts.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/types/fileManager.d.ts +3 -14
- package/dist/src/types/fileManager.d.ts.map +1 -1
- package/dist/src/types/publish.d.ts +14 -0
- package/dist/src/types/publish.d.ts.map +1 -1
- package/dist/{syncDbWithEas-BU-jZ5bJ.js → syncDbWithEas--HUA9WNb.js} +15 -14
- package/dist/syncDbWithEas--HUA9WNb.js.map +1 -0
- package/dist/{tabEvents-BZJMY5uK.js → tabEvents-DguZpCCv.js} +294 -58
- package/dist/tabEvents-DguZpCCv.js.map +1 -0
- package/dist/tolerantWebAccess-BZYWt09Y.js +551 -0
- package/dist/tolerantWebAccess-BZYWt09Y.js.map +1 -0
- package/dist/{updateSeedRevokedAt-iLpzae1i.js → updateSeedRevokedAt-D_EG-q3b.js} +3 -3
- package/dist/{updateSeedRevokedAt-iLpzae1i.js.map → updateSeedRevokedAt-D_EG-q3b.js.map} +1 -1
- package/package.json +5 -5
- package/dist/BasePathResolver-BdxCSIzn.js.map +0 -1
- package/dist/ClientManager-DDA9956Y.js.map +0 -1
- package/dist/Item-D4FigtYS.js.map +0 -1
- package/dist/ModelProperty-BDt6AU2h.js.map +0 -1
- package/dist/cjs/getPublishUploads-BQr8aMVP.js +0 -495
- package/dist/cjs/getPublishUploads-BQr8aMVP.js.map +0 -1
- package/dist/cjs/index-nA5PxBSs.js.map +0 -1
- package/dist/cjs/index-usKaANAq.js.map +0 -1
- package/dist/eas-CpOD74Ke.js.map +0 -1
- package/dist/getPublishUploads-DHP01KgU.js +0 -484
- package/dist/getPublishUploads-DHP01KgU.js.map +0 -1
- package/dist/index-BGt4_oPO.js.map +0 -1
- package/dist/index-CSOQFAOn.js.map +0 -1
- package/dist/index.browser-CjTe0vt1.js.map +0 -1
- package/dist/property-BrXkY1Rg.js.map +0 -1
- package/dist/syncDbWithEas-BU-jZ5bJ.js.map +0 -1
- package/dist/tabEvents-BZJMY5uK.js.map +0 -1
- package/dist/tolerantWebAccess-BZ2RA_mb.js +0 -160
- package/dist/tolerantWebAccess-BZ2RA_mb.js.map +0 -1
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
|
-
import {
|
|
3
|
-
import { isEasAttestationExplorerUrl, BaseArweaveClient, ensureReadGatewaySelected, getArweaveReadBaseUrls } from '@seedprotocol/arweave';
|
|
2
|
+
import { B as BaseDb, m as metadata, t as BaseFileManager, a as appState, D as ImageSize, E as EAS_SEED_DATA_SYNCED_TO_DB_EVENT } from './BasePathResolver-CfSfMW5_.js';
|
|
3
|
+
import { isEasAttestationExplorerUrl, BaseArweaveClient, ensureReadGatewaySelected, getArweaveReadBaseUrls, getTransactionTagsByIds } from '@seedprotocol/arweave';
|
|
4
4
|
import { BaseQueryClient, BaseEasClient, GET_FILES_METADATA } from '@seedprotocol/eas';
|
|
5
5
|
import { waitFor } from 'xstate';
|
|
6
6
|
import 'pluralize';
|
|
7
|
-
import { t as getAllAddressesFromDb, m as eventEmitter } from './db-
|
|
8
|
-
import { and, eq,
|
|
7
|
+
import { n as normalizeDataType, t as getAllAddressesFromDb, m as eventEmitter } from './db-D9K_f5cF.js';
|
|
8
|
+
import { and, eq, isNotNull, inArray, or } from 'drizzle-orm';
|
|
9
9
|
import { customAlphabet } from 'nanoid';
|
|
10
10
|
import { alphanumeric } from 'nanoid-dictionary';
|
|
11
11
|
import '@seedprotocol/query';
|
|
12
|
+
import { sha256 } from '@noble/hashes/sha256';
|
|
13
|
+
import { sha3_256 } from '@noble/hashes/sha3';
|
|
14
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
12
15
|
import { throttle } from 'lodash-es';
|
|
13
16
|
|
|
14
17
|
/** Same rules as getCorrectId in helpers/index (avoid barrel circular import). */
|
|
@@ -409,6 +412,124 @@ const supportsOpfsFileDownloads = () => {
|
|
|
409
412
|
return isBrowser() || isElectronRenderer();
|
|
410
413
|
};
|
|
411
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Tag every Seed upload carries with the hex digest of its data. Producers: the SDK's
|
|
417
|
+
* `getPublishUploadData` / `getPublishUploads` (and through them both the L1 transaction path and
|
|
418
|
+
* the bundler / DataItem path in `@seedprotocol/publish`). Consumer: the files download
|
|
419
|
+
* (`events/files/download.ts` and the download worker), which verifies downloaded bytes against it
|
|
420
|
+
* and copies a verified value into `metadata.content_hash`.
|
|
421
|
+
*/
|
|
422
|
+
const CONTENT_SHA256_TAG = 'Content-SHA-256';
|
|
423
|
+
const CONTENT_TYPE_TAG = 'Content-Type';
|
|
424
|
+
/**
|
|
425
|
+
* Lowercase hex SHA-256 of `data`: the value of the {@link CONTENT_SHA256_TAG} tag.
|
|
426
|
+
*
|
|
427
|
+
* Uses @noble/hashes rather than WebCrypto so it also works outside secure contexts (WebCrypto's
|
|
428
|
+
* `crypto.subtle` is missing on plain-http origins); the digest is the same.
|
|
429
|
+
*
|
|
430
|
+
* In SDK 0.7.2 and earlier the L1 transaction path (`getPublishUploads`) wrote SHA3-256 under this tag name
|
|
431
|
+
* while the bundler path wrote SHA-256. Uploads from that path still carry SHA3-256 digests; use
|
|
432
|
+
* {@link contentSha256TagMatches} to check a tag value against bytes.
|
|
433
|
+
*/
|
|
434
|
+
const getContentSha256 = (data) => bytesToHex(sha256(data));
|
|
435
|
+
/**
|
|
436
|
+
* True when `tagValue` (a {@link CONTENT_SHA256_TAG} value read from Arweave) is the digest of
|
|
437
|
+
* `data`. Accepts SHA-256 and, for uploads made by SDK 0.7.2 and earlier through the L1 transaction path,
|
|
438
|
+
* SHA3-256.
|
|
439
|
+
*/
|
|
440
|
+
const contentSha256TagMatches = (data, tagValue) => {
|
|
441
|
+
const expected = tagValue.trim().toLowerCase();
|
|
442
|
+
if (!expected)
|
|
443
|
+
return false;
|
|
444
|
+
return getContentSha256(data) === expected || bytesToHex(sha3_256(data)) === expected;
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* Tags for one upload, in the order every upload uses: content hash, content type, then any
|
|
448
|
+
* configured extra tags (e.g. App-Name from `arweaveUploadTags`).
|
|
449
|
+
*/
|
|
450
|
+
const buildArweaveContentTags = (contentHash, contentType, extra) => {
|
|
451
|
+
const tags = [];
|
|
452
|
+
if (contentHash)
|
|
453
|
+
tags.push({ name: CONTENT_SHA256_TAG, value: contentHash });
|
|
454
|
+
if (contentType)
|
|
455
|
+
tags.push({ name: CONTENT_TYPE_TAG, value: contentType });
|
|
456
|
+
if (extra?.length)
|
|
457
|
+
tags.push(...extra);
|
|
458
|
+
return tags;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/** Subdirectory of the files root that holds a storage seed's file, by its data type. */
|
|
462
|
+
const getStorageSubdirForDataType = (dataType) => {
|
|
463
|
+
switch (normalizeDataType(dataType ?? undefined)) {
|
|
464
|
+
case 'Image':
|
|
465
|
+
return 'images';
|
|
466
|
+
case 'Html':
|
|
467
|
+
return 'html';
|
|
468
|
+
case 'Json':
|
|
469
|
+
return 'json';
|
|
470
|
+
case 'File':
|
|
471
|
+
default:
|
|
472
|
+
// Unknown types are generic files; `images/` is only for what the SDK knows is an image.
|
|
473
|
+
return 'files';
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
/** Absolute directory for a storage seed's file (`images/`, `files/`, `html/` or `json/` under the files root). */
|
|
477
|
+
const getStorageDirForDataType = (dataType) => BaseFileManager.getFilesPath(getStorageSubdirForDataType(dataType));
|
|
478
|
+
/**
|
|
479
|
+
* Subdirectory (relative to the files root, no leading slash) for an ItemStorage property's file:
|
|
480
|
+
* its model's `storage.path` (`localStorageDir`), else `files`.
|
|
481
|
+
*/
|
|
482
|
+
const getItemStorageSubdir = (localStorageDir) => (localStorageDir ?? '').replace(/^\/+/, '').replace(/\/+$/, '') || 'files';
|
|
483
|
+
/**
|
|
484
|
+
* File name a local save gives an ItemStorage property: `<seedUid or seedLocalId><extension>`
|
|
485
|
+
* (see saveItemStorage). Downloaded content is named after its transaction instead
|
|
486
|
+
* (`<txId><extension>`, see syncDbWithEas), which is what the metadata row's refResolvedValue says.
|
|
487
|
+
*/
|
|
488
|
+
const getItemStorageLocalFileName = (seedId, filenameSuffix) => `${seedId}${filenameSuffix ?? ''}`;
|
|
489
|
+
|
|
490
|
+
/** Rows per query: well under SQLite's bound-parameter limit. */
|
|
491
|
+
const CHUNK_SIZE = 400;
|
|
492
|
+
/**
|
|
493
|
+
* Where the download worker saves each child of a composite upload, by transaction id then child
|
|
494
|
+
* (property) name: a path relative to the files root.
|
|
495
|
+
*
|
|
496
|
+
* The paths come from the ItemStorage rows sync derives from a `storage_transaction_id`
|
|
497
|
+
* attestation (see `createMetadataRecordsForStorageTransactionId`): property value = the
|
|
498
|
+
* transaction id, `refResolvedValue` = `<txId><extension>`, `localStorageDir` = the model's storage
|
|
499
|
+
* directory. Those rows are what hydration reads, so a child saved here is found as that property's
|
|
500
|
+
* file. Transactions with no such rows are left out; the worker then falls back to the legacy
|
|
501
|
+
* html / json layout.
|
|
502
|
+
*/
|
|
503
|
+
const getCompositeChildPaths = async (transactionIds) => {
|
|
504
|
+
const out = {};
|
|
505
|
+
const appDb = BaseDb.getAppDb();
|
|
506
|
+
if (!appDb || transactionIds.length === 0)
|
|
507
|
+
return out;
|
|
508
|
+
for (let i = 0; i < transactionIds.length; i += CHUNK_SIZE) {
|
|
509
|
+
const chunk = transactionIds.slice(i, i + CHUNK_SIZE);
|
|
510
|
+
const rows = await appDb
|
|
511
|
+
.select({
|
|
512
|
+
transactionId: metadata.propertyValue,
|
|
513
|
+
propertyName: metadata.propertyName,
|
|
514
|
+
refResolvedValue: metadata.refResolvedValue,
|
|
515
|
+
localStorageDir: metadata.localStorageDir,
|
|
516
|
+
})
|
|
517
|
+
.from(metadata)
|
|
518
|
+
.where(and(isNotNull(metadata.derivedFromUid), isNotNull(metadata.refResolvedValue), inArray(metadata.propertyValue, chunk)));
|
|
519
|
+
for (const row of rows) {
|
|
520
|
+
const { transactionId, propertyName, refResolvedValue } = row;
|
|
521
|
+
if (!transactionId || !propertyName || !refResolvedValue)
|
|
522
|
+
continue;
|
|
523
|
+
// A file name, never a path: anything else is not where the SDK would look.
|
|
524
|
+
if (refResolvedValue.includes('/') || refResolvedValue.includes('\\'))
|
|
525
|
+
continue;
|
|
526
|
+
const byName = (out[transactionId] ?? (out[transactionId] = {}));
|
|
527
|
+
byName[propertyName] ?? (byName[propertyName] = `${getItemStorageSubdir(row.localStorageDir)}/${refResolvedValue}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return out;
|
|
531
|
+
};
|
|
532
|
+
|
|
412
533
|
const logger$4 = debug('seedSdk:files:download');
|
|
413
534
|
const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
|
|
414
535
|
/** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
|
|
@@ -425,8 +546,8 @@ const syncDbFiles = async (endpoints) => {
|
|
|
425
546
|
const getAppDbReady = async () => {
|
|
426
547
|
if (!BaseDb.isAppDbReady()) {
|
|
427
548
|
// Wait for ClientManager to be ready (DB_INIT state or later)
|
|
428
|
-
const _mod_0 = await import('./ClientManager-
|
|
429
|
-
const _ns_0 = _mod_0.
|
|
549
|
+
const _mod_0 = await import('./ClientManager-C-QXqUK9.js');
|
|
550
|
+
const _ns_0 = _mod_0.J;
|
|
430
551
|
const clientManagerMod = _ns_0;
|
|
431
552
|
const { getClient } = clientManagerMod;
|
|
432
553
|
const clientManager = getClient();
|
|
@@ -561,76 +682,117 @@ const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) =>
|
|
|
561
682
|
}
|
|
562
683
|
return transactionIds;
|
|
563
684
|
};
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
685
|
+
/** Content-SHA-256 tag values for the transactions that have one, from one batched tag lookup (cached). */
|
|
686
|
+
const getExpectedContentHashes = async (transactionIds) => {
|
|
687
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
688
|
+
const tagsById = new Map();
|
|
689
|
+
const toFetch = [];
|
|
690
|
+
for (const transactionId of transactionIds) {
|
|
691
|
+
// Tags never change once a transaction is indexed, so a cached lookup stays good.
|
|
692
|
+
const cached = queryClient.getQueryData?.(['getTransactionTags', transactionId]);
|
|
693
|
+
if (cached)
|
|
694
|
+
tagsById.set(transactionId, cached);
|
|
695
|
+
else
|
|
696
|
+
toFetch.push(transactionId);
|
|
697
|
+
}
|
|
698
|
+
if (toFetch.length > 0) {
|
|
699
|
+
try {
|
|
700
|
+
const fetched = await getTransactionTagsByIds(toFetch, {
|
|
701
|
+
client: BaseArweaveClient.getArweaveClient(),
|
|
702
|
+
onError: (error) => logger$4('[download] transaction tags lookup failed', error),
|
|
703
|
+
});
|
|
704
|
+
for (const [transactionId, tags] of fetched) {
|
|
705
|
+
tagsById.set(transactionId, tags);
|
|
706
|
+
// Seed the per-transaction cache entry (the client interface has no setQueryData).
|
|
707
|
+
void queryClient
|
|
708
|
+
.fetchQuery({ queryKey: ['getTransactionTags', transactionId], queryFn: async () => tags })
|
|
709
|
+
.catch(() => { });
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
catch (error) {
|
|
713
|
+
logger$4('[download] transaction tags lookup failed', error);
|
|
714
|
+
}
|
|
567
715
|
}
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
716
|
+
const out = {};
|
|
717
|
+
for (const [transactionId, tags] of tagsById) {
|
|
718
|
+
const value = tags.find((tag) => tag.name === CONTENT_SHA256_TAG)?.value?.trim();
|
|
719
|
+
if (value)
|
|
720
|
+
out[transactionId] = value;
|
|
571
721
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
722
|
+
return out;
|
|
723
|
+
};
|
|
724
|
+
/** Store the (now verified) Content-SHA-256 of each downloaded transaction on its metadata row. */
|
|
725
|
+
const recordVerifiedContentHashes = async (transactionIds, expectedContentHashes) => {
|
|
576
726
|
for (const transactionId of transactionIds) {
|
|
577
|
-
|
|
727
|
+
const contentHash = expectedContentHashes[transactionId];
|
|
728
|
+
if (!contentHash)
|
|
578
729
|
continue;
|
|
579
|
-
}
|
|
580
730
|
try {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
try {
|
|
585
|
-
tags = await queryClient.fetchQuery({
|
|
586
|
-
queryKey: ['getTransactionTags', transactionId],
|
|
587
|
-
queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
|
|
588
|
-
});
|
|
731
|
+
const metadataRecord = await getMetadata({ storageTransactionId: transactionId });
|
|
732
|
+
if (metadataRecord) {
|
|
733
|
+
await saveMetadata(metadataRecord, { contentHash });
|
|
589
734
|
}
|
|
590
|
-
catch {
|
|
591
|
-
tags = [];
|
|
592
|
-
}
|
|
593
|
-
if (tags && tags.length > 0) {
|
|
594
|
-
for (const { name, value } of tags) {
|
|
595
|
-
if (name !== 'Content-SHA-256')
|
|
596
|
-
continue;
|
|
597
|
-
const metadataRecord = await getMetadata({
|
|
598
|
-
storageTransactionId: transactionId,
|
|
599
|
-
});
|
|
600
|
-
if (metadataRecord) {
|
|
601
|
-
await saveMetadata(metadataRecord, {
|
|
602
|
-
contentHash: value,
|
|
603
|
-
});
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
transactionIdsToDownload.push(transactionId);
|
|
608
735
|
}
|
|
609
736
|
catch (error) {
|
|
610
737
|
logger$4(error);
|
|
611
738
|
}
|
|
612
739
|
}
|
|
740
|
+
};
|
|
741
|
+
const downloadTransactionIds = async (rawTransactionIds, options) => {
|
|
742
|
+
if (!supportsOpfsFileDownloads()) {
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
|
|
746
|
+
if (transactionIds.length === 0) {
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
750
|
+
await ensureReadGatewaySelected();
|
|
751
|
+
// Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
|
|
752
|
+
// CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
|
|
753
|
+
const transactionIdsToDownload = transactionIds.filter((id) => !excludedTransactions.has(id));
|
|
613
754
|
if (transactionIdsToDownload.length === 0) {
|
|
614
755
|
return false;
|
|
615
756
|
}
|
|
757
|
+
// One batched lookup for every upload's Content-SHA-256 tag; downloads are verified against it.
|
|
758
|
+
// Missing tags (old uploads, or a just-published one not indexed yet) just mean no verification.
|
|
759
|
+
const expectedContentHashes = await getExpectedContentHashes(transactionIdsToDownload);
|
|
616
760
|
// Preferred gateways first: a just-published item is only on the gateway it was uploaded through.
|
|
617
761
|
const arweaveBaseUrls = getArweaveReadBaseUrls();
|
|
762
|
+
// Where each ItemStorage child of a composite goes (the worker cannot read the DB or the schema).
|
|
763
|
+
const compositeChildPaths = await getCompositeChildPaths(transactionIdsToDownload).catch((error) => {
|
|
764
|
+
logger$4('[download] composite child paths lookup failed', error);
|
|
765
|
+
return {};
|
|
766
|
+
});
|
|
767
|
+
let result;
|
|
618
768
|
if (transactionIdsToDownload.length === 1) {
|
|
619
|
-
|
|
620
|
-
|
|
769
|
+
const transactionId = transactionIdsToDownload[0];
|
|
770
|
+
result = await BaseFileManager.downloadFileByTransactionId({
|
|
771
|
+
transactionId,
|
|
621
772
|
arweaveHost: BaseArweaveClient.getBaseUrl(),
|
|
622
773
|
arweaveBaseUrls,
|
|
623
774
|
excludedTransactions,
|
|
775
|
+
expectedContentHash: expectedContentHashes[transactionId],
|
|
776
|
+
compositeChildPaths: compositeChildPaths[transactionId],
|
|
624
777
|
});
|
|
625
778
|
}
|
|
626
779
|
else {
|
|
627
|
-
await BaseFileManager.downloadAllFiles({
|
|
780
|
+
result = await BaseFileManager.downloadAllFiles({
|
|
628
781
|
transactionIds: transactionIdsToDownload,
|
|
629
782
|
arweaveHost: BaseArweaveClient.getBaseUrl(),
|
|
630
783
|
arweaveBaseUrls,
|
|
631
784
|
excludedTransactions,
|
|
785
|
+
expectedContentHashes,
|
|
786
|
+
compositeChildPaths,
|
|
632
787
|
});
|
|
633
788
|
}
|
|
789
|
+
if (result) {
|
|
790
|
+
for (const transactionId of result.hashMismatchTransactionIds) {
|
|
791
|
+
// Not saved by the worker; left for a later run (a gateway may serve the right bytes then).
|
|
792
|
+
logger$4(`[download] ${transactionId}: downloaded bytes do not match Content-SHA-256; skipped`);
|
|
793
|
+
}
|
|
794
|
+
await recordVerifiedContentHashes(result.verifiedTransactionIds, expectedContentHashes);
|
|
795
|
+
}
|
|
634
796
|
if (options?.resizeAllImages !== false) {
|
|
635
797
|
await BaseFileManager.resizeAllImages({
|
|
636
798
|
width: 480,
|
|
@@ -715,6 +877,7 @@ const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
|
|
|
715
877
|
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
|
|
716
878
|
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
|
|
717
879
|
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
|
|
880
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('files'));
|
|
718
881
|
const excludedTransactions = await getExcludedTransactions();
|
|
719
882
|
const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
|
|
720
883
|
const fromLocal = await collectTransactionIdsFromLocalMetadata();
|
|
@@ -1188,6 +1351,10 @@ function waitForTurn(previous, name, timeoutMs) {
|
|
|
1188
1351
|
}
|
|
1189
1352
|
|
|
1190
1353
|
const logger$1 = debug('seedSdk:helpers:tabCoordinator');
|
|
1354
|
+
/** Identifies this tab (this page's SDK instance) in the messages it sends. */
|
|
1355
|
+
const TAB_ID = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
|
|
1356
|
+
? crypto.randomUUID()
|
|
1357
|
+
: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
1191
1358
|
let state;
|
|
1192
1359
|
let leader = false;
|
|
1193
1360
|
let leaderWaiters = [];
|
|
@@ -1206,6 +1373,10 @@ function startTabCoordination({ filesDir, mode = 'coordinate' }) {
|
|
|
1206
1373
|
}
|
|
1207
1374
|
const channel = new BroadcastChannel(`seed:tabs:${dbKey}`);
|
|
1208
1375
|
channel.onmessage = (event) => {
|
|
1376
|
+
// A BroadcastChannel never hears itself, but another channel object in this page would (a
|
|
1377
|
+
// second channel opened by a test, or the same module loaded twice): skip our own messages.
|
|
1378
|
+
if (event.data?.from === TAB_ID)
|
|
1379
|
+
return;
|
|
1209
1380
|
for (const handler of messageHandlers)
|
|
1210
1381
|
handler(event.data);
|
|
1211
1382
|
};
|
|
@@ -1243,7 +1414,11 @@ function whenLeaderTab() {
|
|
|
1243
1414
|
}
|
|
1244
1415
|
/** Sends to the other tabs of this database; a no-op when not coordinating. */
|
|
1245
1416
|
function postTabMessage(message) {
|
|
1246
|
-
state?.channel?.postMessage(message);
|
|
1417
|
+
state?.channel?.postMessage({ ...message, from: TAB_ID });
|
|
1418
|
+
}
|
|
1419
|
+
/** Whether postTabMessage reaches other tabs (a browser tab coordinating with Web Locks). */
|
|
1420
|
+
function isPostingTabMessages() {
|
|
1421
|
+
return !!state?.channel;
|
|
1247
1422
|
}
|
|
1248
1423
|
function onTabMessage(handler) {
|
|
1249
1424
|
messageHandlers.add(handler);
|
|
@@ -1274,12 +1449,11 @@ function emitAcrossTabs(name, payload) {
|
|
|
1274
1449
|
postTabMessage({ type: 'event', name, payload });
|
|
1275
1450
|
}
|
|
1276
1451
|
/**
|
|
1277
|
-
* A file saved through this tab's file system: emits `file-saved` here
|
|
1278
|
-
*
|
|
1452
|
+
* A file saved through this tab's file system: emits `file-saved` here. Other tabs hear about it
|
|
1453
|
+
* from the file system itself (see queueFilesChangedNotice), once the write has reached OPFS.
|
|
1279
1454
|
*/
|
|
1280
1455
|
function notifyFileSaved(filePath) {
|
|
1281
1456
|
eventEmitter.emit('file-saved', filePath);
|
|
1282
|
-
postTabMessage({ type: 'files-changed', paths: [filePath] });
|
|
1283
1457
|
}
|
|
1284
1458
|
/**
|
|
1285
1459
|
* Files written straight to OPFS by a worker: refreshes this tab's file-system cache, emits
|
|
@@ -1290,20 +1464,68 @@ async function notifyFilesWrittenOutsideCache(paths) {
|
|
|
1290
1464
|
return;
|
|
1291
1465
|
await BaseFileManager.invalidateCachedPaths(paths);
|
|
1292
1466
|
eventEmitter.emit(FILES_CHANGED_EVENT, paths);
|
|
1293
|
-
|
|
1467
|
+
queueFilesChangedNotice(paths);
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* How long changed paths gather before one `files-changed` message goes out. Counted from the
|
|
1471
|
+
* first queued path, so a steady stream of writes still sends once per window, never later.
|
|
1472
|
+
*/
|
|
1473
|
+
const FILES_CHANGED_FLUSH_MS = 25;
|
|
1474
|
+
/** Keeps a message for a huge batch (a bulk download) from being one giant structured clone. */
|
|
1475
|
+
const FILES_CHANGED_MAX_PATHS = 500;
|
|
1476
|
+
let pendingChangedPaths = new Set();
|
|
1477
|
+
let flushTimer;
|
|
1478
|
+
let flushOnPageHide = false;
|
|
1479
|
+
/**
|
|
1480
|
+
* Tells other tabs that these absolute ZenFS paths changed in OPFS, so they drop and re-read their
|
|
1481
|
+
* cached copies (the sync API's in-memory copy in particular). The browser file system calls this
|
|
1482
|
+
* for every file it writes, truncates or removes (`TolerantWebAccessFS.onOpfsChange`, wired in
|
|
1483
|
+
* `BrowserFileManager.initializeFileSystem`), after the change reached OPFS. Paths are coalesced
|
|
1484
|
+
* for FILES_CHANGED_FLUSH_MS, so bulk writes (migrations, schema processing, downloads) send a few
|
|
1485
|
+
* messages rather than one per write.
|
|
1486
|
+
*
|
|
1487
|
+
* Defense in depth only: a tab that misses a message still sees the change on its next async
|
|
1488
|
+
* stat() (see TolerantWebAccessFS.stat). A no-op unless this tab coordinates with others.
|
|
1489
|
+
*/
|
|
1490
|
+
function queueFilesChangedNotice(paths) {
|
|
1491
|
+
if (!isPostingTabMessages())
|
|
1492
|
+
return;
|
|
1493
|
+
for (const path of paths)
|
|
1494
|
+
pendingChangedPaths.add(path);
|
|
1495
|
+
if (flushTimer !== undefined || pendingChangedPaths.size === 0)
|
|
1496
|
+
return;
|
|
1497
|
+
flushTimer = setTimeout(flushFilesChangedNotices, FILES_CHANGED_FLUSH_MS);
|
|
1498
|
+
if (!flushOnPageHide && typeof addEventListener === 'function') {
|
|
1499
|
+
flushOnPageHide = true;
|
|
1500
|
+
// A tab closing inside the window still sends what it wrote.
|
|
1501
|
+
addEventListener('pagehide', flushFilesChangedNotices);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
/** Sends the queued paths now (page hide, tests). */
|
|
1505
|
+
function flushFilesChangedNotices() {
|
|
1506
|
+
if (flushTimer !== undefined)
|
|
1507
|
+
clearTimeout(flushTimer);
|
|
1508
|
+
flushTimer = undefined;
|
|
1509
|
+
if (pendingChangedPaths.size === 0)
|
|
1510
|
+
return;
|
|
1511
|
+
const paths = [...pendingChangedPaths];
|
|
1512
|
+
pendingChangedPaths = new Set();
|
|
1513
|
+
for (let i = 0; i < paths.length; i += FILES_CHANGED_MAX_PATHS) {
|
|
1514
|
+
postTabMessage({ type: 'files-changed', paths: paths.slice(i, i + FILES_CHANGED_MAX_PATHS) });
|
|
1515
|
+
}
|
|
1294
1516
|
}
|
|
1295
1517
|
/** Refreshes this tab's in-memory state for an event another tab emitted, before re-emitting it. */
|
|
1296
1518
|
async function catchUpOn(name, payload) {
|
|
1297
1519
|
if (name === EAS_SEED_DATA_SYNCED_TO_DB_EVENT) {
|
|
1298
|
-
const _mod_1 = await import('./Item-
|
|
1299
|
-
const _ns_1 = _mod_1.
|
|
1520
|
+
const _mod_1 = await import('./Item-C7sUUu2B.js');
|
|
1521
|
+
const _ns_1 = _mod_1.a2;
|
|
1300
1522
|
const { Item } = _ns_1;
|
|
1301
1523
|
await Item.rehydrateCachedItemsFromDbAfterEasSync();
|
|
1302
1524
|
}
|
|
1303
1525
|
else if (name === LOCAL_COPIES_REMOVED_EVENT) {
|
|
1304
1526
|
const { removedSeedLocalIds = [], removedSeedUids = [] } = (payload ?? {});
|
|
1305
|
-
const _mod_2 = await import('./Item-
|
|
1306
|
-
const _ns_2 = _mod_2.
|
|
1527
|
+
const _mod_2 = await import('./Item-C7sUUu2B.js');
|
|
1528
|
+
const _ns_2 = _mod_2.a2;
|
|
1307
1529
|
const { Item } = _ns_2;
|
|
1308
1530
|
Item.dropCachedInstancesForSeedIds([...removedSeedLocalIds, ...removedSeedUids]);
|
|
1309
1531
|
}
|
|
@@ -1333,6 +1555,7 @@ function listenForOtherTabsEvents() {
|
|
|
1333
1555
|
});
|
|
1334
1556
|
}
|
|
1335
1557
|
else if (message.type === 'files-changed') {
|
|
1558
|
+
// Only refreshes caches: never writes, so never sends files-changed back.
|
|
1336
1559
|
void BaseFileManager.invalidateCachedPaths(message.paths)
|
|
1337
1560
|
.catch((error) => logger('refreshing changed files failed', error))
|
|
1338
1561
|
.then(() => eventEmitter.emit(FILES_CHANGED_EVENT, message.paths));
|
|
@@ -1340,5 +1563,18 @@ function listenForOtherTabsEvents() {
|
|
|
1340
1563
|
});
|
|
1341
1564
|
}
|
|
1342
1565
|
|
|
1343
|
-
|
|
1344
|
-
|
|
1566
|
+
var tabEvents = /*#__PURE__*/Object.freeze({
|
|
1567
|
+
__proto__: null,
|
|
1568
|
+
FILES_CHANGED_EVENT: FILES_CHANGED_EVENT,
|
|
1569
|
+
FILES_CHANGED_FLUSH_MS: FILES_CHANGED_FLUSH_MS,
|
|
1570
|
+
FILES_CHANGED_MAX_PATHS: FILES_CHANGED_MAX_PATHS,
|
|
1571
|
+
emitAcrossTabs: emitAcrossTabs,
|
|
1572
|
+
flushFilesChangedNotices: flushFilesChangedNotices,
|
|
1573
|
+
listenForOtherTabsEvents: listenForOtherTabsEvents,
|
|
1574
|
+
notifyFileSaved: notifyFileSaved,
|
|
1575
|
+
notifyFilesWrittenOutsideCache: notifyFilesWrittenOutsideCache,
|
|
1576
|
+
queueFilesChangedNotice: queueFilesChangedNotice
|
|
1577
|
+
});
|
|
1578
|
+
|
|
1579
|
+
export { ADDRESSES_PERSISTED_EVENT as A, whenLeaderTab as B, CONTENT_SHA256_TAG as C, withDbTabLock as D, notifyFilesWrittenOutsideCache as E, FILES_CHANGED_EVENT as F, withSeedDbLock as G, postTabMessage as H, onTabMessage as I, listenForOtherTabsEvents as J, isNode as K, LOCAL_COPIES_REMOVED_EVENT as L, isBrowser as M, startTabCoordination as N, downloadAllFilesRequestHandler as O, downloadAllFilesBinaryRequestHandler as P, getStorageTransactionIdForSeedUid as Q, convertTxIdToImage as R, downloadTransactionIdWithDedupe as S, TabLockTimeoutError as T, getDataTypeFromString as U, getMimeType as V, notifyFileSaved as W, withTabLock as X, download as Y, generateId$1 as Z, tabEvents as _, getItemStorageSubdir as a, buildArweaveContentTags as b, getItemStorageLocalFileName as c, getContentSha256 as d, getCorrectId as e, isStorageSeedRef as f, getStorageDirForDataType as g, emitAcrossTabs as h, isPublishedSeedRef as i, generateId as j, getArweaveUrlForTransaction as k, CONTENT_TYPE_TAG as l, classifyMediaRef as m, normalizeRelationPropertyValue as n, closestImageSize as o, contentSha256TagMatches as p, ensureImageLocal as q, resolveSeedIdsFromRefString as r, scheduleBulkFilesDownloadFromEasSync as s, toSnakeCase as t, getFeedItemStringField as u, isLeaderTab as v, normalizeArweaveTxIdForEnsure as w, normalizeFeedItemFields as x, parseAddressesPersistedPayload as y, resolveMediaRef as z };
|
|
1580
|
+
//# sourceMappingURL=tabEvents-DguZpCCv.js.map
|