@seedprotocol/sdk 0.4.21 → 0.4.23
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/{ArweaveClient-DxpJnJXU.js → ArweaveClient-DoBABTLW.js} +3 -4
- package/dist/{ArweaveClient-DxpJnJXU.js.map → ArweaveClient-DoBABTLW.js.map} +1 -1
- package/dist/{ArweaveClient-Cz9ZLiEV.js → ArweaveClient-KF_T3NSr.js} +3 -4
- package/dist/{ArweaveClient-Cz9ZLiEV.js.map → ArweaveClient-KF_T3NSr.js.map} +1 -1
- package/dist/{Db-DkTBncAM.js → Db-Cg7Q5gIc.js} +4 -5
- package/dist/{Db-DkTBncAM.js.map → Db-Cg7Q5gIc.js.map} +1 -1
- package/dist/{Db-CXwQVLZv.js → Db-DA_e7Jcc.js} +107 -7
- package/dist/Db-DA_e7Jcc.js.map +1 -0
- package/dist/{EasClient-DjpbHjU9.js → EasClient-B4VivHxM.js} +2 -3
- package/dist/{EasClient-JYkmHxu1.js.map → EasClient-B4VivHxM.js.map} +1 -1
- package/dist/{EasClient-JYkmHxu1.js → EasClient-CVPHYGNP.js} +2 -3
- package/dist/{EasClient-DjpbHjU9.js.map → EasClient-CVPHYGNP.js.map} +1 -1
- package/dist/{FileManager-DHnyb040.js → FileManager-BOxbzROS.js} +18 -3
- package/dist/FileManager-BOxbzROS.js.map +1 -0
- package/dist/{FileManager-CKyoLrBP.js → FileManager-Ba5BCbCL.js} +2 -3
- package/dist/{FileManager-CKyoLrBP.js.map → FileManager-Ba5BCbCL.js.map} +1 -1
- package/dist/{ModelProperty-DWtv9fQr.js → ModelProperty-D6JLRqQW.js} +24 -25
- package/dist/ModelProperty-D6JLRqQW.js.map +1 -0
- package/dist/{PathResolver-Ce4K9acQ.js → PathResolver-D7WqjJCo.js} +2 -3
- package/dist/{PathResolver-Ce4K9acQ.js.map → PathResolver-D7WqjJCo.js.map} +1 -1
- package/dist/{PathResolver-pmw--Ea2.js → PathResolver-DHTAlCzo.js} +2 -3
- package/dist/{PathResolver-pmw--Ea2.js.map → PathResolver-DHTAlCzo.js.map} +1 -1
- package/dist/{QueryClient-unspcsWa.js → QueryClient-B12y2daD.js} +7 -4
- package/dist/QueryClient-B12y2daD.js.map +1 -0
- package/dist/{QueryClient-OUjfvY3g.js → QueryClient-BCxuWg7f.js} +3 -3
- package/dist/QueryClient-BCxuWg7f.js.map +1 -0
- package/dist/{Schema-CqqcEexA.js → Schema-B5_B8nM5.js} +38 -38
- package/dist/{Schema-CqqcEexA.js.map → Schema-B5_B8nM5.js.map} +1 -1
- package/dist/{SchemaValidationService-Cb-b4kpD.js → SchemaValidationService-DXYRdSYa.js} +2 -3
- package/dist/{SchemaValidationService-Cb-b4kpD.js.map → SchemaValidationService-DXYRdSYa.js.map} +1 -1
- package/dist/{backfillMetadataPropertyIds-CRyRez3h.js → backfillMetadataPropertyIds-BWEhAJPS.js} +2 -3
- package/dist/{backfillMetadataPropertyIds-CRyRez3h.js.map → backfillMetadataPropertyIds-BWEhAJPS.js.map} +1 -1
- package/dist/cjs/{ModelProperty-sNx_ZQZX.js → ModelProperty-Ov1_YL9l.js} +17 -18
- package/dist/cjs/{ModelProperty-sNx_ZQZX.js.map → ModelProperty-Ov1_YL9l.js.map} +1 -1
- package/dist/cjs/{Schema-B4RRA-0g.js → Schema-CeG5iRX_.js} +20 -21
- package/dist/cjs/{Schema-B4RRA-0g.js.map → Schema-CeG5iRX_.js.map} +1 -1
- package/dist/cjs/{SchemaValidationService-DCflhpcI.js → SchemaValidationService-C8mdrNnp.js} +2 -3
- package/dist/cjs/{SchemaValidationService-DCflhpcI.js.map → SchemaValidationService-C8mdrNnp.js.map} +1 -1
- package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js → backfillMetadataPropertyIds-LDYghZxU.js} +2 -3
- package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js.map → backfillMetadataPropertyIds-LDYghZxU.js.map} +1 -1
- package/dist/cjs/{getItem-lyM2x5pT.js → getItem-CW3BFytl.js} +2 -3
- package/dist/cjs/{getItem-lyM2x5pT.js.map → getItem-CW3BFytl.js.map} +1 -1
- package/dist/cjs/{getPublishPayload-DP2fm4q8.js → getPublishPayload-C0hWIYCX.js} +11 -12
- package/dist/cjs/{getPublishPayload-DP2fm4q8.js.map → getPublishPayload-C0hWIYCX.js.map} +1 -1
- package/dist/cjs/{getPublishUploads-DdVy-5fK.js → getPublishUploads-CMpPR2JJ.js} +39 -7
- package/dist/cjs/getPublishUploads-CMpPR2JJ.js.map +1 -0
- package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js → getSegmentedItemProperties-B4ao_B1Q.js} +3 -3
- package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js.map → getSegmentedItemProperties-B4ao_B1Q.js.map} +1 -1
- package/dist/cjs/{index-DTkoTvcq.js → index-Dty7eE10.js} +3 -4
- package/dist/cjs/index-Dty7eE10.js.map +1 -0
- package/dist/cjs/{index-D1qR8xnb.js → index-Far6-WGM.js} +2034 -1118
- package/dist/cjs/index-Far6-WGM.js.map +1 -0
- package/dist/cjs/{ownership-DanM_n8E.js → ownership-TCXiKRY_.js} +2 -3
- package/dist/cjs/{ownership-DanM_n8E.js.map → ownership-TCXiKRY_.js.map} +1 -1
- package/dist/cjs/{property-BQokoaRe.js → property-BT7i8Tl-.js} +4 -5
- package/dist/cjs/{property-BQokoaRe.js.map → property-BT7i8Tl-.js.map} +1 -1
- package/dist/cjs/syncDbWithEas-DUi78csI.js +609 -0
- package/dist/cjs/syncDbWithEas-DUi78csI.js.map +1 -0
- package/dist/db/drizzle/drizzle/0013_eas_sync_processes.sql +12 -0
- package/dist/db/drizzle/drizzle/meta/0013_snapshot.json +1262 -0
- package/dist/db/drizzle/drizzle/meta/_journal.json +7 -0
- package/dist/{getItem-VI3QqdZH.js → getItem-D5_bPYyC.js} +2 -3
- package/dist/{getItem-VI3QqdZH.js.map → getItem-D5_bPYyC.js.map} +1 -1
- package/dist/{getPublishPayload-DpYwi-rd.js → getPublishPayload-DEdHgrgC.js} +14 -15
- package/dist/getPublishPayload-DEdHgrgC.js.map +1 -0
- package/dist/{getPublishUploads-DS2dQ4Ho.js → getPublishUploads-CH72lAID.js} +39 -7
- package/dist/getPublishUploads-CH72lAID.js.map +1 -0
- package/dist/{getSegmentedItemProperties-Bz5B4DSA.js → getSegmentedItemProperties-Cp92QUHQ.js} +3 -3
- package/dist/{getSegmentedItemProperties-Bz5B4DSA.js.map → getSegmentedItemProperties-Cp92QUHQ.js.map} +1 -1
- package/dist/{index-BrD_NNaX.js → index-18lln0cM.js} +2045 -1130
- package/dist/index-18lln0cM.js.map +1 -0
- package/dist/{index-DdzhrbkF.js → index-Bp0ChnQr.js} +3 -2
- package/dist/index-Bp0ChnQr.js.map +1 -0
- package/dist/{index-Cqf_DxkJ.js → index-DB3nZ0lK.js} +3 -4
- package/dist/index-DB3nZ0lK.js.map +1 -0
- package/dist/main.cjs +1 -2
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +16 -42
- package/dist/main.js.map +1 -1
- package/dist/node.js +10 -11
- package/dist/node.js.map +1 -1
- package/dist/{ownership-BK6suksO.js → ownership-D-KsIkxM.js} +2 -3
- package/dist/{ownership-BK6suksO.js.map → ownership-D-KsIkxM.js.map} +1 -1
- package/dist/{property-C63Ddzap.js → property-DViA9nga.js} +6 -7
- package/dist/property-DViA9nga.js.map +1 -0
- package/dist/{queries-BGuWjEqt.js → queries-ANFHy2e0.js} +2 -2
- package/dist/{queries-BGuWjEqt.js.map → queries-ANFHy2e0.js.map} +1 -1
- package/dist/seedSchema/EasSyncProcessSchema.ts +17 -0
- package/dist/seedSchema/index.ts +1 -0
- package/dist/src/Item/Item.d.ts +18 -0
- package/dist/src/Item/Item.d.ts.map +1 -1
- package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/loadOrCreateProperty.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/actors/saveValueToDb/saveImage.d.ts.map +1 -1
- package/dist/src/ItemProperty/service/propertyMachine.d.ts +4 -1
- package/dist/src/ItemProperty/service/propertyMachine.d.ts.map +1 -1
- package/dist/src/Model/service/modelMachine.d.ts +20 -20
- package/dist/src/ModelProperty/service/modelPropertyMachine.d.ts +2 -2
- package/dist/src/Schema/service/addModelsMachine.d.ts +1 -1
- package/dist/src/Schema/service/schemaMachine.d.ts +55 -55
- package/dist/src/browser/db/drizzleFiles.d.ts +3 -2
- package/dist/src/browser/db/drizzleFiles.d.ts.map +1 -1
- package/dist/src/browser/helpers/QueryClient.d.ts.map +1 -1
- package/dist/src/client/ClientManager.d.ts.map +1 -1
- package/dist/src/client/actors/addModelsToDb.d.ts.map +1 -1
- package/dist/src/client/actors/platformClassesInit.d.ts.map +1 -1
- package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
- package/dist/src/client/constants.d.ts +1 -0
- package/dist/src/client/constants.d.ts.map +1 -1
- package/dist/src/db/read/getPublishPendingDiff.d.ts.map +1 -1
- package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
- package/dist/src/db/write/applyPropertyAttestationUidsFromPublish.d.ts.map +1 -1
- package/dist/src/db/write/easSyncProcess.d.ts +12 -0
- package/dist/src/db/write/easSyncProcess.d.ts.map +1 -0
- package/dist/src/db/write/updateItemPropertyValue.d.ts.map +1 -1
- package/dist/src/eventBus.d.ts +13 -2
- package/dist/src/eventBus.d.ts.map +1 -1
- package/dist/src/events/files/download.d.ts +5 -1
- package/dist/src/events/files/download.d.ts.map +1 -1
- package/dist/src/events/item/easSyncManager.d.ts +71 -0
- package/dist/src/events/item/easSyncManager.d.ts.map +1 -0
- package/dist/src/events/item/index.d.ts.map +1 -1
- package/dist/src/events/item/mergeEasSyncOptions.d.ts +7 -0
- package/dist/src/events/item/mergeEasSyncOptions.d.ts.map +1 -0
- package/dist/src/events/item/syncDbWithEas.d.ts +0 -3
- package/dist/src/events/item/syncDbWithEas.d.ts.map +1 -1
- package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts +17 -0
- package/dist/src/helpers/ArweaveClient/BaseArweaveClient.d.ts.map +1 -1
- package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts +6 -0
- package/dist/src/helpers/ArweaveClient/arweaveL1UploadApi.d.ts.map +1 -1
- package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts +16 -0
- package/dist/src/helpers/ArweaveClient/selectReadGateway.d.ts.map +1 -0
- package/dist/src/helpers/FileManager/BaseFileManager.d.ts +1 -0
- package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
- package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts +16 -0
- package/dist/src/helpers/compareMetadataRowsLatestFirst.d.ts.map +1 -0
- package/dist/src/helpers/constants.d.ts +20 -5
- package/dist/src/helpers/constants.d.ts.map +1 -1
- package/dist/src/helpers/environment.d.ts +5 -0
- package/dist/src/helpers/environment.d.ts.map +1 -1
- package/dist/src/helpers/htmlEmbeddedDataUriPublish.d.ts.map +1 -1
- package/dist/src/helpers/index.d.ts +1 -0
- package/dist/src/helpers/index.d.ts.map +1 -1
- package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts +8 -0
- package/dist/src/helpers/readHtmlBodyForStorageSeed.d.ts.map +1 -0
- package/dist/src/index.d.ts +7 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/interfaces/IQueryClient.d.ts +4 -0
- package/dist/src/interfaces/IQueryClient.d.ts.map +1 -1
- package/dist/src/node/helpers/QueryClient.d.ts.map +1 -1
- package/dist/src/seedSchema/EasSyncProcessSchema.d.ts +190 -0
- package/dist/src/seedSchema/EasSyncProcessSchema.d.ts.map +1 -0
- package/dist/src/seedSchema/index.d.ts +1 -0
- package/dist/src/seedSchema/index.d.ts.map +1 -1
- package/dist/src/services/write/writeProcessMachine.d.ts +1 -1
- package/dist/src/types/fileManager.d.ts +5 -0
- package/dist/src/types/fileManager.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +3 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/machines.d.ts +1 -1
- package/dist/src/types/machines.d.ts.map +1 -1
- package/dist/src/vite/index.d.ts.map +1 -1
- package/dist/syncDbWithEas-m-_3Ds7d.js +582 -0
- package/dist/syncDbWithEas-m-_3Ds7d.js.map +1 -0
- package/dist/updateSeedRevokedAt-BvAK-Rfh.js +22 -0
- package/dist/updateSeedRevokedAt-BvAK-Rfh.js.map +1 -0
- package/dist/vite.cjs +100 -26
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +100 -26
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/dist/Db-CXwQVLZv.js.map +0 -1
- package/dist/FileManager-DHnyb040.js.map +0 -1
- package/dist/ModelProperty-DWtv9fQr.js.map +0 -1
- package/dist/QueryClient-OUjfvY3g.js.map +0 -1
- package/dist/QueryClient-unspcsWa.js.map +0 -1
- package/dist/cjs/getPublishUploads-DdVy-5fK.js.map +0 -1
- package/dist/cjs/index-D1qR8xnb.js.map +0 -1
- package/dist/cjs/index-DTkoTvcq.js.map +0 -1
- package/dist/getPublishPayload-DpYwi-rd.js.map +0 -1
- package/dist/getPublishUploads-DS2dQ4Ho.js.map +0 -1
- package/dist/index-BrD_NNaX.js.map +0 -1
- package/dist/index-Cqf_DxkJ.js.map +0 -1
- package/dist/index-DdzhrbkF.js.map +0 -1
- package/dist/property-C63Ddzap.js.map +0 -1
|
@@ -14,7 +14,6 @@ var typebox = require('@sinclair/typebox');
|
|
|
14
14
|
var casing = require('drizzle-orm/casing');
|
|
15
15
|
var lodashEs = require('lodash-es');
|
|
16
16
|
var rxjs = require('rxjs');
|
|
17
|
-
var EventEmitter = require('eventemitter3');
|
|
18
17
|
var Arweave = require('arweave');
|
|
19
18
|
var sha3 = require('js-sha3');
|
|
20
19
|
var fsAsync = require('fs/promises');
|
|
@@ -198,6 +197,13 @@ class BaseFileManager {
|
|
|
198
197
|
static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
|
|
199
198
|
return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
|
|
200
199
|
}
|
|
200
|
+
static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
|
|
201
|
+
return this.PlatformClass.downloadAllFiles({
|
|
202
|
+
transactionIds: [transactionId],
|
|
203
|
+
arweaveHost,
|
|
204
|
+
excludedTransactions,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
201
207
|
static resizeImage({ filePath, width, height }) {
|
|
202
208
|
return this.PlatformClass.resizeImage({ filePath, width, height });
|
|
203
209
|
}
|
|
@@ -406,8 +412,51 @@ var SeedModels;
|
|
|
406
412
|
// Internal SDK schema that should not be created in app's files directory
|
|
407
413
|
const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
|
|
408
414
|
const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
|
|
409
|
-
/** Default Arweave gateway host used across all packages */
|
|
410
|
-
const DEFAULT_ARWEAVE_HOST = '
|
|
415
|
+
/** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
|
|
416
|
+
const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
|
|
417
|
+
/**
|
|
418
|
+
* Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
|
|
419
|
+
* Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
|
|
420
|
+
*/
|
|
421
|
+
const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
|
|
422
|
+
const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
|
|
423
|
+
/** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
|
|
424
|
+
function getDefaultArweaveReadGatewayHostsOrdered() {
|
|
425
|
+
if (typeof process === 'undefined' || !process.env) {
|
|
426
|
+
return [...DEFAULT_ARWEAVE_GATEWAYS];
|
|
427
|
+
}
|
|
428
|
+
for (const key of READ_GATEWAYS_ENV_KEYS) {
|
|
429
|
+
const raw = process.env[key]?.trim();
|
|
430
|
+
if (raw) {
|
|
431
|
+
return raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return [...DEFAULT_ARWEAVE_GATEWAYS];
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Deduped host list: primary first, then each default not already present (case-insensitive).
|
|
438
|
+
*/
|
|
439
|
+
function mergePrimaryHostWithDefaults(primary, defaults) {
|
|
440
|
+
const seen = new Set();
|
|
441
|
+
const out = [];
|
|
442
|
+
const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
|
|
443
|
+
const add = (h) => {
|
|
444
|
+
const t = h.trim().replace(/\/$/, '');
|
|
445
|
+
if (!t)
|
|
446
|
+
return;
|
|
447
|
+
const k = keyOf(t);
|
|
448
|
+
if (seen.has(k))
|
|
449
|
+
return;
|
|
450
|
+
seen.add(k);
|
|
451
|
+
out.push(t);
|
|
452
|
+
};
|
|
453
|
+
add(primary);
|
|
454
|
+
for (const d of defaults)
|
|
455
|
+
add(d);
|
|
456
|
+
return out;
|
|
457
|
+
}
|
|
458
|
+
/** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
|
|
459
|
+
const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
|
|
411
460
|
/**
|
|
412
461
|
* Check if a schema is an internal SDK schema that should not be created in app files
|
|
413
462
|
*/
|
|
@@ -419,7 +468,9 @@ function isInternalSchema(schemaName, schemaId) {
|
|
|
419
468
|
var constants = /*#__PURE__*/Object.freeze({
|
|
420
469
|
__proto__: null,
|
|
421
470
|
CLIENT_NOT_INITIALIZED: CLIENT_NOT_INITIALIZED,
|
|
471
|
+
DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
|
|
422
472
|
DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
|
|
473
|
+
EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
|
|
423
474
|
INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
|
|
424
475
|
INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
|
|
425
476
|
INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
|
|
@@ -437,7 +488,9 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
437
488
|
ZERO_BYTES: ZERO_BYTES,
|
|
438
489
|
ZERO_BYTES32: ZERO_BYTES32,
|
|
439
490
|
defaultAttestationData: defaultAttestationData,
|
|
440
|
-
|
|
491
|
+
getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
|
|
492
|
+
isInternalSchema: isInternalSchema,
|
|
493
|
+
mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
|
|
441
494
|
});
|
|
442
495
|
|
|
443
496
|
function parseGateway(input) {
|
|
@@ -454,6 +507,8 @@ function parseGateway(input) {
|
|
|
454
507
|
let _host = DEFAULT_ARWEAVE_HOST;
|
|
455
508
|
let _protocol = 'https';
|
|
456
509
|
let _hostExplicitlySet = false;
|
|
510
|
+
/** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
|
|
511
|
+
let _suppressEnvGatewayOverride = false;
|
|
457
512
|
class BaseArweaveClient {
|
|
458
513
|
static setPlatformClass(platformClass) {
|
|
459
514
|
this.PlatformClass = platformClass;
|
|
@@ -466,7 +521,7 @@ class BaseArweaveClient {
|
|
|
466
521
|
const envHost = typeof process !== 'undefined' && process.env
|
|
467
522
|
? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
|
|
468
523
|
: undefined;
|
|
469
|
-
if (envHost && !_hostExplicitlySet) {
|
|
524
|
+
if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
|
|
470
525
|
return parseGateway(envHost);
|
|
471
526
|
}
|
|
472
527
|
}
|
|
@@ -504,6 +559,39 @@ class BaseArweaveClient {
|
|
|
504
559
|
_host = parsed.host;
|
|
505
560
|
_protocol = parsed.protocol;
|
|
506
561
|
_hostExplicitlySet = true;
|
|
562
|
+
_suppressEnvGatewayOverride = false;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* When true, read-path gateway probing does not change the host ({@link setHost}).
|
|
566
|
+
*/
|
|
567
|
+
static isReadGatewayLocked() {
|
|
568
|
+
return _hostExplicitlySet;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* @internal Clears env override suppression after probing (for test isolation).
|
|
572
|
+
*/
|
|
573
|
+
static resetReadGatewaySelectionStateForTests() {
|
|
574
|
+
_suppressEnvGatewayOverride = false;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
|
|
578
|
+
* Used for seed `arweaveDomain`.
|
|
579
|
+
*/
|
|
580
|
+
static setPreferredReadGateway(host) {
|
|
581
|
+
const parsed = parseGateway(host);
|
|
582
|
+
_host = parsed.host;
|
|
583
|
+
_protocol = parsed.protocol;
|
|
584
|
+
_hostExplicitlySet = false;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
|
|
588
|
+
*/
|
|
589
|
+
static applyProbedReadGateway(host) {
|
|
590
|
+
const parsed = parseGateway(host);
|
|
591
|
+
_host = parsed.host;
|
|
592
|
+
_protocol = parsed.protocol;
|
|
593
|
+
_hostExplicitlySet = false;
|
|
594
|
+
_suppressEnvGatewayOverride = true;
|
|
507
595
|
}
|
|
508
596
|
/**
|
|
509
597
|
* Get the GraphQL endpoint URL
|
|
@@ -587,6 +675,11 @@ class BaseArweaveClient {
|
|
|
587
675
|
}
|
|
588
676
|
}
|
|
589
677
|
|
|
678
|
+
var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
|
|
679
|
+
__proto__: null,
|
|
680
|
+
BaseArweaveClient: BaseArweaveClient
|
|
681
|
+
});
|
|
682
|
+
|
|
590
683
|
/**
|
|
591
684
|
* Trim and strip a trailing slash from an upload API base URL.
|
|
592
685
|
*/
|
|
@@ -638,6 +731,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
|
|
|
638
731
|
}
|
|
639
732
|
}
|
|
640
733
|
|
|
734
|
+
const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
|
|
735
|
+
const PROBE_TIMEOUT_MS = 5000;
|
|
736
|
+
let readGatewayCache = null;
|
|
737
|
+
let ensureInFlight = null;
|
|
738
|
+
/** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
|
|
739
|
+
function invalidateReadGatewayCache() {
|
|
740
|
+
readGatewayCache = null;
|
|
741
|
+
ensureInFlight = null;
|
|
742
|
+
}
|
|
743
|
+
/** Clears probe cache, env override suppression, and preferred host (for tests). */
|
|
744
|
+
function resetArweaveReadGatewayForTests() {
|
|
745
|
+
invalidateReadGatewayCache();
|
|
746
|
+
BaseArweaveClient.resetReadGatewaySelectionStateForTests();
|
|
747
|
+
if (!BaseArweaveClient.isReadGatewayLocked()) {
|
|
748
|
+
BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* GET /info with timeout. Treat 2xx + JSON object as healthy.
|
|
753
|
+
*/
|
|
754
|
+
async function probeGateway(baseUrl, signal) {
|
|
755
|
+
const url = `${baseUrl.replace(/\/$/, '')}/info`;
|
|
756
|
+
let timer;
|
|
757
|
+
const controller = new AbortController();
|
|
758
|
+
const effectiveSignal = signal ?? controller.signal;
|
|
759
|
+
if (!signal) {
|
|
760
|
+
timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
761
|
+
}
|
|
762
|
+
try {
|
|
763
|
+
const response = await fetch(url, {
|
|
764
|
+
method: 'GET',
|
|
765
|
+
signal: effectiveSignal,
|
|
766
|
+
headers: { Accept: 'application/json' },
|
|
767
|
+
});
|
|
768
|
+
if (!response.ok)
|
|
769
|
+
return false;
|
|
770
|
+
const text = await response.text();
|
|
771
|
+
if (!text.trim())
|
|
772
|
+
return false;
|
|
773
|
+
try {
|
|
774
|
+
const json = JSON.parse(text);
|
|
775
|
+
return typeof json === 'object' && json !== null;
|
|
776
|
+
}
|
|
777
|
+
catch {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
catch {
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
finally {
|
|
785
|
+
if (timer)
|
|
786
|
+
clearTimeout(timer);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
|
|
790
|
+
for (const host of hosts) {
|
|
791
|
+
const h = host.trim().replace(/\/$/, '');
|
|
792
|
+
if (!h)
|
|
793
|
+
continue;
|
|
794
|
+
const baseUrl = `${protocol}://${h}`;
|
|
795
|
+
if (await probeGateway(baseUrl, signal)) {
|
|
796
|
+
return h;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
function buildOrderedHostsForProbe() {
|
|
802
|
+
const primary = BaseArweaveClient.getHost();
|
|
803
|
+
const defaults = getDefaultArweaveReadGatewayHostsOrdered();
|
|
804
|
+
return mergePrimaryHostWithDefaults(primary, defaults);
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
|
|
808
|
+
* No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
|
|
809
|
+
* Uses a short TTL cache to avoid probing on every read.
|
|
810
|
+
*/
|
|
811
|
+
async function ensureReadGatewaySelected(signal) {
|
|
812
|
+
if (BaseArweaveClient.isReadGatewayLocked()) {
|
|
813
|
+
return BaseArweaveClient.getHost();
|
|
814
|
+
}
|
|
815
|
+
const now = Date.now();
|
|
816
|
+
if (readGatewayCache && now < readGatewayCache.expiresAt) {
|
|
817
|
+
return readGatewayCache.host;
|
|
818
|
+
}
|
|
819
|
+
if (ensureInFlight) {
|
|
820
|
+
return ensureInFlight;
|
|
821
|
+
}
|
|
822
|
+
ensureInFlight = (async () => {
|
|
823
|
+
const ordered = buildOrderedHostsForProbe();
|
|
824
|
+
const protocol = BaseArweaveClient.getProtocol();
|
|
825
|
+
const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
|
|
826
|
+
if (!BaseArweaveClient.isReadGatewayLocked()) {
|
|
827
|
+
if (picked) {
|
|
828
|
+
BaseArweaveClient.applyProbedReadGateway(picked);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
readGatewayCache = {
|
|
832
|
+
host: BaseArweaveClient.getHost(),
|
|
833
|
+
expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
|
|
834
|
+
};
|
|
835
|
+
return readGatewayCache.host;
|
|
836
|
+
})();
|
|
837
|
+
try {
|
|
838
|
+
return await ensureInFlight;
|
|
839
|
+
}
|
|
840
|
+
finally {
|
|
841
|
+
ensureInFlight = null;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
var selectReadGateway = /*#__PURE__*/Object.freeze({
|
|
846
|
+
__proto__: null,
|
|
847
|
+
ensureReadGatewaySelected: ensureReadGatewaySelected,
|
|
848
|
+
invalidateReadGatewayCache: invalidateReadGatewayCache,
|
|
849
|
+
probeGateway: probeGateway,
|
|
850
|
+
resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
|
|
851
|
+
selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
|
|
852
|
+
});
|
|
853
|
+
|
|
641
854
|
const GATEWAY_TX_QUERY = `
|
|
642
855
|
query ArweaveGatewayTransaction($id: String!) {
|
|
643
856
|
transaction(id: $id) {
|
|
@@ -734,6 +947,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
|
|
|
734
947
|
return null;
|
|
735
948
|
}
|
|
736
949
|
}
|
|
950
|
+
/**
|
|
951
|
+
* Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
|
|
952
|
+
* {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
|
|
953
|
+
* {@link getDefaultArweaveReadGatewayHostsOrdered}.
|
|
954
|
+
*/
|
|
955
|
+
async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
|
|
956
|
+
const defaults = getDefaultArweaveReadGatewayHostsOrdered();
|
|
957
|
+
const trimmed = graphqlUrl?.trim();
|
|
958
|
+
let protocol = 'https';
|
|
959
|
+
let preferredHost = null;
|
|
960
|
+
if (trimmed) {
|
|
961
|
+
try {
|
|
962
|
+
const u = new URL(trimmed);
|
|
963
|
+
protocol = u.protocol === 'http:' ? 'http' : 'https';
|
|
964
|
+
preferredHost = u.hostname || null;
|
|
965
|
+
}
|
|
966
|
+
catch {
|
|
967
|
+
preferredHost = null;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
const ordered = preferredHost && preferredHost.length > 0
|
|
971
|
+
? mergePrimaryHostWithDefaults(preferredHost, defaults)
|
|
972
|
+
: [...defaults];
|
|
973
|
+
const signal = init?.signal;
|
|
974
|
+
for (const host of ordered) {
|
|
975
|
+
const base = `${protocol}://${host}`;
|
|
976
|
+
if (!(await probeGateway(base, signal ?? undefined)))
|
|
977
|
+
continue;
|
|
978
|
+
const gqlUrl = `${protocol}://${host}/graphql`;
|
|
979
|
+
const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
|
|
980
|
+
if (result !== null) {
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return null;
|
|
985
|
+
}
|
|
737
986
|
|
|
738
987
|
class BaseEasClient {
|
|
739
988
|
static setPlatformClass(platformClass) {
|
|
@@ -1409,6 +1658,19 @@ const arweaveL1FinalizeJobs = sqliteCore.sqliteTable('arweave_l1_finalize_jobs',
|
|
|
1409
1658
|
dataItemIdUnique: sqliteCore.uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
|
|
1410
1659
|
}));
|
|
1411
1660
|
|
|
1661
|
+
const easSyncProcesses = sqliteCore.sqliteTable('eas_sync_processes', {
|
|
1662
|
+
id: sqliteCore.int('id').primaryKey({ autoIncrement: true }),
|
|
1663
|
+
status: sqliteCore.text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
|
|
1664
|
+
startedAt: sqliteCore.int('started_at').notNull(),
|
|
1665
|
+
completedAt: sqliteCore.int('completed_at'),
|
|
1666
|
+
requestPayload: sqliteCore.text('request_payload').notNull(),
|
|
1667
|
+
errorMessage: sqliteCore.text('error_message'),
|
|
1668
|
+
errorDetails: sqliteCore.text('error_details'),
|
|
1669
|
+
persistedSnapshot: sqliteCore.text('persisted_snapshot').notNull(),
|
|
1670
|
+
createdAt: sqliteCore.int('created_at'),
|
|
1671
|
+
updatedAt: sqliteCore.int('updated_at'),
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1412
1674
|
/**
|
|
1413
1675
|
* Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
|
|
1414
1676
|
* Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
|
|
@@ -1430,6 +1692,7 @@ var schema$1 = /*#__PURE__*/Object.freeze({
|
|
|
1430
1692
|
appState: appState,
|
|
1431
1693
|
arweaveL1FinalizeJobs: arweaveL1FinalizeJobs,
|
|
1432
1694
|
config: config,
|
|
1695
|
+
easSyncProcesses: easSyncProcesses,
|
|
1433
1696
|
htmlEmbeddedImageCoPublish: htmlEmbeddedImageCoPublish,
|
|
1434
1697
|
metadata: metadata$1,
|
|
1435
1698
|
modelRelations: modelRelations,
|
|
@@ -1922,6 +2185,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1922
2185
|
capitalizeFirstLetter: capitalizeFirstLetter,
|
|
1923
2186
|
classifyMediaRef: classifyMediaRef,
|
|
1924
2187
|
convertTxIdToImage: convertTxIdToImage,
|
|
2188
|
+
ensureReadGatewaySelected: ensureReadGatewaySelected,
|
|
1925
2189
|
generateId: generateId,
|
|
1926
2190
|
getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
|
|
1927
2191
|
getArweaveUploadStatus: getArweaveUploadStatus,
|
|
@@ -1941,6 +2205,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1941
2205
|
getUploadExecutor: getUploadExecutor,
|
|
1942
2206
|
getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
|
|
1943
2207
|
identifyString: identifyString,
|
|
2208
|
+
invalidateReadGatewayCache: invalidateReadGatewayCache,
|
|
1944
2209
|
isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
|
|
1945
2210
|
isBinary: isBinary,
|
|
1946
2211
|
isPlaceholderUid: isPlaceholderUid,
|
|
@@ -1953,11 +2218,15 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1953
2218
|
normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
|
|
1954
2219
|
parseEasRelationPropertyName: parseEasRelationPropertyName,
|
|
1955
2220
|
pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
|
|
2221
|
+
probeGateway: probeGateway,
|
|
1956
2222
|
queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
|
|
2223
|
+
queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
|
|
2224
|
+
resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
|
|
1957
2225
|
resolveMediaRef: resolveMediaRef,
|
|
1958
2226
|
resolveMetadataRecord: resolveMetadataRecord,
|
|
1959
2227
|
resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
|
|
1960
2228
|
resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
|
|
2229
|
+
selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
|
|
1961
2230
|
setAdditionalSyncAddresses: setAdditionalSyncAddresses,
|
|
1962
2231
|
setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
|
|
1963
2232
|
setRevokeExecutor: setRevokeExecutor,
|
|
@@ -1980,7 +2249,7 @@ const createPropertyInstances = async (propertyFileIds) => {
|
|
|
1980
2249
|
return;
|
|
1981
2250
|
}
|
|
1982
2251
|
try {
|
|
1983
|
-
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-
|
|
2252
|
+
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); });
|
|
1984
2253
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
1985
2254
|
if (!ModelProperty) {
|
|
1986
2255
|
logger$y('createPropertyInstances: ModelProperty not available from dynamic import');
|
|
@@ -2164,7 +2433,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
|
|
|
2164
2433
|
// Step 2: Fallback to Schema context (only if database doesn't have the model)
|
|
2165
2434
|
// This handles the case where model exists in schema file but not yet in database
|
|
2166
2435
|
try {
|
|
2167
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2436
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
|
|
2168
2437
|
const { Schema } = schemaMod;
|
|
2169
2438
|
const schema = Schema.create(schemaName, { waitForReady: false });
|
|
2170
2439
|
const schemaSnapshot = schema.getService().getSnapshot();
|
|
@@ -2408,7 +2677,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
|
|
|
2408
2677
|
}
|
|
2409
2678
|
// Mark schema as draft when a new model is created so saveNewVersion() can persist it
|
|
2410
2679
|
try {
|
|
2411
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2680
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
|
|
2412
2681
|
const { Schema } = schemaMod;
|
|
2413
2682
|
const schema = Schema.create(schemaName, { waitForReady: false });
|
|
2414
2683
|
schema.getService().send({ type: 'markAsDraft', propertyKey: 'schema:models' });
|
|
@@ -2452,10 +2721,10 @@ const validateModel = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
2452
2721
|
const _validateModel = async () => {
|
|
2453
2722
|
try {
|
|
2454
2723
|
// Use dynamic imports to break circular dependencies
|
|
2455
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
2724
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
|
|
2456
2725
|
const { SchemaValidationService } = validationServiceMod;
|
|
2457
2726
|
const validationService = new SchemaValidationService();
|
|
2458
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2727
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
|
|
2459
2728
|
const { Schema } = schemaMod;
|
|
2460
2729
|
// Validate model structure
|
|
2461
2730
|
const structureResult = validationService.validateModelStructure(context);
|
|
@@ -2565,7 +2834,7 @@ const createModelProperties = xstate.fromCallback(({ sendBack, input }) => {
|
|
|
2565
2834
|
return;
|
|
2566
2835
|
}
|
|
2567
2836
|
logger$w(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
|
|
2568
|
-
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-
|
|
2837
|
+
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); });
|
|
2569
2838
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
2570
2839
|
if (!ModelProperty) {
|
|
2571
2840
|
logger$w('ModelProperty not available from dynamic import');
|
|
@@ -2669,7 +2938,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2669
2938
|
const structureMsg = `[validateEntity] Validating model structure`;
|
|
2670
2939
|
logger$v(structureMsg);
|
|
2671
2940
|
// Use existing Model validation
|
|
2672
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
2941
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
|
|
2673
2942
|
const { SchemaValidationService } = validationServiceMod;
|
|
2674
2943
|
const validationService = new SchemaValidationService();
|
|
2675
2944
|
// Validate model structure
|
|
@@ -2687,7 +2956,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2687
2956
|
if (entityInput.entityData.schemaName) {
|
|
2688
2957
|
try {
|
|
2689
2958
|
logger$v(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
|
|
2690
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2959
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
|
|
2691
2960
|
const { Schema } = schemaMod;
|
|
2692
2961
|
const schema = Schema.create(entityInput.entityData.schemaName, {
|
|
2693
2962
|
waitForReady: false,
|
|
@@ -2723,7 +2992,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2723
2992
|
}
|
|
2724
2993
|
else if (entityInput.entityType === 'modelProperty') {
|
|
2725
2994
|
// Use existing ModelProperty validation
|
|
2726
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
2995
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
|
|
2727
2996
|
const { SchemaValidationService } = validationServiceMod;
|
|
2728
2997
|
const validationService = new SchemaValidationService();
|
|
2729
2998
|
// Validate property structure
|
|
@@ -2738,7 +3007,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2738
3007
|
// If schema name and model name provided, validate against schema
|
|
2739
3008
|
if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
|
|
2740
3009
|
try {
|
|
2741
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
3010
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
|
|
2742
3011
|
const { Schema } = schemaMod;
|
|
2743
3012
|
const schema = Schema.create(entityInput.entityData._schemaName, {
|
|
2744
3013
|
waitForReady: false,
|
|
@@ -2767,7 +3036,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2767
3036
|
}
|
|
2768
3037
|
else if (entityInput.entityType === 'schema') {
|
|
2769
3038
|
// Schema validation - use existing validation
|
|
2770
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
3039
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
|
|
2771
3040
|
const { SchemaValidationService } = validationServiceMod;
|
|
2772
3041
|
const validationService = new SchemaValidationService();
|
|
2773
3042
|
const schemaResult = validationService.validateSchema(entityInput.entityData);
|
|
@@ -4719,7 +4988,7 @@ const writeToDatabase = xstate.fromCallback(({ sendBack, input }) => {
|
|
|
4719
4988
|
// initial write completes is not overwritten by the stale requestWrite payload.
|
|
4720
4989
|
let dataToWrite = input.entityData;
|
|
4721
4990
|
try {
|
|
4722
|
-
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-
|
|
4991
|
+
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); });
|
|
4723
4992
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
4724
4993
|
if (ModelProperty && typeof ModelProperty.getById === 'function') {
|
|
4725
4994
|
const instance = ModelProperty.getById(input.entityId);
|
|
@@ -5099,7 +5368,7 @@ const modelMachine = xstate.setup({
|
|
|
5099
5368
|
// Create ModelProperty instances for any new property IDs
|
|
5100
5369
|
if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
|
|
5101
5370
|
// Import and create instances asynchronously (fire-and-forget)
|
|
5102
|
-
Promise.resolve().then(function () { return require('./ModelProperty-
|
|
5371
|
+
Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); }).then(({ ModelProperty }) => {
|
|
5103
5372
|
const createPromises = newPropertyIds.map(async (propertyFileId) => {
|
|
5104
5373
|
try {
|
|
5105
5374
|
const property = await ModelProperty.createById(propertyFileId);
|
|
@@ -5402,6 +5671,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
|
|
|
5402
5671
|
var MachineIds;
|
|
5403
5672
|
(function (MachineIds) {
|
|
5404
5673
|
MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
|
|
5674
|
+
MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
|
|
5405
5675
|
MachineIds["GLOBAL"] = "@seedSdk/global";
|
|
5406
5676
|
MachineIds["INTERNAL"] = "@seedSdk/internal";
|
|
5407
5677
|
MachineIds["EAS"] = "@seedSdk/eas";
|
|
@@ -5474,7 +5744,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
|
|
|
5474
5744
|
* This constant is kept for backward compatibility but will be removed in a future version.
|
|
5475
5745
|
* Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
|
|
5476
5746
|
*/
|
|
5477
|
-
ENV.NEXT_PUBLIC_ARWEAVE_HOST || '
|
|
5747
|
+
ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
|
|
5478
5748
|
|
|
5479
5749
|
debug('seedSdk:item:service:actors:waitForDb');
|
|
5480
5750
|
const waitForDb$1 = xstate.fromCallback(({ sendBack }) => {
|
|
@@ -6357,7 +6627,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
|
|
|
6357
6627
|
rowNum: drizzleOrm.sql.raw(`
|
|
6358
6628
|
ROW_NUMBER() OVER (
|
|
6359
6629
|
PARTITION BY property_name
|
|
6360
|
-
ORDER BY COALESCE(attestation_created_at, created_at) DESC
|
|
6630
|
+
ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
|
|
6361
6631
|
)
|
|
6362
6632
|
`).as('rowNum')
|
|
6363
6633
|
})
|
|
@@ -6370,6 +6640,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
|
|
|
6370
6640
|
getMetadataLatest: getMetadataLatest
|
|
6371
6641
|
});
|
|
6372
6642
|
|
|
6643
|
+
/**
|
|
6644
|
+
* Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
|
|
6645
|
+
* `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
|
|
6646
|
+
*/
|
|
6647
|
+
function metadataLatestFirstSortKey(row) {
|
|
6648
|
+
return {
|
|
6649
|
+
t: row.attestationCreatedAt ?? row.createdAt ?? 0,
|
|
6650
|
+
localId: String(row.localId ?? ''),
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
/** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
|
|
6654
|
+
function compareMetadataRowsLatestFirst(a, b) {
|
|
6655
|
+
const ka = metadataLatestFirstSortKey(a);
|
|
6656
|
+
const kb = metadataLatestFirstSortKey(b);
|
|
6657
|
+
if (kb.t !== ka.t)
|
|
6658
|
+
return kb.t - ka.t;
|
|
6659
|
+
return kb.localId.localeCompare(ka.localId);
|
|
6660
|
+
}
|
|
6661
|
+
|
|
6373
6662
|
const logger$q = debug('seedSdk:item:actors:loadOrCreateItem');
|
|
6374
6663
|
/**
|
|
6375
6664
|
* Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
|
|
@@ -6411,9 +6700,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
|
|
|
6411
6700
|
return b;
|
|
6412
6701
|
if (sa !== sb)
|
|
6413
6702
|
return sa > sb ? a : b;
|
|
6414
|
-
const
|
|
6415
|
-
|
|
6416
|
-
return ta >= tb ? a : b;
|
|
6703
|
+
const cmp = compareMetadataRowsLatestFirst(a, b);
|
|
6704
|
+
return cmp < 0 ? a : b;
|
|
6417
6705
|
}
|
|
6418
6706
|
function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
|
|
6419
6707
|
const byKey = new Map();
|
|
@@ -6461,7 +6749,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6461
6749
|
const schemaNameToTry = model$1?.schemaName;
|
|
6462
6750
|
if (schemaNameToTry) {
|
|
6463
6751
|
try {
|
|
6464
|
-
const { Schema } = await Promise.resolve().then(function () { return require('./Schema-
|
|
6752
|
+
const { Schema } = await Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); });
|
|
6465
6753
|
const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
|
|
6466
6754
|
const schemaContext = schemaInstance.getService().getSnapshot().context;
|
|
6467
6755
|
if (schemaContext.models?.[modelName]?.properties) {
|
|
@@ -6510,7 +6798,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6510
6798
|
}
|
|
6511
6799
|
}
|
|
6512
6800
|
if (Object.keys(propertySchemas).length === 0) {
|
|
6513
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
6801
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
6514
6802
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
6515
6803
|
const KNOWN_MODEL_FALLBACKS = {
|
|
6516
6804
|
Post: {
|
|
@@ -6557,7 +6845,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6557
6845
|
// Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
|
|
6558
6846
|
let propSchema = propertySchemas[propertyName];
|
|
6559
6847
|
if (!propSchema && isRefTypeFromMeta) {
|
|
6560
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
6848
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
6561
6849
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
6562
6850
|
propSchema = {
|
|
6563
6851
|
dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
|
|
@@ -6814,9 +7102,9 @@ const runPublish = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
|
6814
7102
|
sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
|
|
6815
7103
|
return;
|
|
6816
7104
|
}
|
|
6817
|
-
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-
|
|
7105
|
+
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-CMpPR2JJ.js'); });
|
|
6818
7106
|
const { getPublishUploads } = getPublishUploadsMod;
|
|
6819
|
-
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-
|
|
7107
|
+
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-C0hWIYCX.js'); });
|
|
6820
7108
|
const { getPublishPayload } = getPublishPayloadMod;
|
|
6821
7109
|
const uploads = await getPublishUploads(item);
|
|
6822
7110
|
let uploadedTransactions = [];
|
|
@@ -7162,6 +7450,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
|
|
|
7162
7450
|
return rows[0];
|
|
7163
7451
|
};
|
|
7164
7452
|
|
|
7453
|
+
var getSeedData$1 = /*#__PURE__*/Object.freeze({
|
|
7454
|
+
__proto__: null,
|
|
7455
|
+
getSeedData: getSeedData
|
|
7456
|
+
});
|
|
7457
|
+
|
|
7165
7458
|
/**
|
|
7166
7459
|
* Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
|
|
7167
7460
|
* Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
|
|
@@ -7651,7 +7944,7 @@ const resolveRelatedValue = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
7651
7944
|
const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
|
|
7652
7945
|
const _resolveRelatedValue = async () => {
|
|
7653
7946
|
// Use dynamic import to break circular dependency
|
|
7654
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
7947
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
7655
7948
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
7656
7949
|
if (!propertyValue || !isRelation || populatedFromDb) {
|
|
7657
7950
|
return;
|
|
@@ -8014,174 +8307,864 @@ function parseListPropertyValueFromStorage(raw) {
|
|
|
8014
8307
|
return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
|
|
8015
8308
|
}
|
|
8016
8309
|
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
8021
|
-
const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
|
|
8022
|
-
if (!propertyNameRaw) {
|
|
8023
|
-
throw new Error('propertyName is required');
|
|
8310
|
+
class SeedEventEmitter {
|
|
8311
|
+
constructor() {
|
|
8312
|
+
this.listeners = new Map();
|
|
8024
8313
|
}
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
const firstRow = rows[0];
|
|
8068
|
-
const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
|
|
8069
|
-
let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
|
|
8070
|
-
let propertyValueProcessed = propertyValueFromDb;
|
|
8071
|
-
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
8072
|
-
if (isImageDynamic) {
|
|
8073
|
-
let dir = localStorageDir;
|
|
8074
|
-
if (!dir && isImageDynamic) {
|
|
8075
|
-
dir = 'images';
|
|
8076
|
-
}
|
|
8077
|
-
dir = dir.replace(/^\//, '');
|
|
8078
|
-
if (propertyValueFromDb &&
|
|
8079
|
-
propertyValueFromDb.length === 66) {
|
|
8080
|
-
// Here the storageTransactionId is stored on a different record and
|
|
8081
|
-
// we want to add it as the refResolvedValue
|
|
8082
|
-
const storageTransactionQuery = await appDb
|
|
8083
|
-
.select({
|
|
8084
|
-
propertyValue: metadata$1.propertyValue,
|
|
8085
|
-
})
|
|
8086
|
-
.from(metadata$1)
|
|
8087
|
-
.where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, propertyValueFromDb), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))));
|
|
8088
|
-
if (storageTransactionQuery && storageTransactionQuery.length > 0) {
|
|
8089
|
-
const row = storageTransactionQuery[0];
|
|
8090
|
-
refResolvedValue = row.propertyValue;
|
|
8091
|
-
await updateMetadata({
|
|
8092
|
-
localId,
|
|
8093
|
-
refResolvedValue,
|
|
8094
|
-
localStorageDir: '/images',
|
|
8095
|
-
});
|
|
8096
|
-
}
|
|
8097
|
-
}
|
|
8098
|
-
if (refResolvedValue) {
|
|
8099
|
-
try {
|
|
8100
|
-
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
8101
|
-
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
8102
|
-
if (dirExists) {
|
|
8103
|
-
const fs = await BaseFileManager.getFs();
|
|
8104
|
-
const path = BaseFileManager.getPathModule();
|
|
8105
|
-
const files = await fs.promises.readdir(dirPath);
|
|
8106
|
-
const matchingFiles = files.filter((file) => {
|
|
8107
|
-
return path.basename(file).includes(refResolvedValue);
|
|
8108
|
-
});
|
|
8109
|
-
let fileExists = false;
|
|
8110
|
-
let filename;
|
|
8111
|
-
let filePath;
|
|
8112
|
-
if (matchingFiles && matchingFiles.length > 0) {
|
|
8113
|
-
fileExists = true;
|
|
8114
|
-
filename = matchingFiles[0];
|
|
8115
|
-
filePath = BaseFileManager.getFilesPath(dir, filename);
|
|
8116
|
-
}
|
|
8117
|
-
localStorageDir = `/${dir}`;
|
|
8118
|
-
if (fileExists && filename && filePath) {
|
|
8119
|
-
const file = await BaseFileManager.readFile(filePath);
|
|
8120
|
-
refResolvedDisplayValue = URL.createObjectURL(file);
|
|
8121
|
-
// Do not persist blob URL - it is session-scoped
|
|
8122
|
-
}
|
|
8123
|
-
}
|
|
8124
|
-
}
|
|
8125
|
-
catch (e) {
|
|
8126
|
-
logger$l('[hydrateFromDb] Image file resolution error', e);
|
|
8127
|
-
}
|
|
8128
|
-
}
|
|
8129
|
-
}
|
|
8130
|
-
if (propertyRecordSchema &&
|
|
8131
|
-
normalizedDataType === ModelPropertyDataTypes.List &&
|
|
8132
|
-
typeof propertyValueFromDb === 'string') {
|
|
8133
|
-
propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
|
|
8314
|
+
on(event, listener) {
|
|
8315
|
+
const set = this.listeners.get(event) ?? new Set();
|
|
8316
|
+
set.add(listener);
|
|
8317
|
+
this.listeners.set(event, set);
|
|
8318
|
+
return this;
|
|
8319
|
+
}
|
|
8320
|
+
addListener(event, listener) {
|
|
8321
|
+
return this.on(event, listener);
|
|
8322
|
+
}
|
|
8323
|
+
once(event, listener) {
|
|
8324
|
+
const wrapped = (...args) => {
|
|
8325
|
+
this.off(event, wrapped);
|
|
8326
|
+
listener(...args);
|
|
8327
|
+
};
|
|
8328
|
+
return this.on(event, wrapped);
|
|
8329
|
+
}
|
|
8330
|
+
off(event, listener) {
|
|
8331
|
+
const set = this.listeners.get(event);
|
|
8332
|
+
if (!set)
|
|
8333
|
+
return this;
|
|
8334
|
+
set.delete(listener);
|
|
8335
|
+
if (set.size === 0)
|
|
8336
|
+
this.listeners.delete(event);
|
|
8337
|
+
return this;
|
|
8338
|
+
}
|
|
8339
|
+
removeListener(event, listener) {
|
|
8340
|
+
return this.off(event, listener);
|
|
8341
|
+
}
|
|
8342
|
+
removeAllListeners(event) {
|
|
8343
|
+
if (typeof event === 'undefined') {
|
|
8344
|
+
this.listeners.clear();
|
|
8345
|
+
return this;
|
|
8346
|
+
}
|
|
8347
|
+
this.listeners.delete(event);
|
|
8348
|
+
return this;
|
|
8349
|
+
}
|
|
8350
|
+
emit(event, ...args) {
|
|
8351
|
+
const set = this.listeners.get(event);
|
|
8352
|
+
if (!set || set.size === 0)
|
|
8353
|
+
return false;
|
|
8354
|
+
for (const listener of [...set]) {
|
|
8355
|
+
listener(...args);
|
|
8134
8356
|
}
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8357
|
+
return true;
|
|
8358
|
+
}
|
|
8359
|
+
}
|
|
8360
|
+
const eventEmitter = new SeedEventEmitter();
|
|
8361
|
+
|
|
8362
|
+
const GET_FILES_METADATA = graphql(/* GraphQL */ `
|
|
8363
|
+
query GetFilesMetadata($where: AttestationWhereInput!) {
|
|
8364
|
+
filesMetadata: attestations(
|
|
8365
|
+
where: $where
|
|
8366
|
+
orderBy: [{ timeCreated: desc }]
|
|
8367
|
+
) {
|
|
8368
|
+
...attestationFields
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
`);
|
|
8372
|
+
|
|
8373
|
+
const getMetadata = async (props) => {
|
|
8374
|
+
const appDb = BaseDb.getAppDb();
|
|
8375
|
+
let storageTransactionId;
|
|
8376
|
+
if (props) {
|
|
8377
|
+
storageTransactionId = props.storageTransactionId;
|
|
8378
|
+
}
|
|
8379
|
+
const whereClauses = [];
|
|
8380
|
+
if (storageTransactionId) {
|
|
8381
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'));
|
|
8382
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.propertyValue, storageTransactionId));
|
|
8383
|
+
}
|
|
8384
|
+
const metadataRows = await appDb
|
|
8385
|
+
.select()
|
|
8386
|
+
.from(metadata$1)
|
|
8387
|
+
.where(drizzleOrm.and(...whereClauses));
|
|
8388
|
+
if (!metadataRows || metadataRows.length === 0) {
|
|
8389
|
+
return;
|
|
8390
|
+
}
|
|
8391
|
+
return metadataRows[0];
|
|
8392
|
+
};
|
|
8393
|
+
|
|
8394
|
+
const saveMetadata = async (metadataRecord, metadataValues) => {
|
|
8395
|
+
if (!metadataRecord.localId) {
|
|
8396
|
+
return;
|
|
8397
|
+
}
|
|
8398
|
+
const appDb = BaseDb.getAppDb();
|
|
8399
|
+
await appDb
|
|
8400
|
+
.update(metadata$1)
|
|
8401
|
+
.set({
|
|
8402
|
+
...metadataValues,
|
|
8403
|
+
updatedAt: Date.now(),
|
|
8404
|
+
})
|
|
8405
|
+
.where(drizzleOrm.eq(metadata$1.localId, metadataRecord.localId));
|
|
8406
|
+
};
|
|
8407
|
+
|
|
8408
|
+
const isNode = () => {
|
|
8409
|
+
return (typeof process !== 'undefined' &&
|
|
8410
|
+
process.versions != null &&
|
|
8411
|
+
process.versions.node != null);
|
|
8412
|
+
};
|
|
8413
|
+
const isBrowser = () => {
|
|
8414
|
+
return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
|
|
8415
|
+
};
|
|
8416
|
+
const isElectron = () => {
|
|
8417
|
+
return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
|
|
8418
|
+
};
|
|
8419
|
+
/**
|
|
8420
|
+
* Detects if code is running in an Electron renderer process.
|
|
8421
|
+
*
|
|
8422
|
+
* Uses multiple detection methods for robustness:
|
|
8423
|
+
* 1. Checks process.type === 'renderer' (most reliable)
|
|
8424
|
+
* 2. Falls back to checking if Electron is present and window/document exist
|
|
8425
|
+
*
|
|
8426
|
+
* @returns true if running in Electron renderer process, false otherwise
|
|
8427
|
+
*/
|
|
8428
|
+
const isElectronRenderer = () => {
|
|
8429
|
+
// Method 1: Check process.type (most reliable - official Electron API)
|
|
8430
|
+
if (typeof process !== 'undefined' &&
|
|
8431
|
+
process.type === 'renderer') {
|
|
8432
|
+
return true;
|
|
8433
|
+
}
|
|
8434
|
+
// Method 2: Fallback - Electron + browser-like environment
|
|
8435
|
+
// Renderer processes have window/document, main process doesn't (in modern Electron)
|
|
8436
|
+
if (isElectron() &&
|
|
8437
|
+
typeof window !== 'undefined' &&
|
|
8438
|
+
typeof document !== 'undefined') {
|
|
8439
|
+
return true;
|
|
8440
|
+
}
|
|
8441
|
+
return false;
|
|
8442
|
+
};
|
|
8443
|
+
/**
|
|
8444
|
+
* True where OPFS-backed Arweave file downloads should run: normal browsers and
|
|
8445
|
+
* Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
|
|
8446
|
+
*/
|
|
8447
|
+
const supportsOpfsFileDownloads = () => {
|
|
8448
|
+
return isBrowser() || isElectronRenderer();
|
|
8449
|
+
};
|
|
8450
|
+
|
|
8451
|
+
const logger$l = debug('seedSdk:files:download');
|
|
8452
|
+
const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
|
|
8453
|
+
/** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
|
|
8454
|
+
const GET_FILES_METADATA_STALE_MS = 120000;
|
|
8455
|
+
let bulkDownloadInFlight = null;
|
|
8456
|
+
const lazyDownloadInFlightByTransactionId = new Map();
|
|
8457
|
+
// syncDbFiles helper - internal service removed, functionality moved here
|
|
8458
|
+
const syncDbFiles = async (endpoints) => {
|
|
8459
|
+
// TODO: Implement syncDbFiles functionality if needed
|
|
8460
|
+
// This was previously in @/services/internal/helpers
|
|
8461
|
+
logger$l('[download] syncDbFiles called but not yet implemented');
|
|
8462
|
+
return Promise.resolve();
|
|
8463
|
+
};
|
|
8464
|
+
const getAppDbReady = async () => {
|
|
8465
|
+
if (!BaseDb.isAppDbReady()) {
|
|
8466
|
+
// Wait for ClientManager to be ready (DB_INIT state or later)
|
|
8467
|
+
const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
|
|
8468
|
+
const { getClient } = clientManagerMod;
|
|
8469
|
+
const clientManager = getClient();
|
|
8470
|
+
const clientService = clientManager.getService();
|
|
8471
|
+
await xstate.waitFor(clientService, (snapshot) => {
|
|
8472
|
+
const state = snapshot.value;
|
|
8473
|
+
return state === 'dbInit' ||
|
|
8474
|
+
state === 'saveConfig' ||
|
|
8475
|
+
state === 'processSchemaFiles' ||
|
|
8476
|
+
state === 'addModelsToStore' ||
|
|
8477
|
+
state === 'addModelsToDb' ||
|
|
8478
|
+
state === 'idle';
|
|
8479
|
+
}, { timeout: 30000 });
|
|
8480
|
+
}
|
|
8481
|
+
return BaseDb.getAppDb();
|
|
8482
|
+
};
|
|
8483
|
+
const getExcludedTransactions = async () => {
|
|
8484
|
+
const appDb = await getAppDbReady();
|
|
8485
|
+
if (!appDb) {
|
|
8486
|
+
return new Set();
|
|
8487
|
+
}
|
|
8488
|
+
const excludedTransactionsQuery = await appDb
|
|
8489
|
+
.select()
|
|
8490
|
+
.from(appState)
|
|
8491
|
+
.where(drizzleOrm.eq(appState.key, 'excludedTransactions'));
|
|
8492
|
+
const excludedTransactions = new Set();
|
|
8493
|
+
if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
|
|
8494
|
+
const valueString = excludedTransactionsQuery[0].value;
|
|
8495
|
+
if (valueString) {
|
|
8496
|
+
const excludedTransactionsArray = JSON.parse(valueString);
|
|
8497
|
+
for (const txId of excludedTransactionsArray) {
|
|
8498
|
+
excludedTransactions.add(txId);
|
|
8499
|
+
}
|
|
8500
|
+
}
|
|
8501
|
+
}
|
|
8502
|
+
return excludedTransactions;
|
|
8503
|
+
};
|
|
8504
|
+
/** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
|
|
8505
|
+
const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
|
|
8506
|
+
const normalizeArweaveTxId = (raw) => {
|
|
8507
|
+
if (raw == null || raw === '')
|
|
8508
|
+
return undefined;
|
|
8509
|
+
const t = String(raw).trim();
|
|
8510
|
+
if (ARWEAVE_TX_ID_RE.test(t))
|
|
8511
|
+
return t;
|
|
8512
|
+
const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
|
|
8513
|
+
if (m)
|
|
8514
|
+
return m[1];
|
|
8515
|
+
// Values may be full gateway URLs or paths; scan for the embedded tx id.
|
|
8516
|
+
const embedded = t.match(/[a-z0-9_-]{43}/gi);
|
|
8517
|
+
if (embedded) {
|
|
8518
|
+
for (const candidate of embedded) {
|
|
8519
|
+
if (ARWEAVE_TX_ID_RE.test(candidate))
|
|
8520
|
+
return candidate;
|
|
8521
|
+
}
|
|
8522
|
+
}
|
|
8523
|
+
return undefined;
|
|
8524
|
+
};
|
|
8525
|
+
const mergeAddressLists = (a, b) => {
|
|
8526
|
+
const seen = new Set();
|
|
8527
|
+
const out = [];
|
|
8528
|
+
for (const addr of [...(a ?? []), ...(b ?? [])]) {
|
|
8529
|
+
if (!addr || !addr.trim())
|
|
8530
|
+
continue;
|
|
8531
|
+
const k = addr.toLowerCase();
|
|
8532
|
+
if (seen.has(k))
|
|
8533
|
+
continue;
|
|
8534
|
+
seen.add(k);
|
|
8535
|
+
out.push(addr);
|
|
8536
|
+
}
|
|
8537
|
+
return out;
|
|
8538
|
+
};
|
|
8539
|
+
const collectTransactionIdsFromLocalMetadata = async () => {
|
|
8540
|
+
const appDb = await getAppDbReady();
|
|
8541
|
+
if (!appDb) {
|
|
8542
|
+
return [];
|
|
8543
|
+
}
|
|
8544
|
+
const nameOr = drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'storage_transaction_id'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'));
|
|
8545
|
+
const propRows = await appDb
|
|
8546
|
+
.select({ propertyValue: metadata$1.propertyValue })
|
|
8547
|
+
.from(metadata$1)
|
|
8548
|
+
.where(drizzleOrm.and(nameOr, drizzleOrm.isNotNull(metadata$1.propertyValue)));
|
|
8549
|
+
const refRows = await appDb
|
|
8550
|
+
.select({ refResolvedValue: metadata$1.refResolvedValue })
|
|
8551
|
+
.from(metadata$1)
|
|
8552
|
+
.where(drizzleOrm.isNotNull(metadata$1.refResolvedValue));
|
|
8553
|
+
const ids = new Set();
|
|
8554
|
+
for (const row of propRows) {
|
|
8555
|
+
const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
|
|
8556
|
+
if (id)
|
|
8557
|
+
ids.add(id);
|
|
8558
|
+
}
|
|
8559
|
+
for (const row of refRows) {
|
|
8560
|
+
const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
|
|
8561
|
+
if (id)
|
|
8562
|
+
ids.add(id);
|
|
8563
|
+
}
|
|
8564
|
+
return Array.from(ids);
|
|
8565
|
+
};
|
|
8566
|
+
const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
|
|
8567
|
+
const transactionIds = [];
|
|
8568
|
+
for (const fileMetadata of filesMetadata) {
|
|
8569
|
+
// Validate and parse decodedDataJson
|
|
8570
|
+
if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
|
|
8571
|
+
console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
|
|
8572
|
+
continue;
|
|
8573
|
+
}
|
|
8574
|
+
let json;
|
|
8575
|
+
try {
|
|
8576
|
+
json = JSON.parse(fileMetadata.decodedDataJson);
|
|
8577
|
+
}
|
|
8578
|
+
catch (error) {
|
|
8579
|
+
console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
|
|
8580
|
+
continue;
|
|
8581
|
+
}
|
|
8582
|
+
if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
|
|
8583
|
+
console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
|
|
8584
|
+
continue;
|
|
8585
|
+
}
|
|
8586
|
+
const rawTx = json[0].value.value;
|
|
8587
|
+
if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
|
|
8588
|
+
continue;
|
|
8589
|
+
}
|
|
8590
|
+
const transactionId = normalizeArweaveTxId(rawTx.trim());
|
|
8591
|
+
if (!transactionId) {
|
|
8592
|
+
continue;
|
|
8593
|
+
}
|
|
8594
|
+
if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
|
|
8595
|
+
continue;
|
|
8596
|
+
}
|
|
8597
|
+
transactionIds.push(transactionId);
|
|
8598
|
+
}
|
|
8599
|
+
return transactionIds;
|
|
8600
|
+
};
|
|
8601
|
+
const downloadTransactionIds = async (rawTransactionIds, options) => {
|
|
8602
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8603
|
+
return false;
|
|
8604
|
+
}
|
|
8605
|
+
const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
|
|
8606
|
+
if (transactionIds.length === 0) {
|
|
8607
|
+
return false;
|
|
8608
|
+
}
|
|
8609
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
8610
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
8611
|
+
const transactionIdsToDownload = [];
|
|
8612
|
+
await ensureReadGatewaySelected();
|
|
8613
|
+
for (const transactionId of transactionIds) {
|
|
8614
|
+
if (excludedTransactions.has(transactionId)) {
|
|
8615
|
+
continue;
|
|
8616
|
+
}
|
|
8617
|
+
try {
|
|
8618
|
+
// Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
|
|
8619
|
+
// CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
|
|
8620
|
+
let tags = [];
|
|
8621
|
+
try {
|
|
8622
|
+
tags = await queryClient.fetchQuery({
|
|
8623
|
+
queryKey: ['getTransactionTags', transactionId],
|
|
8624
|
+
queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
|
|
8625
|
+
});
|
|
8626
|
+
}
|
|
8627
|
+
catch {
|
|
8628
|
+
tags = [];
|
|
8629
|
+
}
|
|
8630
|
+
if (tags && tags.length > 0) {
|
|
8631
|
+
for (const { name, value } of tags) {
|
|
8632
|
+
if (name !== 'Content-SHA-256')
|
|
8633
|
+
continue;
|
|
8634
|
+
const metadataRecord = await getMetadata({
|
|
8635
|
+
storageTransactionId: transactionId,
|
|
8636
|
+
});
|
|
8637
|
+
if (metadataRecord) {
|
|
8638
|
+
await saveMetadata(metadataRecord, {
|
|
8639
|
+
contentHash: value,
|
|
8640
|
+
});
|
|
8641
|
+
}
|
|
8642
|
+
}
|
|
8643
|
+
}
|
|
8644
|
+
transactionIdsToDownload.push(transactionId);
|
|
8645
|
+
}
|
|
8646
|
+
catch (error) {
|
|
8647
|
+
logger$l(error);
|
|
8648
|
+
}
|
|
8649
|
+
}
|
|
8650
|
+
if (transactionIdsToDownload.length === 0) {
|
|
8651
|
+
return false;
|
|
8652
|
+
}
|
|
8653
|
+
if (transactionIdsToDownload.length === 1) {
|
|
8654
|
+
await BaseFileManager.downloadFileByTransactionId({
|
|
8655
|
+
transactionId: transactionIdsToDownload[0],
|
|
8656
|
+
arweaveHost: BaseArweaveClient.getHost(),
|
|
8657
|
+
excludedTransactions,
|
|
8658
|
+
});
|
|
8659
|
+
}
|
|
8660
|
+
else {
|
|
8661
|
+
await BaseFileManager.downloadAllFiles({
|
|
8662
|
+
transactionIds: transactionIdsToDownload,
|
|
8663
|
+
arweaveHost: BaseArweaveClient.getHost(),
|
|
8664
|
+
excludedTransactions,
|
|
8665
|
+
});
|
|
8666
|
+
}
|
|
8667
|
+
if (options?.resizeAllImages !== false) {
|
|
8668
|
+
await BaseFileManager.resizeAllImages({
|
|
8669
|
+
width: 480,
|
|
8670
|
+
height: 480,
|
|
8671
|
+
});
|
|
8672
|
+
}
|
|
8673
|
+
return true;
|
|
8674
|
+
};
|
|
8675
|
+
const runBulkDownloadWithDedupe = async (transactionIds) => {
|
|
8676
|
+
if (bulkDownloadInFlight) {
|
|
8677
|
+
return bulkDownloadInFlight;
|
|
8678
|
+
}
|
|
8679
|
+
bulkDownloadInFlight = (async () => {
|
|
8680
|
+
try {
|
|
8681
|
+
await downloadTransactionIds(transactionIds, { resizeAllImages: true });
|
|
8682
|
+
}
|
|
8683
|
+
finally {
|
|
8684
|
+
bulkDownloadInFlight = null;
|
|
8685
|
+
}
|
|
8686
|
+
})();
|
|
8687
|
+
return bulkDownloadInFlight;
|
|
8688
|
+
};
|
|
8689
|
+
const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
|
|
8690
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8691
|
+
return;
|
|
8692
|
+
}
|
|
8693
|
+
await syncDbFiles();
|
|
8694
|
+
eventEmitter.emit('fs.downloadAll.success', { eventId });
|
|
8695
|
+
eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
|
|
8696
|
+
};
|
|
8697
|
+
const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
|
|
8698
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8699
|
+
return;
|
|
8700
|
+
}
|
|
8701
|
+
const addressesHint = Array.isArray(addressesHintOrPayload)
|
|
8702
|
+
? addressesHintOrPayload
|
|
8703
|
+
: undefined;
|
|
8704
|
+
let fromDb = [];
|
|
8705
|
+
if (BaseDb.isAppDbReady()) {
|
|
8706
|
+
fromDb = await getAllAddressesFromDb();
|
|
8707
|
+
}
|
|
8708
|
+
if (!BaseDb.isAppDbReady()) {
|
|
8709
|
+
await getAppDbReady();
|
|
8710
|
+
fromDb = await getAllAddressesFromDb();
|
|
8711
|
+
}
|
|
8712
|
+
const addresses = mergeAddressLists(addressesHint, fromDb);
|
|
8713
|
+
if (!addresses || addresses.length === 0) {
|
|
8714
|
+
return;
|
|
8715
|
+
}
|
|
8716
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
8717
|
+
const easClient = BaseEasClient.getEasClient();
|
|
8718
|
+
const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
|
|
8719
|
+
const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
|
|
8720
|
+
where: {
|
|
8721
|
+
attester: {
|
|
8722
|
+
in: addresses,
|
|
8723
|
+
},
|
|
8724
|
+
schema: {
|
|
8725
|
+
is: {
|
|
8726
|
+
id: {
|
|
8727
|
+
equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
|
|
8728
|
+
},
|
|
8729
|
+
},
|
|
8730
|
+
},
|
|
8731
|
+
},
|
|
8732
|
+
});
|
|
8733
|
+
let { filesMetadata } = await queryClient.fetchQuery({
|
|
8734
|
+
queryKey: filesMetadataQueryKey,
|
|
8735
|
+
queryFn: fetchFilesMetadata,
|
|
8736
|
+
staleTime: GET_FILES_METADATA_STALE_MS,
|
|
8737
|
+
});
|
|
8738
|
+
if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
|
|
8739
|
+
await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
|
|
8740
|
+
({ filesMetadata } = await queryClient.fetchQuery({
|
|
8741
|
+
queryKey: filesMetadataQueryKey,
|
|
8742
|
+
queryFn: fetchFilesMetadata,
|
|
8743
|
+
staleTime: GET_FILES_METADATA_STALE_MS,
|
|
8744
|
+
}));
|
|
8745
|
+
}
|
|
8746
|
+
const filesRoot = BaseFileManager.getWorkingDir();
|
|
8747
|
+
await BaseFileManager.createDirIfNotExists(filesRoot);
|
|
8748
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
|
|
8749
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
|
|
8750
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
|
|
8751
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
8752
|
+
const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
|
|
8753
|
+
const fromLocal = await collectTransactionIdsFromLocalMetadata();
|
|
8754
|
+
const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
|
|
8755
|
+
await runBulkDownloadWithDedupe(transactionIds);
|
|
8756
|
+
};
|
|
8757
|
+
const downloadTransactionIdWithDedupe = async (transactionId) => {
|
|
8758
|
+
if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
|
|
8759
|
+
return false;
|
|
8760
|
+
}
|
|
8761
|
+
const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
|
|
8762
|
+
const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
|
|
8763
|
+
if (existing) {
|
|
8764
|
+
return existing;
|
|
8765
|
+
}
|
|
8766
|
+
const inFlight = (async () => {
|
|
8767
|
+
try {
|
|
8768
|
+
const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
|
|
8769
|
+
return ok;
|
|
8770
|
+
}
|
|
8771
|
+
finally {
|
|
8772
|
+
lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
|
|
8773
|
+
}
|
|
8774
|
+
})();
|
|
8775
|
+
lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
|
|
8776
|
+
return inFlight;
|
|
8777
|
+
};
|
|
8778
|
+
const scheduleBulkFilesDownloadFromEasSyncThrottled = lodashEs.throttle((addressesHint) => {
|
|
8779
|
+
void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
|
|
8780
|
+
logger$l('[scheduleBulkFilesDownloadFromEasSync] failed', error);
|
|
8781
|
+
});
|
|
8782
|
+
}, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
|
|
8783
|
+
const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
|
|
8784
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8785
|
+
return;
|
|
8786
|
+
}
|
|
8787
|
+
scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
|
|
8788
|
+
};
|
|
8789
|
+
|
|
8790
|
+
var download = /*#__PURE__*/Object.freeze({
|
|
8791
|
+
__proto__: null,
|
|
8792
|
+
downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
|
|
8793
|
+
downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
|
|
8794
|
+
downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
|
|
8795
|
+
scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
|
|
8796
|
+
});
|
|
8797
|
+
|
|
8798
|
+
/** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
|
|
8799
|
+
const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
8800
|
+
/** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
|
|
8801
|
+
const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
|
|
8802
|
+
function extractArweaveTransactionId(raw) {
|
|
8803
|
+
const t = raw.trim();
|
|
8804
|
+
const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
|
|
8805
|
+
if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
|
|
8806
|
+
return embedded[0];
|
|
8807
|
+
}
|
|
8808
|
+
return t;
|
|
8809
|
+
}
|
|
8810
|
+
/**
|
|
8811
|
+
* GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
|
|
8812
|
+
* arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
|
|
8813
|
+
*/
|
|
8814
|
+
async function fetchHtmlViaRawAcrossGateways(txId) {
|
|
8815
|
+
const id = extractArweaveTransactionId(txId);
|
|
8816
|
+
if (!id || SEED_UID_HEX_RE.test(id))
|
|
8817
|
+
return undefined;
|
|
8818
|
+
try {
|
|
8819
|
+
const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
|
|
8820
|
+
await ensureReadGatewaySelected().catch(() => { });
|
|
8821
|
+
}
|
|
8822
|
+
catch {
|
|
8823
|
+
/* optional */
|
|
8824
|
+
}
|
|
8825
|
+
const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
|
|
8826
|
+
const protocol = BaseArweaveClient.getProtocol();
|
|
8827
|
+
const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
|
|
8828
|
+
for (const host of hosts) {
|
|
8829
|
+
const h = host.trim().replace(/\/$/, '');
|
|
8830
|
+
if (!h)
|
|
8831
|
+
continue;
|
|
8832
|
+
const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
|
|
8833
|
+
try {
|
|
8834
|
+
const res = await fetch(url, { method: 'GET', credentials: 'omit' });
|
|
8835
|
+
if (!res.ok)
|
|
8836
|
+
continue;
|
|
8837
|
+
const text = await res.text();
|
|
8838
|
+
if (typeof text === 'string' && text.length > 0) {
|
|
8839
|
+
return text;
|
|
8840
|
+
}
|
|
8841
|
+
}
|
|
8842
|
+
catch {
|
|
8843
|
+
/* next gateway */
|
|
8844
|
+
}
|
|
8845
|
+
}
|
|
8846
|
+
return undefined;
|
|
8847
|
+
}
|
|
8848
|
+
/**
|
|
8849
|
+
* Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
|
|
8850
|
+
* `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
|
|
8851
|
+
*/
|
|
8852
|
+
async function resolveHtmlStorageSeedLocalId(propertyValue) {
|
|
8853
|
+
const pv = String(propertyValue ?? '').trim();
|
|
8854
|
+
if (!pv)
|
|
8855
|
+
return undefined;
|
|
8856
|
+
if (SEED_UID_HEX_RE.test(pv)) {
|
|
8857
|
+
const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
|
|
8858
|
+
return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
|
|
8859
|
+
}
|
|
8860
|
+
return pv;
|
|
8861
|
+
}
|
|
8862
|
+
/**
|
|
8863
|
+
* When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
|
|
8864
|
+
* Html storage seed's published Arweave transaction id on that child seed.
|
|
8865
|
+
*/
|
|
8866
|
+
async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
|
|
8867
|
+
const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
|
|
8868
|
+
const pickTx = async (name) => {
|
|
8869
|
+
const row = await getPropertyData({ propertyName: name, seedLocalId });
|
|
8870
|
+
const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
|
|
8871
|
+
return v || undefined;
|
|
8872
|
+
};
|
|
8873
|
+
const txId = (await pickTx('storageTransactionId')) ??
|
|
8874
|
+
(await pickTx('transactionId')) ??
|
|
8875
|
+
(await pickTx('storage_transaction_id'));
|
|
8876
|
+
if (!txId || SEED_UID_HEX_RE.test(txId)) {
|
|
8877
|
+
return { txIdLen: 0, gatewayStringLen: 0 };
|
|
8878
|
+
}
|
|
8879
|
+
const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
|
|
8880
|
+
if (rawHtml && rawHtml.length > 0) {
|
|
8881
|
+
return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
|
|
8882
|
+
}
|
|
8883
|
+
try {
|
|
8884
|
+
const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
|
|
8885
|
+
const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
|
|
8886
|
+
string: true,
|
|
8887
|
+
});
|
|
8888
|
+
if (typeof data === 'string' && data.length > 0) {
|
|
8889
|
+
return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
|
|
8890
|
+
}
|
|
8891
|
+
}
|
|
8892
|
+
catch {
|
|
8893
|
+
/* offline / bad tx id */
|
|
8894
|
+
}
|
|
8895
|
+
try {
|
|
8896
|
+
const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
|
|
8897
|
+
await downloadTransactionIdWithDedupe(txId);
|
|
8898
|
+
const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
|
|
8899
|
+
if (await BaseFileManager.pathExists(retryFp)) {
|
|
8900
|
+
const s = await BaseFileManager.readFileAsString(retryFp);
|
|
8901
|
+
return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8902
|
+
}
|
|
8903
|
+
const dirPath = BaseFileManager.getFilesPath('html');
|
|
8904
|
+
if (await BaseFileManager.pathExists(dirPath)) {
|
|
8905
|
+
const fs = await BaseFileManager.getFs();
|
|
8906
|
+
const pathMod = BaseFileManager.getPathModule();
|
|
8907
|
+
const files = await fs.promises.readdir(dirPath);
|
|
8908
|
+
const needle = txId.replace(/\.[^/.]+$/, '');
|
|
8909
|
+
const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
|
|
8910
|
+
if (match) {
|
|
8911
|
+
const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
|
|
8912
|
+
return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8913
|
+
}
|
|
8914
|
+
}
|
|
8915
|
+
}
|
|
8916
|
+
catch {
|
|
8917
|
+
/* OPFS unsupported or download failed */
|
|
8918
|
+
}
|
|
8919
|
+
return { txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8920
|
+
}
|
|
8921
|
+
/** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
|
|
8922
|
+
async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
|
|
8923
|
+
const pv = String(propertyValue ?? '').trim();
|
|
8924
|
+
if (!pv)
|
|
8925
|
+
return undefined;
|
|
8926
|
+
const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
|
|
8927
|
+
const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
|
|
8928
|
+
let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
|
|
8929
|
+
// OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
|
|
8930
|
+
if (!fileExists && fp) {
|
|
8931
|
+
await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
|
|
8932
|
+
fileExists = await BaseFileManager.pathExists(fp);
|
|
8933
|
+
}
|
|
8934
|
+
let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
|
|
8935
|
+
if (!body && localId) {
|
|
8936
|
+
const ar = await readHtmlBodyFromChildStorageArweave(localId);
|
|
8937
|
+
body = ar.body;
|
|
8938
|
+
}
|
|
8939
|
+
return body;
|
|
8940
|
+
}
|
|
8941
|
+
|
|
8942
|
+
// Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
|
|
8943
|
+
// import { ModelPropertyDataTypes } from '@/schema'
|
|
8944
|
+
const logger$k = debug('seedSdk:property:actors:hydrateFromDb');
|
|
8945
|
+
const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
8946
|
+
const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
|
|
8947
|
+
if (!propertyNameRaw) {
|
|
8948
|
+
throw new Error('propertyName is required');
|
|
8949
|
+
}
|
|
8950
|
+
let propertyName = propertyNameRaw;
|
|
8951
|
+
// Note: isRelation, isImage, isFile checks moved inside async function
|
|
8952
|
+
// to use dynamically imported ModelPropertyDataTypes
|
|
8953
|
+
const _hydrateFromDb = async () => {
|
|
8954
|
+
// Use dynamic import to break circular dependency
|
|
8955
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
8956
|
+
const { ModelPropertyDataTypes } = schemaMod;
|
|
8957
|
+
const appDb = BaseDb.getAppDb();
|
|
8958
|
+
const whereClauses = [];
|
|
8959
|
+
// Re-check types with dynamically imported ModelPropertyDataTypes
|
|
8960
|
+
// Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
|
|
8961
|
+
const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
|
|
8962
|
+
const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
|
|
8963
|
+
propertyRecordSchema &&
|
|
8964
|
+
propertyRecordSchema.ref &&
|
|
8965
|
+
normalizedDataType === ModelPropertyDataTypes.Relation;
|
|
8966
|
+
const isImageDynamic = propertyRecordSchema &&
|
|
8967
|
+
(normalizedDataType === ModelPropertyDataTypes.Image ||
|
|
8968
|
+
normalizedRefValueType === ModelPropertyDataTypes.Image);
|
|
8969
|
+
const isFileDynamic = propertyRecordSchema &&
|
|
8970
|
+
normalizedDataType === ModelPropertyDataTypes.File;
|
|
8971
|
+
const isHtmlDynamic = propertyRecordSchema &&
|
|
8972
|
+
normalizedDataType === ModelPropertyDataTypes.Html;
|
|
8973
|
+
// Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
|
|
8974
|
+
const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
|
|
8975
|
+
whereClauses.push(propertyNames.length > 1
|
|
8976
|
+
? drizzleOrm.or(...propertyNames.map((n) => drizzleOrm.eq(metadata$1.propertyName, n)))
|
|
8977
|
+
: drizzleOrm.eq(metadata$1.propertyName, propertyNames[0]));
|
|
8978
|
+
// Draft rows often have only seed_local_id populated; on-chain rows may have uid.
|
|
8979
|
+
// Requiring both with AND misses valid metadata when only one column is set.
|
|
8980
|
+
if (seedUid && seedLocalId) {
|
|
8981
|
+
whereClauses.push(drizzleOrm.or(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId), drizzleOrm.eq(metadata$1.seedUid, seedUid)));
|
|
8982
|
+
}
|
|
8983
|
+
else if (seedUid) {
|
|
8984
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.seedUid, seedUid));
|
|
8985
|
+
}
|
|
8986
|
+
else if (seedLocalId) {
|
|
8987
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId));
|
|
8988
|
+
}
|
|
8989
|
+
const rows = await appDb
|
|
8990
|
+
.select()
|
|
8991
|
+
.from(metadata$1)
|
|
8992
|
+
.where(drizzleOrm.and(...whereClauses))
|
|
8993
|
+
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
|
|
8994
|
+
if (!rows || !rows.length) {
|
|
8995
|
+
return;
|
|
8996
|
+
}
|
|
8997
|
+
const firstRow = rows[0];
|
|
8998
|
+
const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
|
|
8999
|
+
let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
|
|
9000
|
+
let propertyValueProcessed = propertyValueFromDb;
|
|
9001
|
+
let renderValue = refResolvedDisplayValue ?? undefined;
|
|
9002
|
+
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
9003
|
+
if (isImageDynamic) {
|
|
9004
|
+
let dir = localStorageDir;
|
|
9005
|
+
if (!dir && isImageDynamic) {
|
|
9006
|
+
dir = 'images';
|
|
9007
|
+
}
|
|
9008
|
+
dir = dir.replace(/^\//, '');
|
|
9009
|
+
if (propertyValueFromDb &&
|
|
9010
|
+
propertyValueFromDb.length === 66) {
|
|
9011
|
+
// Here the storageTransactionId is stored on a different record and
|
|
9012
|
+
// we want to add it as the refResolvedValue
|
|
9013
|
+
const storageTransactionQuery = await appDb
|
|
9014
|
+
.select({
|
|
9015
|
+
propertyValue: metadata$1.propertyValue,
|
|
9016
|
+
})
|
|
9017
|
+
.from(metadata$1)
|
|
9018
|
+
.where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, propertyValueFromDb), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))));
|
|
9019
|
+
if (storageTransactionQuery && storageTransactionQuery.length > 0) {
|
|
9020
|
+
const row = storageTransactionQuery[0];
|
|
9021
|
+
refResolvedValue = row.propertyValue;
|
|
9022
|
+
await updateMetadata({
|
|
9023
|
+
localId,
|
|
9024
|
+
refResolvedValue,
|
|
9025
|
+
localStorageDir: '/images',
|
|
9026
|
+
});
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
const resolveMatchingFilePath = async (dir, needle) => {
|
|
9030
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9031
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9032
|
+
if (!dirExists)
|
|
9033
|
+
return undefined;
|
|
9034
|
+
const fs = await BaseFileManager.getFs();
|
|
9035
|
+
const path = BaseFileManager.getPathModule();
|
|
9036
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9037
|
+
const matchingFiles = files.filter((file) => {
|
|
9038
|
+
return path.basename(file).includes(needle);
|
|
9039
|
+
});
|
|
9040
|
+
if (!matchingFiles?.length)
|
|
9041
|
+
return undefined;
|
|
9042
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9043
|
+
};
|
|
9044
|
+
if (refResolvedValue) {
|
|
9045
|
+
try {
|
|
9046
|
+
let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
|
|
9047
|
+
if (!filePath) {
|
|
9048
|
+
await downloadTransactionIdWithDedupe(refResolvedValue);
|
|
9049
|
+
filePath = await resolveMatchingFilePath(dir, refResolvedValue);
|
|
9050
|
+
}
|
|
9051
|
+
localStorageDir = `/${dir}`;
|
|
9052
|
+
if (filePath) {
|
|
9053
|
+
const file = await BaseFileManager.readFile(filePath);
|
|
9054
|
+
refResolvedDisplayValue = URL.createObjectURL(file);
|
|
9055
|
+
renderValue = refResolvedDisplayValue;
|
|
9056
|
+
// Do not persist blob URL - it is session-scoped
|
|
9057
|
+
}
|
|
9058
|
+
}
|
|
9059
|
+
catch (e) {
|
|
9060
|
+
logger$k('[hydrateFromDb] Image file resolution error', e);
|
|
9061
|
+
}
|
|
9062
|
+
}
|
|
9063
|
+
}
|
|
9064
|
+
if (isFileDynamic && refResolvedValue) {
|
|
9065
|
+
try {
|
|
9066
|
+
const dir = (localStorageDir ?? '/files').replace(/^\//, '');
|
|
9067
|
+
const resolveMatchingFilePath = async (needle) => {
|
|
9068
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9069
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9070
|
+
if (!dirExists)
|
|
9071
|
+
return undefined;
|
|
9072
|
+
const fs = await BaseFileManager.getFs();
|
|
9073
|
+
const path = BaseFileManager.getPathModule();
|
|
9074
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9075
|
+
const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
|
|
9076
|
+
if (!matchingFiles?.length)
|
|
9077
|
+
return undefined;
|
|
9078
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9079
|
+
};
|
|
9080
|
+
let filePath = await resolveMatchingFilePath(refResolvedValue);
|
|
9081
|
+
if (!filePath) {
|
|
9082
|
+
await downloadTransactionIdWithDedupe(refResolvedValue);
|
|
9083
|
+
filePath = await resolveMatchingFilePath(refResolvedValue);
|
|
9084
|
+
}
|
|
9085
|
+
if (filePath) {
|
|
9086
|
+
localStorageDir = `/${dir}`;
|
|
9087
|
+
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
catch (e) {
|
|
9091
|
+
logger$k('[hydrateFromDb] File resolution error', e);
|
|
9092
|
+
}
|
|
9093
|
+
}
|
|
9094
|
+
if (propertyRecordSchema &&
|
|
9095
|
+
normalizedDataType === ModelPropertyDataTypes.List &&
|
|
9096
|
+
typeof propertyValueFromDb === 'string') {
|
|
9097
|
+
propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
|
|
9098
|
+
}
|
|
9099
|
+
sendBack({
|
|
9100
|
+
type: 'updateContext',
|
|
9101
|
+
localId,
|
|
9102
|
+
uid,
|
|
9103
|
+
propertyValue: propertyValueProcessed,
|
|
9104
|
+
seedLocalId: seedLocalIdFromDb,
|
|
9105
|
+
seedUid: seedUidFromDb,
|
|
9106
|
+
versionLocalId: versionLocalIdFromDb,
|
|
9107
|
+
versionUid: versionUidFromDb,
|
|
9108
|
+
schemaUid: schemaUidFromDb,
|
|
9109
|
+
refValueType,
|
|
9110
|
+
localStorageDir,
|
|
9111
|
+
refResolvedValue,
|
|
9112
|
+
refResolvedDisplayValue,
|
|
9113
|
+
renderValue,
|
|
9114
|
+
populatedFromDb: true,
|
|
9115
|
+
});
|
|
9116
|
+
if (propertyRecordSchema &&
|
|
9117
|
+
propertyRecordSchema.storageType &&
|
|
9118
|
+
propertyRecordSchema.storageType === 'ItemStorage') {
|
|
9119
|
+
const itemMod = await Promise.resolve().then(function () { return Item$1; });
|
|
9120
|
+
const { Item } = itemMod;
|
|
9121
|
+
const item = await Item.find({
|
|
9122
|
+
seedLocalId: seedLocalId ?? undefined,
|
|
9123
|
+
modelName,
|
|
9124
|
+
});
|
|
9125
|
+
if (item) {
|
|
9126
|
+
const dir = localStorageDir?.replace(/^\//, '') || 'files';
|
|
9127
|
+
const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
|
|
9128
|
+
const exists = await BaseFileManager.pathExists(filePath);
|
|
9129
|
+
if (!exists) {
|
|
9130
|
+
return;
|
|
9131
|
+
}
|
|
9132
|
+
const renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
9133
|
+
const property = item.properties.find(p => p.propertyName === propertyName);
|
|
9134
|
+
if (property) {
|
|
9135
|
+
property.getService().send({ type: 'updateContext', renderValue });
|
|
9136
|
+
}
|
|
9137
|
+
return;
|
|
9138
|
+
}
|
|
8175
9139
|
}
|
|
8176
|
-
// Html: read file content for renderValue (blob URLs from DB are invalid after reload)
|
|
8177
|
-
//
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
if (
|
|
8184
|
-
const
|
|
9140
|
+
// Html: read file content for renderValue (blob URLs from DB are invalid after reload).
|
|
9141
|
+
// When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
|
|
9142
|
+
if (isHtmlDynamic) {
|
|
9143
|
+
const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
|
|
9144
|
+
let htmlContent;
|
|
9145
|
+
let outRef = refResolvedValue;
|
|
9146
|
+
let outDir = htmlLocalStorageDir;
|
|
9147
|
+
if (refResolvedValue && htmlLocalStorageDir) {
|
|
9148
|
+
const dir = htmlLocalStorageDir.replace(/^\//, '');
|
|
9149
|
+
const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
|
|
9150
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
9151
|
+
if (!exists) {
|
|
9152
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
9153
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
9154
|
+
}
|
|
9155
|
+
if (exists) {
|
|
9156
|
+
htmlContent = await BaseFileManager.readFileAsString(filePath);
|
|
9157
|
+
}
|
|
9158
|
+
}
|
|
9159
|
+
if (!htmlContent && propertyValueFromDb) {
|
|
9160
|
+
htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
|
|
9161
|
+
const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
|
|
9162
|
+
if (lid) {
|
|
9163
|
+
outRef = `${lid}.html`;
|
|
9164
|
+
outDir = '/html';
|
|
9165
|
+
}
|
|
9166
|
+
}
|
|
9167
|
+
if (htmlContent) {
|
|
8185
9168
|
sendBack({
|
|
8186
9169
|
type: 'updateContext',
|
|
8187
9170
|
localId,
|
|
@@ -8193,8 +9176,8 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8193
9176
|
versionUid: versionUidFromDb,
|
|
8194
9177
|
schemaUid: schemaUidFromDb,
|
|
8195
9178
|
refValueType,
|
|
8196
|
-
localStorageDir:
|
|
8197
|
-
refResolvedValue,
|
|
9179
|
+
localStorageDir: outDir,
|
|
9180
|
+
refResolvedValue: outRef ?? refResolvedValue,
|
|
8198
9181
|
refResolvedDisplayValue,
|
|
8199
9182
|
renderValue: htmlContent,
|
|
8200
9183
|
populatedFromDb: true,
|
|
@@ -8208,11 +9191,11 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8208
9191
|
});
|
|
8209
9192
|
});
|
|
8210
9193
|
|
|
8211
|
-
const logger$
|
|
9194
|
+
const logger$j = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
|
|
8212
9195
|
const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
8213
9196
|
const _loadOrCreateProperty = async () => {
|
|
8214
9197
|
const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
|
|
8215
|
-
logger$
|
|
9198
|
+
logger$j(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
|
|
8216
9199
|
if (!seedLocalId && !seedUid) {
|
|
8217
9200
|
throw new Error('seedLocalId or seedUid is required');
|
|
8218
9201
|
}
|
|
@@ -8258,15 +9241,15 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8258
9241
|
const schemas = modelPropertiesToObject(model$1.properties);
|
|
8259
9242
|
propertyRecordSchema = schemas[propertyName];
|
|
8260
9243
|
if (propertyRecordSchema) {
|
|
8261
|
-
logger$
|
|
9244
|
+
logger$j(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
|
|
8262
9245
|
}
|
|
8263
9246
|
}
|
|
8264
9247
|
}
|
|
8265
9248
|
catch (error) {
|
|
8266
|
-
logger$
|
|
9249
|
+
logger$j(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
|
|
8267
9250
|
}
|
|
8268
9251
|
}
|
|
8269
|
-
logger$
|
|
9252
|
+
logger$j(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
|
|
8270
9253
|
sendBack({
|
|
8271
9254
|
type: 'loadOrCreatePropertySuccess',
|
|
8272
9255
|
property: {
|
|
@@ -8332,7 +9315,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8332
9315
|
};
|
|
8333
9316
|
// Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
|
|
8334
9317
|
try {
|
|
8335
|
-
const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-
|
|
9318
|
+
const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-BT7i8Tl-.js'); });
|
|
8336
9319
|
let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
|
|
8337
9320
|
if (!schemaFromFile?.validation) {
|
|
8338
9321
|
// Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
|
|
@@ -8370,7 +9353,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8370
9353
|
}
|
|
8371
9354
|
}
|
|
8372
9355
|
catch (error) {
|
|
8373
|
-
logger$
|
|
9356
|
+
logger$j(`Error loading propertyRecordSchema from database: ${error}`);
|
|
8374
9357
|
// Continue without propertyRecordSchema
|
|
8375
9358
|
}
|
|
8376
9359
|
}
|
|
@@ -8388,22 +9371,27 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8388
9371
|
const schemas = modelPropertiesToObject(model$1.properties);
|
|
8389
9372
|
propertyRecordSchema = schemas[propertyName];
|
|
8390
9373
|
if (propertyRecordSchema) {
|
|
8391
|
-
logger$
|
|
9374
|
+
logger$j(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
|
|
8392
9375
|
}
|
|
8393
9376
|
}
|
|
8394
9377
|
}
|
|
8395
9378
|
catch (error) {
|
|
8396
|
-
logger$
|
|
9379
|
+
logger$j(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
|
|
8397
9380
|
}
|
|
8398
9381
|
}
|
|
8399
9382
|
// For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
|
|
8400
9383
|
let renderValue = metadataRecord.propertyValue || undefined;
|
|
8401
9384
|
const refSeedType = metadataRecord.refSeedType;
|
|
8402
|
-
const
|
|
8403
|
-
|
|
9385
|
+
const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
|
|
9386
|
+
const isHtml = refSeedType === 'html' || normalizedHtmlDt === exports.ModelPropertyDataTypes.Html;
|
|
9387
|
+
// Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
|
|
9388
|
+
// After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
|
|
8404
9389
|
if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
|
|
8405
|
-
|
|
8406
|
-
|
|
9390
|
+
const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
|
|
9391
|
+
if (lid) {
|
|
9392
|
+
metadataRecord.refResolvedValue = `${lid}.html`;
|
|
9393
|
+
metadataRecord.localStorageDir = '/html';
|
|
9394
|
+
}
|
|
8407
9395
|
}
|
|
8408
9396
|
// Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
|
|
8409
9397
|
if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
|
|
@@ -8413,13 +9401,34 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8413
9401
|
try {
|
|
8414
9402
|
const dir = metadataRecord.localStorageDir.replace(/^\//, '');
|
|
8415
9403
|
const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
|
|
8416
|
-
|
|
9404
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
9405
|
+
if (!exists) {
|
|
9406
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
9407
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
9408
|
+
}
|
|
8417
9409
|
if (exists) {
|
|
8418
9410
|
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
8419
9411
|
}
|
|
9412
|
+
else {
|
|
9413
|
+
const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
|
|
9414
|
+
if (viaSeedPointer) {
|
|
9415
|
+
renderValue = viaSeedPointer;
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
8420
9418
|
}
|
|
8421
9419
|
catch (e) {
|
|
8422
|
-
logger$
|
|
9420
|
+
logger$j(`Failed to read Html file for ${propertyName}: ${e}`);
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9423
|
+
// Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
|
|
9424
|
+
if (isHtml && metadataRecord.propertyValue) {
|
|
9425
|
+
const pv = String(metadataRecord.propertyValue).trim();
|
|
9426
|
+
const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
|
|
9427
|
+
if (!rv || rv === pv) {
|
|
9428
|
+
const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
|
|
9429
|
+
if (recovered) {
|
|
9430
|
+
renderValue = recovered;
|
|
9431
|
+
}
|
|
8423
9432
|
}
|
|
8424
9433
|
}
|
|
8425
9434
|
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
@@ -8429,28 +9438,83 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8429
9438
|
const isImage = refSeedType === 'image' ||
|
|
8430
9439
|
normalizedDataType === 'Image' ||
|
|
8431
9440
|
normalizedRefValueType === 'Image';
|
|
9441
|
+
const resolveMatchingFilePath = async (dir, needle) => {
|
|
9442
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9443
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9444
|
+
if (!dirExists)
|
|
9445
|
+
return undefined;
|
|
9446
|
+
const fs = await BaseFileManager.getFs();
|
|
9447
|
+
const path = BaseFileManager.getPathModule();
|
|
9448
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9449
|
+
const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
|
|
9450
|
+
if (!matchingFiles?.length)
|
|
9451
|
+
return undefined;
|
|
9452
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9453
|
+
};
|
|
9454
|
+
// EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
|
|
9455
|
+
// hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
|
|
9456
|
+
if (isImage &&
|
|
9457
|
+
!metadataRecord.refResolvedValue &&
|
|
9458
|
+
typeof metadataRecord.propertyValue === 'string' &&
|
|
9459
|
+
metadataRecord.propertyValue.length === 66) {
|
|
9460
|
+
const storageTxRows = await db
|
|
9461
|
+
.select({ propertyValue: metadata$1.propertyValue })
|
|
9462
|
+
.from(metadata$1)
|
|
9463
|
+
.where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, metadataRecord.propertyValue), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))))
|
|
9464
|
+
.limit(1);
|
|
9465
|
+
const derivedTxId = storageTxRows[0]?.propertyValue;
|
|
9466
|
+
if (derivedTxId) {
|
|
9467
|
+
metadataRecord.refResolvedValue = derivedTxId;
|
|
9468
|
+
metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
|
|
9469
|
+
if (metadataRecord.localId) {
|
|
9470
|
+
try {
|
|
9471
|
+
await updateMetadata({
|
|
9472
|
+
localId: metadataRecord.localId,
|
|
9473
|
+
refResolvedValue: derivedTxId,
|
|
9474
|
+
localStorageDir: '/images',
|
|
9475
|
+
});
|
|
9476
|
+
}
|
|
9477
|
+
catch (e) {
|
|
9478
|
+
logger$j(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
|
|
9479
|
+
}
|
|
9480
|
+
}
|
|
9481
|
+
}
|
|
9482
|
+
}
|
|
8432
9483
|
if (isImage && metadataRecord.refResolvedValue) {
|
|
8433
9484
|
try {
|
|
8434
9485
|
const dir = (metadataRecord.localStorageDir ?? '/images').replace(/^\//, '');
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
const
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
9486
|
+
let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9487
|
+
if (!filePath) {
|
|
9488
|
+
await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
|
|
9489
|
+
filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9490
|
+
}
|
|
9491
|
+
if (filePath) {
|
|
9492
|
+
const file = await BaseFileManager.readFile(filePath);
|
|
9493
|
+
const freshBlobUrl = URL.createObjectURL(file);
|
|
9494
|
+
renderValue = freshBlobUrl;
|
|
9495
|
+
refResolvedDisplayValue = freshBlobUrl;
|
|
9496
|
+
}
|
|
9497
|
+
}
|
|
9498
|
+
catch (e) {
|
|
9499
|
+
logger$j(`Failed to resolve Image file for ${propertyName}: ${e}`);
|
|
9500
|
+
}
|
|
9501
|
+
}
|
|
9502
|
+
const isFile = refSeedType === 'file' ||
|
|
9503
|
+
normalizedDataType === 'File';
|
|
9504
|
+
if (isFile && metadataRecord.refResolvedValue) {
|
|
9505
|
+
try {
|
|
9506
|
+
const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
|
|
9507
|
+
let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9508
|
+
if (!filePath) {
|
|
9509
|
+
await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
|
|
9510
|
+
filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9511
|
+
}
|
|
9512
|
+
if (filePath) {
|
|
9513
|
+
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
8450
9514
|
}
|
|
8451
9515
|
}
|
|
8452
9516
|
catch (e) {
|
|
8453
|
-
logger$
|
|
9517
|
+
logger$j(`Failed to resolve File for ${propertyName}: ${e}`);
|
|
8454
9518
|
}
|
|
8455
9519
|
}
|
|
8456
9520
|
let propertyValueOut = metadataRecord.propertyValue || undefined;
|
|
@@ -8482,7 +9546,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8482
9546
|
});
|
|
8483
9547
|
};
|
|
8484
9548
|
_loadOrCreateProperty().catch((error) => {
|
|
8485
|
-
logger$
|
|
9549
|
+
logger$j(`Error in loadOrCreateProperty: ${error}`);
|
|
8486
9550
|
sendBack({
|
|
8487
9551
|
type: 'loadOrCreatePropertyError',
|
|
8488
9552
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -8512,10 +9576,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
|
|
|
8512
9576
|
return queryRows[0];
|
|
8513
9577
|
};
|
|
8514
9578
|
|
|
8515
|
-
const logger$
|
|
9579
|
+
const logger$i = debug('seedSdk:write:updateItemPropertyValue');
|
|
8516
9580
|
const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
|
|
8517
9581
|
if (!localIdParam && !seedLocalId) {
|
|
8518
|
-
logger$
|
|
9582
|
+
logger$i(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
|
|
8519
9583
|
return;
|
|
8520
9584
|
}
|
|
8521
9585
|
let safeNewValue = newValue;
|
|
@@ -8543,7 +9607,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8543
9607
|
.select()
|
|
8544
9608
|
.from(metadata$1)
|
|
8545
9609
|
.where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
|
|
8546
|
-
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
|
|
9610
|
+
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
|
|
8547
9611
|
}
|
|
8548
9612
|
}
|
|
8549
9613
|
else if (localIdParam) {
|
|
@@ -8563,7 +9627,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8563
9627
|
.select()
|
|
8564
9628
|
.from(metadata$1)
|
|
8565
9629
|
.where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
|
|
8566
|
-
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
|
|
9630
|
+
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
|
|
8567
9631
|
}
|
|
8568
9632
|
// const mostRecentRecordStatement = `SELECT local_id,
|
|
8569
9633
|
// uid,
|
|
@@ -8579,7 +9643,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8579
9643
|
// FROM metadata
|
|
8580
9644
|
// WHERE property_name = '${propertyName}'
|
|
8581
9645
|
// AND seed_local_id = '${seedLocalId}'
|
|
8582
|
-
// ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
|
|
9646
|
+
// ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
|
|
8583
9647
|
//
|
|
8584
9648
|
// const { rows } = await runQueryForStatement(mostRecentRecordStatement)
|
|
8585
9649
|
if (rows && rows.length > 0) {
|
|
@@ -8588,7 +9652,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8588
9652
|
modelType === modelName?.toLowerCase() &&
|
|
8589
9653
|
refSeedTypeFromDb === refSeedType &&
|
|
8590
9654
|
refResolvedValueFromDb === refResolvedValue) {
|
|
8591
|
-
logger$
|
|
9655
|
+
logger$i(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
|
|
8592
9656
|
return;
|
|
8593
9657
|
}
|
|
8594
9658
|
// This means we already have a local-only record so we should just update that one
|
|
@@ -8716,9 +9780,9 @@ const analyzeInput = xstate.fromCallback(({ sendBack, input: { context, event }
|
|
|
8716
9780
|
}
|
|
8717
9781
|
const _analyzeInput = async () => {
|
|
8718
9782
|
// Use dynamic import to break circular dependency
|
|
8719
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
9783
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
8720
9784
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
8721
|
-
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
9785
|
+
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
|
|
8722
9786
|
let propertyName = propertyNameRaw;
|
|
8723
9787
|
if (!propertyName) {
|
|
8724
9788
|
throw new Error('propertyName is required');
|
|
@@ -8916,7 +9980,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
|
|
|
8916
9980
|
propertyRecordSchema?.validation &&
|
|
8917
9981
|
metadataValues.propertyValue != null &&
|
|
8918
9982
|
metadataValues.propertyValue !== '') {
|
|
8919
|
-
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
9983
|
+
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-C8mdrNnp.js'); });
|
|
8920
9984
|
const validationService = new SchemaValidationService();
|
|
8921
9985
|
const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
|
|
8922
9986
|
if (!validationResult.isValid && validationResult.errors.length > 0) {
|
|
@@ -8994,8 +10058,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
|
|
|
8994
10058
|
return inserted[0];
|
|
8995
10059
|
};
|
|
8996
10060
|
|
|
8997
|
-
const eventEmitter = new EventEmitter();
|
|
8998
|
-
|
|
8999
10061
|
const readFileAsArrayBuffer$1 = async (file) => {
|
|
9000
10062
|
return new Promise((resolve) => {
|
|
9001
10063
|
const reader = new FileReader();
|
|
@@ -9142,6 +10204,12 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
|
|
|
9142
10204
|
}
|
|
9143
10205
|
const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
|
|
9144
10206
|
let newLocalId;
|
|
10207
|
+
const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
|
|
10208
|
+
? schemaUid
|
|
10209
|
+
: (await getEasSchemaForItemProperty({
|
|
10210
|
+
propertyName,
|
|
10211
|
+
easDataType: 'bytes32',
|
|
10212
|
+
}))?.id;
|
|
9145
10213
|
if (!localId) {
|
|
9146
10214
|
const result = await createMetadata({
|
|
9147
10215
|
propertyName,
|
|
@@ -9151,7 +10219,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
|
|
|
9151
10219
|
versionLocalId,
|
|
9152
10220
|
versionUid,
|
|
9153
10221
|
modelName,
|
|
9154
|
-
schemaUid:
|
|
10222
|
+
schemaUid: resolvedPropertySchemaUid,
|
|
9155
10223
|
refSeedType: 'image',
|
|
9156
10224
|
refModelUid: imageSchemaUid,
|
|
9157
10225
|
refResolvedValue: fileName,
|
|
@@ -9170,7 +10238,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
|
|
|
9170
10238
|
seedLocalId,
|
|
9171
10239
|
versionLocalId,
|
|
9172
10240
|
modelName,
|
|
9173
|
-
schemaUid,
|
|
10241
|
+
schemaUid: resolvedPropertySchemaUid,
|
|
9174
10242
|
refSeedType: 'image',
|
|
9175
10243
|
refResolvedValue: fileName,
|
|
9176
10244
|
localStorageDir: '/images',
|
|
@@ -9503,7 +10571,7 @@ const saveRelation = xstate.fromCallback(({ sendBack, input: { context, event }
|
|
|
9503
10571
|
}
|
|
9504
10572
|
const _saveRelation = async () => {
|
|
9505
10573
|
// Use dynamic import to break circular dependency
|
|
9506
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
10574
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
9507
10575
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
9508
10576
|
if (!propertyNameRaw) {
|
|
9509
10577
|
throw new Error('propertyName is required');
|
|
@@ -9712,6 +10780,10 @@ const propertyMachine = xstate.setup({
|
|
|
9712
10780
|
context: {},
|
|
9713
10781
|
input: {},
|
|
9714
10782
|
},
|
|
10783
|
+
guards: {
|
|
10784
|
+
// stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
|
|
10785
|
+
propertyMachineIsIdle: xstate.stateIn('idle'),
|
|
10786
|
+
},
|
|
9715
10787
|
// actions: {
|
|
9716
10788
|
// updateContext: updateMachineContext,
|
|
9717
10789
|
// },
|
|
@@ -9734,7 +10806,11 @@ const propertyMachine = xstate.setup({
|
|
|
9734
10806
|
initial: 'waitingForDb',
|
|
9735
10807
|
context: ({ input }) => input,
|
|
9736
10808
|
on: {
|
|
9737
|
-
|
|
10809
|
+
/** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
|
|
10810
|
+
rehydrateFromDb: {
|
|
10811
|
+
guard: 'propertyMachineIsIdle',
|
|
10812
|
+
target: '.hydratingFromDb',
|
|
10813
|
+
},
|
|
9738
10814
|
save: {
|
|
9739
10815
|
actions: xstate.assign({
|
|
9740
10816
|
isSaving: true,
|
|
@@ -10333,6 +11409,8 @@ function createReactiveProxy(config) {
|
|
|
10333
11409
|
return proxy;
|
|
10334
11410
|
}
|
|
10335
11411
|
|
|
11412
|
+
/** Parent Html property `propertyValue` after publish (66-char seed uid). */
|
|
11413
|
+
const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
10336
11414
|
// Start loading Model at module load time (non-blocking)
|
|
10337
11415
|
Promise.resolve().then(function () { return Model$1; }).then(module => {
|
|
10338
11416
|
module.Model;
|
|
@@ -10432,7 +11510,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
|
|
|
10432
11510
|
};
|
|
10433
11511
|
/** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
|
|
10434
11512
|
const modelTypeToModelName = (modelType) => modelType ? lodashEs.upperFirst(lodashEs.camelCase(modelType)) : '';
|
|
10435
|
-
const logger$
|
|
11513
|
+
const logger$h = debug('seedSdk:property:class');
|
|
10436
11514
|
// Define tracked properties for the Proxy
|
|
10437
11515
|
// These properties will be read from/written to the actor context
|
|
10438
11516
|
const TRACKED_PROPERTIES$2 = [
|
|
@@ -10514,7 +11592,7 @@ class ItemProperty {
|
|
|
10514
11592
|
serviceInput.propertyValue = JSON.parse(propertyValue);
|
|
10515
11593
|
}
|
|
10516
11594
|
catch (e) {
|
|
10517
|
-
logger$
|
|
11595
|
+
logger$h('List property value is not JSON', e);
|
|
10518
11596
|
}
|
|
10519
11597
|
}
|
|
10520
11598
|
}
|
|
@@ -10537,7 +11615,7 @@ class ItemProperty {
|
|
|
10537
11615
|
return;
|
|
10538
11616
|
}
|
|
10539
11617
|
// Use dynamic import to break circular dependency
|
|
10540
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
11618
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-Dty7eE10.js'); });
|
|
10541
11619
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
10542
11620
|
const { context } = snapshot;
|
|
10543
11621
|
const { propertyRecordSchema } = context;
|
|
@@ -10560,7 +11638,8 @@ class ItemProperty {
|
|
|
10560
11638
|
propertyRecordSchema.storageType === 'ItemStorage' &&
|
|
10561
11639
|
context.refResolvedValue &&
|
|
10562
11640
|
context.localStorageDir;
|
|
10563
|
-
const
|
|
11641
|
+
const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
|
|
11642
|
+
const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
|
|
10564
11643
|
context.refResolvedValue;
|
|
10565
11644
|
// Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
|
|
10566
11645
|
// so the UI can display the filename and preview immediately (these update again when save completes)
|
|
@@ -10596,7 +11675,11 @@ class ItemProperty {
|
|
|
10596
11675
|
const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
|
|
10597
11676
|
const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
|
|
10598
11677
|
try {
|
|
10599
|
-
|
|
11678
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
11679
|
+
if (!exists && isHtml) {
|
|
11680
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
11681
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
11682
|
+
}
|
|
10600
11683
|
if (exists && (isItemStorage || isHtml)) {
|
|
10601
11684
|
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
10602
11685
|
}
|
|
@@ -10616,8 +11699,8 @@ class ItemProperty {
|
|
|
10616
11699
|
if (isFile && isFileValue) {
|
|
10617
11700
|
renderValue = pv.name;
|
|
10618
11701
|
}
|
|
10619
|
-
else if (isImage) {
|
|
10620
|
-
// FS race
|
|
11702
|
+
else if (isImage || isHtml) {
|
|
11703
|
+
// FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
|
|
10621
11704
|
renderValue = undefined;
|
|
10622
11705
|
}
|
|
10623
11706
|
else {
|
|
@@ -10626,13 +11709,21 @@ class ItemProperty {
|
|
|
10626
11709
|
}
|
|
10627
11710
|
}
|
|
10628
11711
|
catch (e) {
|
|
10629
|
-
logger$
|
|
10630
|
-
renderValue = 'No file found';
|
|
11712
|
+
logger$h(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
|
|
11713
|
+
renderValue = isHtml ? undefined : 'No file found';
|
|
10631
11714
|
}
|
|
10632
11715
|
}
|
|
10633
11716
|
if (!renderValue) {
|
|
10634
11717
|
renderValue = context.renderValue || context.propertyValue;
|
|
10635
11718
|
}
|
|
11719
|
+
const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
|
|
11720
|
+
if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
|
|
11721
|
+
HTML_PROP_SEED_UID_RE.test(pvStr) &&
|
|
11722
|
+
renderValue === pvStr &&
|
|
11723
|
+
typeof context.renderValue === 'string' &&
|
|
11724
|
+
context.renderValue.length > pvStr.length) {
|
|
11725
|
+
renderValue = context.renderValue;
|
|
11726
|
+
}
|
|
10636
11727
|
let transformedPropertyName = propertyName;
|
|
10637
11728
|
const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
|
|
10638
11729
|
if (!skipTransform && transformedPropertyName.endsWith('Id')) {
|
|
@@ -11045,6 +12136,35 @@ class ItemProperty {
|
|
|
11045
12136
|
instance._service.send({ type: 'updateContext', ...updates });
|
|
11046
12137
|
}
|
|
11047
12138
|
}
|
|
12139
|
+
// After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
|
|
12140
|
+
// paths would hydrate. Re-run DB hydration without clobbering propertyValue.
|
|
12141
|
+
const svc = instance._service;
|
|
12142
|
+
const snap = svc.getSnapshot();
|
|
12143
|
+
if (snap.status === 'active' && snap.value === 'idle') {
|
|
12144
|
+
const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
|
|
12145
|
+
const dt = normalizeDataType(schema?.dataType);
|
|
12146
|
+
const isHtmlProp = props.refSeedType === 'html' ||
|
|
12147
|
+
ctx.refSeedType === 'html' ||
|
|
12148
|
+
dt === exports.ModelPropertyDataTypes.Html;
|
|
12149
|
+
const isListProp = dt === exports.ModelPropertyDataTypes.List;
|
|
12150
|
+
const isRelationProp = dt === exports.ModelPropertyDataTypes.Relation;
|
|
12151
|
+
const pv = ctx.propertyValue;
|
|
12152
|
+
const pvStr = typeof pv === 'string' ? pv.trim() : '';
|
|
12153
|
+
const renderVal = ctx.renderValue;
|
|
12154
|
+
const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
|
|
12155
|
+
const htmlStuckOnUid = isHtmlProp &&
|
|
12156
|
+
HTML_PROP_SEED_UID_RE.test(pvStr) &&
|
|
12157
|
+
(renderMissing || renderVal === pv);
|
|
12158
|
+
const pvPresent = pv != null &&
|
|
12159
|
+
(Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
|
|
12160
|
+
const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
|
|
12161
|
+
const versionChanged = props.versionLocalId != null &&
|
|
12162
|
+
ctx.versionLocalId != null &&
|
|
12163
|
+
props.versionLocalId !== ctx.versionLocalId;
|
|
12164
|
+
if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
|
|
12165
|
+
svc.send({ type: 'rehydrateFromDb' });
|
|
12166
|
+
}
|
|
12167
|
+
}
|
|
11048
12168
|
// On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
|
|
11049
12169
|
if (!waitForReady)
|
|
11050
12170
|
return instance;
|
|
@@ -11394,7 +12514,7 @@ class ItemProperty {
|
|
|
11394
12514
|
}
|
|
11395
12515
|
async save() {
|
|
11396
12516
|
const ctx = this._getSnapshotContext();
|
|
11397
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
12517
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
|
|
11398
12518
|
await assertItemOwned({
|
|
11399
12519
|
seedLocalId: ctx?.seedLocalId ?? undefined,
|
|
11400
12520
|
seedUid: ctx?.seedUid ?? undefined,
|
|
@@ -11733,7 +12853,7 @@ class Item {
|
|
|
11733
12853
|
});
|
|
11734
12854
|
};
|
|
11735
12855
|
this.unpublish = async () => {
|
|
11736
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
12856
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
|
|
11737
12857
|
const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
|
|
11738
12858
|
await assertItemOwned(this);
|
|
11739
12859
|
const seedUid = this.seedUid;
|
|
@@ -11757,7 +12877,7 @@ class Item {
|
|
|
11757
12877
|
this._service.send({ type: 'updateContext', revokedAt });
|
|
11758
12878
|
};
|
|
11759
12879
|
this.publish = async () => {
|
|
11760
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
12880
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
|
|
11761
12881
|
await assertItemOwned(this);
|
|
11762
12882
|
this._service.send({ type: 'startPublish' });
|
|
11763
12883
|
return new Promise((resolve, reject) => {
|
|
@@ -11793,12 +12913,12 @@ class Item {
|
|
|
11793
12913
|
};
|
|
11794
12914
|
this.getPublishUploads = async (options) => {
|
|
11795
12915
|
// Use dynamic import to break circular dependency
|
|
11796
|
-
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-
|
|
12916
|
+
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-CMpPR2JJ.js'); });
|
|
11797
12917
|
const { getPublishUploads } = getPublishUploadsMod;
|
|
11798
12918
|
return await getPublishUploads(this, [], undefined, options);
|
|
11799
12919
|
};
|
|
11800
12920
|
this.getPublishPayload = async (uploadedTransactions, options) => {
|
|
11801
|
-
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-
|
|
12921
|
+
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-C0hWIYCX.js'); });
|
|
11802
12922
|
const { getPublishPayload } = getPublishPayloadMod;
|
|
11803
12923
|
return await getPublishPayload(this, uploadedTransactions, options);
|
|
11804
12924
|
};
|
|
@@ -11915,6 +13035,8 @@ class Item {
|
|
|
11915
13035
|
'schemaUid',
|
|
11916
13036
|
'latestVersionLocalId',
|
|
11917
13037
|
'latestVersionUid',
|
|
13038
|
+
'publishedVersionUid',
|
|
13039
|
+
'publishedVersionLocalId',
|
|
11918
13040
|
];
|
|
11919
13041
|
const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
|
|
11920
13042
|
const schemaNameForModel = initialValues.schemaName;
|
|
@@ -11958,6 +13080,128 @@ class Item {
|
|
|
11958
13080
|
});
|
|
11959
13081
|
}
|
|
11960
13082
|
}
|
|
13083
|
+
/** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
|
|
13084
|
+
static findItemInstanceCacheEntryByProps(props) {
|
|
13085
|
+
const l = props.seedLocalId;
|
|
13086
|
+
const u = props.seedUid;
|
|
13087
|
+
if (typeof l === 'string' && l.length > 0) {
|
|
13088
|
+
const e = this.instanceCache.get(l);
|
|
13089
|
+
if (e)
|
|
13090
|
+
return e;
|
|
13091
|
+
}
|
|
13092
|
+
if (typeof u === 'string' && u.length > 0) {
|
|
13093
|
+
const e = this.instanceCache.get(u);
|
|
13094
|
+
if (e)
|
|
13095
|
+
return e;
|
|
13096
|
+
}
|
|
13097
|
+
return undefined;
|
|
13098
|
+
}
|
|
13099
|
+
static findItemInstanceCacheEntryById(id) {
|
|
13100
|
+
const direct = this.instanceCache.get(id);
|
|
13101
|
+
if (direct)
|
|
13102
|
+
return direct;
|
|
13103
|
+
for (const [, entry] of this.instanceCache) {
|
|
13104
|
+
const ctx = entry.instance._getSnapshotContext();
|
|
13105
|
+
if (ctx.seedLocalId === id || ctx.seedUid === id)
|
|
13106
|
+
return entry;
|
|
13107
|
+
}
|
|
13108
|
+
return undefined;
|
|
13109
|
+
}
|
|
13110
|
+
static collectInstanceCacheKeysForInstance(instance) {
|
|
13111
|
+
const keys = [];
|
|
13112
|
+
for (const [k, v] of this.instanceCache) {
|
|
13113
|
+
if (v.instance === instance)
|
|
13114
|
+
keys.push(k);
|
|
13115
|
+
}
|
|
13116
|
+
return keys;
|
|
13117
|
+
}
|
|
13118
|
+
static registerItemInInstanceCache(instance) {
|
|
13119
|
+
const ctx = instance._getSnapshotContext();
|
|
13120
|
+
const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
|
|
13121
|
+
? ctx.seedLocalId
|
|
13122
|
+
: undefined;
|
|
13123
|
+
const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
|
|
13124
|
+
const entry = { instance, refCount: 1 };
|
|
13125
|
+
if (lid)
|
|
13126
|
+
this.instanceCache.set(lid, entry);
|
|
13127
|
+
if (uid && uid !== lid)
|
|
13128
|
+
this.instanceCache.set(uid, entry);
|
|
13129
|
+
if (!lid && !uid) {
|
|
13130
|
+
throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
|
|
13131
|
+
}
|
|
13132
|
+
}
|
|
13133
|
+
static releaseItemInstanceCacheHold(instance) {
|
|
13134
|
+
const keys = this.collectInstanceCacheKeysForInstance(instance);
|
|
13135
|
+
if (keys.length === 0)
|
|
13136
|
+
return;
|
|
13137
|
+
const entry = this.instanceCache.get(keys[0]);
|
|
13138
|
+
entry.refCount -= 1;
|
|
13139
|
+
if (entry.refCount <= 0) {
|
|
13140
|
+
for (const k of keys) {
|
|
13141
|
+
this.instanceCache.delete(k);
|
|
13142
|
+
}
|
|
13143
|
+
}
|
|
13144
|
+
}
|
|
13145
|
+
/**
|
|
13146
|
+
* Item machine can reach `idle` before `propertyInstances` is merged (race) or while
|
|
13147
|
+
* child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
|
|
13148
|
+
*/
|
|
13149
|
+
static async waitForItemInstanceReadyForRead(item, readyTimeout) {
|
|
13150
|
+
await waitForEntityIdle(item, { timeout: readyTimeout });
|
|
13151
|
+
const svc = item.getService();
|
|
13152
|
+
try {
|
|
13153
|
+
await xstate.waitFor(svc, (snap) => {
|
|
13154
|
+
if ('value' in snap && snap.value === 'error') {
|
|
13155
|
+
throw new Error('Entity failed to load');
|
|
13156
|
+
}
|
|
13157
|
+
if (!('value' in snap) || snap.value !== 'idle') {
|
|
13158
|
+
return false;
|
|
13159
|
+
}
|
|
13160
|
+
const ctx = snap.context || {};
|
|
13161
|
+
const versionsCount = ctx.versionsCount ?? 0;
|
|
13162
|
+
const hasHeadVersion = !!ctx.latestVersionLocalId;
|
|
13163
|
+
if (versionsCount === 0 && !hasHeadVersion) {
|
|
13164
|
+
return true;
|
|
13165
|
+
}
|
|
13166
|
+
return (ctx.propertyInstances?.size ?? 0) > 0;
|
|
13167
|
+
}, { timeout: readyTimeout });
|
|
13168
|
+
}
|
|
13169
|
+
catch (e) {
|
|
13170
|
+
if (e?.message === 'Entity failed to load') {
|
|
13171
|
+
throw e;
|
|
13172
|
+
}
|
|
13173
|
+
const msg = typeof e?.message === 'string' ? e.message : '';
|
|
13174
|
+
const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
|
|
13175
|
+
if (!isWaitForTimeout) {
|
|
13176
|
+
throw e;
|
|
13177
|
+
}
|
|
13178
|
+
}
|
|
13179
|
+
const snap = svc.getSnapshot();
|
|
13180
|
+
const pis = snap.context?.propertyInstances;
|
|
13181
|
+
if (!pis || pis.size === 0) {
|
|
13182
|
+
return;
|
|
13183
|
+
}
|
|
13184
|
+
await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
|
|
13185
|
+
timeout: readyTimeout,
|
|
13186
|
+
throwOnError: false,
|
|
13187
|
+
})));
|
|
13188
|
+
}
|
|
13189
|
+
static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
|
|
13190
|
+
const snap = instance.getService().getSnapshot();
|
|
13191
|
+
if (snap.value !== 'idle')
|
|
13192
|
+
return false;
|
|
13193
|
+
const mapSize = snap.context.propertyInstances?.size ?? 0;
|
|
13194
|
+
if (mapSize > 0)
|
|
13195
|
+
return false;
|
|
13196
|
+
const ctx = snap.context;
|
|
13197
|
+
const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
|
|
13198
|
+
const hasVersionHead = versionsCount > 0 ||
|
|
13199
|
+
!!props.latestVersionLocalId ||
|
|
13200
|
+
!!ctx.latestVersionLocalId ||
|
|
13201
|
+
!!props.latestVersionUid ||
|
|
13202
|
+
!!ctx.latestVersionUid;
|
|
13203
|
+
return hasVersionHead;
|
|
13204
|
+
}
|
|
11961
13205
|
static async create(props, options) {
|
|
11962
13206
|
const waitForReady = options?.waitForReady !== false;
|
|
11963
13207
|
const readyTimeout = options?.readyTimeout ?? 5000;
|
|
@@ -11965,45 +13209,66 @@ class Item {
|
|
|
11965
13209
|
props.modelName = lodashEs.startCase(props.type);
|
|
11966
13210
|
}
|
|
11967
13211
|
if (props.seedUid || props.seedLocalId) {
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
13212
|
+
cacheReuse: {
|
|
13213
|
+
const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
|
|
13214
|
+
if (cachedEntry) {
|
|
13215
|
+
const instance = cachedEntry.instance;
|
|
13216
|
+
cachedEntry.refCount += 1;
|
|
13217
|
+
for (const [propertyName, propertyValue] of Object.entries(props)) {
|
|
13218
|
+
const snapshot = instance.getService().getSnapshot();
|
|
13219
|
+
const propertyInstances = snapshot.context.propertyInstances;
|
|
13220
|
+
if (!propertyInstances || !propertyInstances.has(propertyName)) {
|
|
13221
|
+
continue;
|
|
13222
|
+
}
|
|
13223
|
+
const propertyInstance = propertyInstances.get(propertyName);
|
|
13224
|
+
if (!propertyInstance) {
|
|
13225
|
+
continue;
|
|
13226
|
+
}
|
|
13227
|
+
propertyInstance.getService().send({
|
|
13228
|
+
type: 'updateContext',
|
|
13229
|
+
propertyValue,
|
|
13230
|
+
});
|
|
11984
13231
|
}
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
propertyValue,
|
|
11988
|
-
});
|
|
11989
|
-
}
|
|
11990
|
-
if (!waitForReady)
|
|
11991
|
-
return instance;
|
|
11992
|
-
try {
|
|
11993
|
-
await waitForEntityIdle(instance, { timeout: readyTimeout });
|
|
11994
|
-
}
|
|
11995
|
-
catch (err) {
|
|
13232
|
+
if (!waitForReady)
|
|
13233
|
+
return instance;
|
|
11996
13234
|
try {
|
|
11997
|
-
|
|
13235
|
+
await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
|
|
11998
13236
|
}
|
|
11999
|
-
catch {
|
|
12000
|
-
|
|
13237
|
+
catch (err) {
|
|
13238
|
+
try {
|
|
13239
|
+
instance.unload();
|
|
13240
|
+
}
|
|
13241
|
+
catch {
|
|
13242
|
+
/* best-effort cache cleanup */
|
|
13243
|
+
}
|
|
13244
|
+
throw err;
|
|
12001
13245
|
}
|
|
12002
|
-
|
|
13246
|
+
if (waitForReady &&
|
|
13247
|
+
this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
|
|
13248
|
+
forceRemoveFromCaches(instance, {
|
|
13249
|
+
getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
|
|
13250
|
+
caches: [Item.instanceCache],
|
|
13251
|
+
});
|
|
13252
|
+
try {
|
|
13253
|
+
unloadEntity(instance, {
|
|
13254
|
+
getCacheKeys: () => [],
|
|
13255
|
+
caches: [],
|
|
13256
|
+
instanceState: itemInstanceState,
|
|
13257
|
+
getService: (inst) => inst._service,
|
|
13258
|
+
onUnload: (inst) => {
|
|
13259
|
+
inst._subscription?.unsubscribe();
|
|
13260
|
+
},
|
|
13261
|
+
});
|
|
13262
|
+
}
|
|
13263
|
+
catch {
|
|
13264
|
+
/* best-effort teardown for stale cached shell */
|
|
13265
|
+
}
|
|
13266
|
+
break cacheReuse;
|
|
13267
|
+
}
|
|
13268
|
+
return instance;
|
|
12003
13269
|
}
|
|
12004
|
-
return instance;
|
|
12005
13270
|
}
|
|
12006
|
-
if (!this.
|
|
13271
|
+
if (!this.findItemInstanceCacheEntryByProps(props)) {
|
|
12007
13272
|
// Item no longer needs modelInstance - it loads properties from database independently
|
|
12008
13273
|
// Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
|
|
12009
13274
|
const { latestVersionUid, ...propsWithoutVersionUid } = props;
|
|
@@ -12092,14 +13357,11 @@ class Item {
|
|
|
12092
13357
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
12093
13358
|
},
|
|
12094
13359
|
});
|
|
12095
|
-
this.
|
|
12096
|
-
instance: proxiedInstance,
|
|
12097
|
-
refCount: 1,
|
|
12098
|
-
});
|
|
13360
|
+
this.registerItemInInstanceCache(proxiedInstance);
|
|
12099
13361
|
if (!waitForReady)
|
|
12100
13362
|
return proxiedInstance;
|
|
12101
13363
|
try {
|
|
12102
|
-
await
|
|
13364
|
+
await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
|
|
12103
13365
|
}
|
|
12104
13366
|
catch (err) {
|
|
12105
13367
|
try {
|
|
@@ -12275,14 +13537,11 @@ class Item {
|
|
|
12275
13537
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
12276
13538
|
},
|
|
12277
13539
|
});
|
|
12278
|
-
this.
|
|
12279
|
-
instance: proxiedInstance,
|
|
12280
|
-
refCount: 1,
|
|
12281
|
-
});
|
|
13540
|
+
this.registerItemInInstanceCache(proxiedInstance);
|
|
12282
13541
|
if (!waitForReady)
|
|
12283
13542
|
return proxiedInstance;
|
|
12284
13543
|
try {
|
|
12285
|
-
await
|
|
13544
|
+
await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
|
|
12286
13545
|
}
|
|
12287
13546
|
catch (err) {
|
|
12288
13547
|
try {
|
|
@@ -12305,14 +13564,10 @@ class Item {
|
|
|
12305
13564
|
if (!id) {
|
|
12306
13565
|
return null;
|
|
12307
13566
|
}
|
|
12308
|
-
|
|
12309
|
-
if (
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
instance,
|
|
12313
|
-
refCount: refCount + 1,
|
|
12314
|
-
});
|
|
12315
|
-
return instance;
|
|
13567
|
+
const entry = this.findItemInstanceCacheEntryById(id);
|
|
13568
|
+
if (entry) {
|
|
13569
|
+
entry.refCount += 1;
|
|
13570
|
+
return entry.instance;
|
|
12316
13571
|
}
|
|
12317
13572
|
return null;
|
|
12318
13573
|
}
|
|
@@ -12358,8 +13613,8 @@ class Item {
|
|
|
12358
13613
|
if (!seedLocalId && !seedUid) {
|
|
12359
13614
|
return undefined;
|
|
12360
13615
|
}
|
|
12361
|
-
//
|
|
12362
|
-
const id =
|
|
13616
|
+
// Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
|
|
13617
|
+
const id = seedLocalId || seedUid;
|
|
12363
13618
|
if (!id) {
|
|
12364
13619
|
return undefined;
|
|
12365
13620
|
}
|
|
@@ -12390,10 +13645,127 @@ class Item {
|
|
|
12390
13645
|
}));
|
|
12391
13646
|
}
|
|
12392
13647
|
if (waitForReady && itemInstances.length > 0) {
|
|
12393
|
-
await Promise.all(itemInstances.map((item) =>
|
|
13648
|
+
await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
|
|
12394
13649
|
}
|
|
12395
13650
|
return lodashEs.orderBy(itemInstances, ['createdAt'], ['desc']);
|
|
12396
13651
|
}
|
|
13652
|
+
/**
|
|
13653
|
+
* After EAS sync writes metadata for the latest version, merge new property instances and
|
|
13654
|
+
* re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
|
|
13655
|
+
* and useItems may not invalidate when the seed set is unchanged.
|
|
13656
|
+
*/
|
|
13657
|
+
static async rehydrateCachedItemsFromDbAfterEasSync() {
|
|
13658
|
+
const appDb = BaseDb.getAppDb();
|
|
13659
|
+
if (!appDb || Item.instanceCache.size === 0) {
|
|
13660
|
+
return;
|
|
13661
|
+
}
|
|
13662
|
+
const { metadata } = await Promise.resolve().then(function () { return schema$1; });
|
|
13663
|
+
const { eq, and } = await import('drizzle-orm');
|
|
13664
|
+
const dedupedInstances = new Map();
|
|
13665
|
+
for (const entry of Item.instanceCache.values()) {
|
|
13666
|
+
dedupedInstances.set(entry.instance, entry);
|
|
13667
|
+
}
|
|
13668
|
+
const entries = [...dedupedInstances.values()];
|
|
13669
|
+
await Promise.all(entries.map(async ({ instance }) => {
|
|
13670
|
+
try {
|
|
13671
|
+
const svc = instance.getService();
|
|
13672
|
+
if (svc.getSnapshot().status !== 'active') {
|
|
13673
|
+
return;
|
|
13674
|
+
}
|
|
13675
|
+
const ctx = svc.getSnapshot().context;
|
|
13676
|
+
const seedLocalId = ctx.seedLocalId;
|
|
13677
|
+
const seedUid = ctx.seedUid;
|
|
13678
|
+
const versionLocalId = ctx.latestVersionLocalId;
|
|
13679
|
+
const itemModelName = ctx.modelName;
|
|
13680
|
+
const schemaNameForModel = ctx.schemaName;
|
|
13681
|
+
if (!seedLocalId || !versionLocalId || !itemModelName) {
|
|
13682
|
+
return;
|
|
13683
|
+
}
|
|
13684
|
+
const metadataRows = await appDb
|
|
13685
|
+
.select()
|
|
13686
|
+
.from(metadata)
|
|
13687
|
+
.where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
|
|
13688
|
+
let propertySchemas = {};
|
|
13689
|
+
try {
|
|
13690
|
+
const M = getModel();
|
|
13691
|
+
const model = schemaNameForModel !== undefined
|
|
13692
|
+
? M?.getByName(itemModelName, schemaNameForModel)
|
|
13693
|
+
: M?.getByName(itemModelName);
|
|
13694
|
+
if (model?.properties?.length) {
|
|
13695
|
+
propertySchemas = modelPropertiesToObject(model.properties);
|
|
13696
|
+
}
|
|
13697
|
+
}
|
|
13698
|
+
catch {
|
|
13699
|
+
/* Model optional */
|
|
13700
|
+
}
|
|
13701
|
+
const sendToItemMachine = (event) => {
|
|
13702
|
+
if (svc.getSnapshot().status !== 'active') {
|
|
13703
|
+
return;
|
|
13704
|
+
}
|
|
13705
|
+
svc.send(event);
|
|
13706
|
+
};
|
|
13707
|
+
for (const metaRow of metadataRows) {
|
|
13708
|
+
try {
|
|
13709
|
+
let propertyName = metaRow.propertyName;
|
|
13710
|
+
const listSchemaKey = propertyName &&
|
|
13711
|
+
Object.keys(propertySchemas).length > 0 &&
|
|
13712
|
+
resolveStorageNameToSchemaName(propertySchemas, propertyName);
|
|
13713
|
+
if (listSchemaKey) {
|
|
13714
|
+
propertyName = listSchemaKey;
|
|
13715
|
+
}
|
|
13716
|
+
else {
|
|
13717
|
+
const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
|
|
13718
|
+
const refSeedType = metaRow.refSeedType;
|
|
13719
|
+
const isRefTypeFromMeta = refSeedType === 'file' ||
|
|
13720
|
+
refSeedType === 'image' ||
|
|
13721
|
+
refSeedType === 'relation' ||
|
|
13722
|
+
refSeedType === 'html';
|
|
13723
|
+
if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
|
|
13724
|
+
propertyName = baseName;
|
|
13725
|
+
}
|
|
13726
|
+
}
|
|
13727
|
+
if (!propertyName) {
|
|
13728
|
+
continue;
|
|
13729
|
+
}
|
|
13730
|
+
const property = await ItemProperty.find({
|
|
13731
|
+
propertyName,
|
|
13732
|
+
seedLocalId,
|
|
13733
|
+
seedUid,
|
|
13734
|
+
modelName: itemModelName,
|
|
13735
|
+
});
|
|
13736
|
+
if (property) {
|
|
13737
|
+
sendToItemMachine({
|
|
13738
|
+
type: 'addPropertyInstance',
|
|
13739
|
+
propertyName,
|
|
13740
|
+
propertyInstance: property,
|
|
13741
|
+
});
|
|
13742
|
+
}
|
|
13743
|
+
}
|
|
13744
|
+
catch {
|
|
13745
|
+
/* row skipped */
|
|
13746
|
+
}
|
|
13747
|
+
}
|
|
13748
|
+
const instances = svc.getSnapshot().context.propertyInstances;
|
|
13749
|
+
if (!instances) {
|
|
13750
|
+
return;
|
|
13751
|
+
}
|
|
13752
|
+
for (const propertyInstance of instances.values()) {
|
|
13753
|
+
try {
|
|
13754
|
+
const propertySnap = propertyInstance.getService().getSnapshot();
|
|
13755
|
+
if (xstate.isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
|
|
13756
|
+
propertyInstance.getService().send({ type: 'rehydrateFromDb' });
|
|
13757
|
+
}
|
|
13758
|
+
}
|
|
13759
|
+
catch {
|
|
13760
|
+
/* best-effort */
|
|
13761
|
+
}
|
|
13762
|
+
}
|
|
13763
|
+
}
|
|
13764
|
+
catch (e) {
|
|
13765
|
+
itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
|
|
13766
|
+
}
|
|
13767
|
+
}));
|
|
13768
|
+
}
|
|
12397
13769
|
_createPropertyInstance(props) {
|
|
12398
13770
|
if (this._storageTransactionId) {
|
|
12399
13771
|
props.storageTransactionId = this._storageTransactionId;
|
|
@@ -13008,15 +14380,10 @@ class Item {
|
|
|
13008
14380
|
}
|
|
13009
14381
|
unload() {
|
|
13010
14382
|
try {
|
|
13011
|
-
|
|
13012
|
-
const cacheKey = context.seedUid || context.seedLocalId;
|
|
13013
|
-
const cacheKeys = [];
|
|
13014
|
-
if (cacheKey) {
|
|
13015
|
-
cacheKeys.push(cacheKey);
|
|
13016
|
-
}
|
|
14383
|
+
Item.releaseItemInstanceCacheHold(this);
|
|
13017
14384
|
unloadEntity(this, {
|
|
13018
|
-
getCacheKeys: () =>
|
|
13019
|
-
caches: [
|
|
14385
|
+
getCacheKeys: () => [],
|
|
14386
|
+
caches: [],
|
|
13020
14387
|
instanceState: itemInstanceState,
|
|
13021
14388
|
getService: (instance) => instance._service,
|
|
13022
14389
|
onUnload: (instance) => {
|
|
@@ -13045,11 +14412,10 @@ class Item {
|
|
|
13045
14412
|
* Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
|
|
13046
14413
|
*/
|
|
13047
14414
|
async destroy() {
|
|
13048
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
14415
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-TCXiKRY_.js'); });
|
|
13049
14416
|
await assertItemOwned(this);
|
|
13050
14417
|
const context = this._getSnapshotContext();
|
|
13051
|
-
const
|
|
13052
|
-
const cacheKeys = cacheKey ? [cacheKey] : [];
|
|
14418
|
+
const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
|
|
13053
14419
|
clearDestroySubscriptions(this, {
|
|
13054
14420
|
instanceState: itemInstanceState,
|
|
13055
14421
|
onUnload: (instance) => instance._subscription?.unsubscribe(),
|
|
@@ -13106,600 +14472,331 @@ function normalizeAddressConfig(addresses) {
|
|
|
13106
14472
|
};
|
|
13107
14473
|
}
|
|
13108
14474
|
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
const
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
const
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
|
|
14475
|
+
let writeTail = Promise.resolve();
|
|
14476
|
+
function enqueueEasSyncDbWrite(fn) {
|
|
14477
|
+
const next = writeTail.then(fn);
|
|
14478
|
+
writeTail = next.catch(() => { });
|
|
14479
|
+
return next;
|
|
14480
|
+
}
|
|
14481
|
+
const MAX_ERROR_MESSAGE_LENGTH = 500;
|
|
14482
|
+
const MAX_ERROR_DETAILS_LENGTH = 2000;
|
|
14483
|
+
async function insertEasSyncProcessRow(params) {
|
|
14484
|
+
return enqueueEasSyncDbWrite(async () => {
|
|
14485
|
+
const db = BaseDb.getAppDb();
|
|
14486
|
+
if (!db) {
|
|
14487
|
+
throw new Error('[easSyncProcess] App DB not available');
|
|
14488
|
+
}
|
|
14489
|
+
const now = Date.now();
|
|
14490
|
+
const [row] = await db
|
|
14491
|
+
.insert(easSyncProcesses)
|
|
14492
|
+
.values({
|
|
14493
|
+
status: 'in_progress',
|
|
14494
|
+
startedAt: now,
|
|
14495
|
+
requestPayload: JSON.stringify(params.requestPayload),
|
|
14496
|
+
persistedSnapshot: JSON.stringify(params.persistedSnapshot),
|
|
14497
|
+
createdAt: now,
|
|
14498
|
+
updatedAt: now,
|
|
13128
14499
|
})
|
|
13129
|
-
.
|
|
13130
|
-
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
id: foundModelQuery[0].id,
|
|
13139
|
-
name: foundModelQuery[0].name,
|
|
13140
|
-
uid: foundModelQuery[0].uid,
|
|
13141
|
-
tableName: pluralize(foundModelQuery[0].name).toLowerCase(),
|
|
13142
|
-
};
|
|
13143
|
-
modelRecords.push(foundModel);
|
|
13144
|
-
if (modelName === 'Seed') {
|
|
13145
|
-
continue;
|
|
13146
|
-
}
|
|
13147
|
-
const schemaString = `bytes32 ${toSnakeCase(modelName)}`;
|
|
13148
|
-
schemaStringToModelRecord.set(schemaString, foundModel);
|
|
13149
|
-
}
|
|
13150
|
-
return {
|
|
13151
|
-
schemaStringToModelRecord,
|
|
13152
|
-
modelRecords,
|
|
13153
|
-
};
|
|
13154
|
-
};
|
|
13155
|
-
|
|
13156
|
-
const createSeeds = async (newSeeds) => {
|
|
13157
|
-
const appDb = BaseDb.getAppDb();
|
|
13158
|
-
const results = await appDb
|
|
13159
|
-
.insert(seeds)
|
|
13160
|
-
.values(newSeeds)
|
|
13161
|
-
.returning({ uid: seeds.uid });
|
|
13162
|
-
const newUids = results.reduce((acc, result) => {
|
|
13163
|
-
if (result.uid) {
|
|
13164
|
-
acc.push(result.uid);
|
|
14500
|
+
.returning({ id: easSyncProcesses.id });
|
|
14501
|
+
return row.id;
|
|
14502
|
+
});
|
|
14503
|
+
}
|
|
14504
|
+
async function finalizeEasSyncProcessRow(id, params) {
|
|
14505
|
+
return enqueueEasSyncDbWrite(async () => {
|
|
14506
|
+
const db = BaseDb.getAppDb();
|
|
14507
|
+
if (!db) {
|
|
14508
|
+
return;
|
|
13165
14509
|
}
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
14510
|
+
const now = Date.now();
|
|
14511
|
+
await db
|
|
14512
|
+
.update(easSyncProcesses)
|
|
14513
|
+
.set({
|
|
14514
|
+
status: params.status,
|
|
14515
|
+
completedAt: now,
|
|
14516
|
+
updatedAt: now,
|
|
14517
|
+
errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
|
|
14518
|
+
errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
|
|
14519
|
+
persistedSnapshot: JSON.stringify(params.persistedSnapshot),
|
|
14520
|
+
})
|
|
14521
|
+
.where(drizzleOrm.eq(easSyncProcesses.id, id));
|
|
14522
|
+
});
|
|
14523
|
+
}
|
|
13170
14524
|
|
|
13171
14525
|
/**
|
|
13172
|
-
*
|
|
14526
|
+
* Merge multiple EAS sync intents: full sync (no concrete address list) wins;
|
|
14527
|
+
* otherwise union addresses (first-seen casing).
|
|
13173
14528
|
*/
|
|
13174
|
-
|
|
13175
|
-
|
|
13176
|
-
|
|
14529
|
+
function mergeEasSyncRequestIntents(parts) {
|
|
14530
|
+
const norm = parts.filter((p) => p != null);
|
|
14531
|
+
if (norm.length === 0) {
|
|
14532
|
+
return {};
|
|
13177
14533
|
}
|
|
13178
|
-
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
.
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
|
|
13188
|
-
|
|
13189
|
-
'0x0000000000000000000000000000000000000000000000000000000000000020',
|
|
13190
|
-
];
|
|
13191
|
-
const seedUidToLocalId = new Map();
|
|
13192
|
-
const seedUidToModelType = new Map();
|
|
13193
|
-
const relatedSeedUids = new Set();
|
|
13194
|
-
const versionUidToLocalId = new Map();
|
|
13195
|
-
const versionUidToSeedUid = new Map();
|
|
13196
|
-
const propertyUidToLocalId = new Map();
|
|
13197
|
-
const saveEasSeedsToDb = async ({ itemSeeds }) => {
|
|
13198
|
-
const appDb = BaseDb.getAppDb();
|
|
13199
|
-
const seedUids = itemSeeds.map((seed) => seed.id);
|
|
13200
|
-
const existingSeedRecordsRows = await appDb
|
|
13201
|
-
.select()
|
|
13202
|
-
.from(seeds)
|
|
13203
|
-
.where(drizzleOrm.inArray(seeds.uid, seedUids));
|
|
13204
|
-
const existingSeedUids = new Set();
|
|
13205
|
-
if (existingSeedRecordsRows && existingSeedRecordsRows.length > 0) {
|
|
13206
|
-
for (const row of existingSeedRecordsRows) {
|
|
13207
|
-
if (row.uid) {
|
|
13208
|
-
existingSeedUids.add(row.uid);
|
|
13209
|
-
if (row.localId) {
|
|
13210
|
-
seedUidToLocalId.set(row.uid, row.localId);
|
|
13211
|
-
}
|
|
13212
|
-
if (row.type) {
|
|
13213
|
-
seedUidToModelType.set(row.uid, row.type);
|
|
13214
|
-
}
|
|
14534
|
+
let full = false;
|
|
14535
|
+
const addressMap = new Map();
|
|
14536
|
+
for (const p of norm) {
|
|
14537
|
+
if (!('addresses' in p) || p.addresses === undefined) {
|
|
14538
|
+
full = true;
|
|
14539
|
+
break;
|
|
14540
|
+
}
|
|
14541
|
+
for (const addr of p.addresses) {
|
|
14542
|
+
const k = addr.toLowerCase();
|
|
14543
|
+
if (!addressMap.has(k)) {
|
|
14544
|
+
addressMap.set(k, addr);
|
|
13215
14545
|
}
|
|
13216
14546
|
}
|
|
13217
14547
|
}
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
const seedByUid = new Map(itemSeeds.map((s) => [s.id, s]));
|
|
13221
|
-
for (const row of existingSeedRecordsRows) {
|
|
13222
|
-
if (!row.uid || !row.localId)
|
|
13223
|
-
continue;
|
|
13224
|
-
const attestation = seedByUid.get(row.uid);
|
|
13225
|
-
if (!attestation?.revoked)
|
|
13226
|
-
continue;
|
|
13227
|
-
if (row.revokedAt != null)
|
|
13228
|
-
continue;
|
|
13229
|
-
const revokedAt = attestation.revocationTime > 0
|
|
13230
|
-
? attestation.revocationTime
|
|
13231
|
-
: Math.floor(Date.now() / 1000);
|
|
13232
|
-
await updateSeedRevokedAt({ seedLocalId: row.localId, revokedAt });
|
|
13233
|
-
}
|
|
13234
|
-
if (newSeeds.length === 0) {
|
|
13235
|
-
return { seedUidToLocalId, seedUids };
|
|
13236
|
-
}
|
|
13237
|
-
const newSeedsData = [];
|
|
13238
|
-
for (let i = 0; i < newSeeds.length; i++) {
|
|
13239
|
-
const seed = newSeeds[i];
|
|
13240
|
-
seedUidToModelType.set(seed.id, seed.schema.schemaNames[0].name);
|
|
13241
|
-
const seedLocalId = generateId();
|
|
13242
|
-
seedUidToLocalId.set(seed.id, seedLocalId);
|
|
13243
|
-
const attestationRaw = escapeSqliteString(JSON.stringify(seed));
|
|
13244
|
-
const revokedAt = seed.revoked && seed.revocationTime != null && seed.revocationTime > 0
|
|
13245
|
-
? seed.revocationTime
|
|
13246
|
-
: seed.revoked
|
|
13247
|
-
? Math.floor(Date.now() / 1000)
|
|
13248
|
-
: undefined;
|
|
13249
|
-
newSeedsData.push({
|
|
13250
|
-
localId: seedLocalId,
|
|
13251
|
-
uid: seed.id,
|
|
13252
|
-
schemaUid: seed.schemaId,
|
|
13253
|
-
type: seed.schema.schemaNames[0].name,
|
|
13254
|
-
publisher: seed.attester,
|
|
13255
|
-
createdAt: Date.now(),
|
|
13256
|
-
attestationCreatedAt: seed.timeCreated * 1000,
|
|
13257
|
-
attestationRaw,
|
|
13258
|
-
...(revokedAt !== undefined && { revokedAt }),
|
|
13259
|
-
});
|
|
13260
|
-
seedUidToLocalId.set(seed.id, seedLocalId);
|
|
14548
|
+
if (full) {
|
|
14549
|
+
return {};
|
|
13261
14550
|
}
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
};
|
|
13265
|
-
const saveEasVersionsToDb = async ({ itemVersions }) => {
|
|
13266
|
-
const versionUids = itemVersions.map((version) => version.id);
|
|
13267
|
-
const appDb = BaseDb.getAppDb();
|
|
13268
|
-
const existingVersionRecordsRows = await appDb
|
|
13269
|
-
.select()
|
|
13270
|
-
.from(versions)
|
|
13271
|
-
.where(drizzleOrm.inArray(versions.uid, versionUids));
|
|
13272
|
-
const existingVersionUids = new Set();
|
|
13273
|
-
if (existingVersionRecordsRows && existingVersionRecordsRows.length > 0) {
|
|
13274
|
-
for (const row of existingVersionRecordsRows) {
|
|
13275
|
-
if (row.uid) {
|
|
13276
|
-
existingVersionUids.add(row.uid);
|
|
13277
|
-
if (row.localId) {
|
|
13278
|
-
versionUidToLocalId.set(row.uid, row.localId);
|
|
13279
|
-
}
|
|
13280
|
-
if (row.seedUid) {
|
|
13281
|
-
versionUidToSeedUid.set(row.uid, row.seedUid);
|
|
13282
|
-
}
|
|
13283
|
-
}
|
|
13284
|
-
}
|
|
13285
|
-
}
|
|
13286
|
-
const newVersions = itemVersions.filter((version) => !existingVersionUids.has(version.id));
|
|
13287
|
-
if (newVersions.length === 0) {
|
|
13288
|
-
return { versionUidToLocalId, versionUids };
|
|
13289
|
-
}
|
|
13290
|
-
let insertVersionsQuery = `INSERT INTO versions (local_id, uid, seed_uid, seed_local_id, seed_type, created_at,
|
|
13291
|
-
attestation_created_at,
|
|
13292
|
-
attestation_raw, publisher)
|
|
13293
|
-
VALUES `;
|
|
13294
|
-
for (let i = 0; i < newVersions.length; i++) {
|
|
13295
|
-
const version = newVersions[i];
|
|
13296
|
-
versionUidToSeedUid.set(version.id, version.refUID);
|
|
13297
|
-
const versionLocalId = generateId();
|
|
13298
|
-
versionUidToLocalId.set(version.id, versionLocalId);
|
|
13299
|
-
const seedUid = versionUidToSeedUid.get(version.id);
|
|
13300
|
-
const seedLocalId = seedUidToLocalId.get(seedUid);
|
|
13301
|
-
const seedType = seedUidToModelType.get(seedUid);
|
|
13302
|
-
const attestationRaw = escapeSqliteString(JSON.stringify(version));
|
|
13303
|
-
const publisher = escapeSqliteString(version.attester ?? '');
|
|
13304
|
-
const valuesString = `('${versionLocalId}', '${version.id}', '${seedUid}', '${seedLocalId}', '${seedType}', ${Date.now()}, ${version.timeCreated * 1000}, '${attestationRaw}', '${publisher}')`;
|
|
13305
|
-
if (i < newVersions.length - 1) {
|
|
13306
|
-
insertVersionsQuery += valuesString + ', ';
|
|
13307
|
-
}
|
|
13308
|
-
if (i === newVersions.length - 1) {
|
|
13309
|
-
insertVersionsQuery += valuesString + ';';
|
|
13310
|
-
}
|
|
13311
|
-
versionUidToLocalId.set(version.id, versionLocalId);
|
|
13312
|
-
}
|
|
13313
|
-
await appDb.run(drizzleOrm.sql.raw(insertVersionsQuery));
|
|
13314
|
-
return { versionUids };
|
|
13315
|
-
};
|
|
13316
|
-
const createMetadataRecordsForStorageTransactionId = async (storageTransactionIdProperty, modelSchema) => {
|
|
13317
|
-
// Early return if modelSchema is not provided
|
|
13318
|
-
if (!modelSchema) {
|
|
13319
|
-
console.warn('[item/events] [syncDbWithEas] modelSchema is undefined for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
|
|
13320
|
-
return;
|
|
14551
|
+
if (addressMap.size === 0) {
|
|
14552
|
+
return { addresses: [] };
|
|
13321
14553
|
}
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
14554
|
+
return { addresses: [...addressMap.values()] };
|
|
14555
|
+
}
|
|
14556
|
+
|
|
14557
|
+
const log = debug('seedSdk:events:easSyncManager');
|
|
14558
|
+
function toRunSyncArg(options) {
|
|
14559
|
+
if (options &&
|
|
14560
|
+
'addresses' in options &&
|
|
14561
|
+
options.addresses !== undefined) {
|
|
14562
|
+
return options;
|
|
13326
14563
|
}
|
|
13327
|
-
|
|
14564
|
+
return undefined;
|
|
14565
|
+
}
|
|
14566
|
+
const runEasSync = xstate.fromPromise(async ({ input, }) => {
|
|
14567
|
+
const rowId = await insertEasSyncProcessRow({
|
|
14568
|
+
requestPayload: input.requestPayload,
|
|
14569
|
+
persistedSnapshot: input.runningSnapshot,
|
|
14570
|
+
});
|
|
14571
|
+
const { runSyncFromEas } = await Promise.resolve().then(function () { return require('./syncDbWithEas-DUi78csI.js'); });
|
|
13328
14572
|
try {
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
|
|
13337
|
-
return;
|
|
13338
|
-
}
|
|
13339
|
-
const attestationData = parsedData[0].value;
|
|
13340
|
-
lodashEs.camelCase(attestationData.name);
|
|
13341
|
-
const propertyValue = attestationData.value;
|
|
13342
|
-
const itemStorageProperties = new Map();
|
|
13343
|
-
for (const [_propertyName, propertyDef] of Object.entries(modelSchema)) {
|
|
13344
|
-
if (propertyDef?.storageType && propertyDef.storageType === 'ItemStorage') {
|
|
13345
|
-
itemStorageProperties.set(_propertyName, propertyDef);
|
|
13346
|
-
}
|
|
13347
|
-
}
|
|
13348
|
-
if (itemStorageProperties.size === 0) {
|
|
13349
|
-
return;
|
|
13350
|
-
}
|
|
13351
|
-
const appDb = BaseDb.getAppDb();
|
|
13352
|
-
for (const [_propertyName, propertyDef] of itemStorageProperties.entries()) {
|
|
13353
|
-
const existingMetadataRecordRows = await appDb
|
|
13354
|
-
.select()
|
|
13355
|
-
.from(metadata$1)
|
|
13356
|
-
.where(drizzleOrm.and(drizzleOrm.eq(metadata$1.propertyName, _propertyName), drizzleOrm.eq(metadata$1.propertyValue, propertyValue), drizzleOrm.eq(metadata$1.versionUid, storageTransactionIdProperty.refUID)));
|
|
13357
|
-
if (existingMetadataRecordRows && existingMetadataRecordRows.length > 0) {
|
|
13358
|
-
continue;
|
|
13359
|
-
}
|
|
13360
|
-
const seedUid = versionUidToSeedUid.get(storageTransactionIdProperty.refUID);
|
|
13361
|
-
const seedLocalId = seedUidToLocalId.get(seedUid);
|
|
13362
|
-
const versionUid = storageTransactionIdProperty.refUID;
|
|
13363
|
-
const versionLocalId = versionUidToLocalId.get(versionUid);
|
|
13364
|
-
const modelType = seedUidToModelType.get(seedUid);
|
|
13365
|
-
const propertyId = modelType != null
|
|
13366
|
-
? await getPropertyIdForModelAndName(modelType, _propertyName)
|
|
13367
|
-
: null;
|
|
13368
|
-
const propertyLocalId = generateId();
|
|
13369
|
-
await appDb.insert(metadata$1).values({
|
|
13370
|
-
localId: propertyLocalId,
|
|
13371
|
-
propertyId: propertyId ?? undefined,
|
|
13372
|
-
propertyName: _propertyName,
|
|
13373
|
-
propertyValue,
|
|
13374
|
-
localStorageDir: propertyDef.localStorageDir,
|
|
13375
|
-
seedLocalId,
|
|
13376
|
-
seedUid,
|
|
13377
|
-
versionLocalId,
|
|
13378
|
-
versionUid,
|
|
13379
|
-
refValueType: 'file',
|
|
13380
|
-
refResolvedValue: `${propertyValue}${propertyDef.filenameSuffix}`,
|
|
13381
|
-
modelType: seedUidToModelType.get(seedUid),
|
|
13382
|
-
createdAt: Date.now(),
|
|
13383
|
-
updatedAt: Date.now(),
|
|
14573
|
+
await runSyncFromEas(toRunSyncArg(input.options));
|
|
14574
|
+
await finalizeEasSyncProcessRow(rowId, {
|
|
14575
|
+
status: 'completed',
|
|
14576
|
+
persistedSnapshot: {
|
|
14577
|
+
phase: 'completed',
|
|
14578
|
+
correlationIds: input.requestPayload.correlationIds,
|
|
14579
|
+
},
|
|
13384
14580
|
});
|
|
13385
14581
|
}
|
|
13386
|
-
|
|
13387
|
-
|
|
13388
|
-
const
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
const appDb = BaseDb.getAppDb();
|
|
13400
|
-
const existingMetadataRecordsRows = await appDb
|
|
13401
|
-
.select()
|
|
13402
|
-
.from(metadata$1)
|
|
13403
|
-
.where(drizzleOrm.inArray(metadata$1.uid, propertyUids));
|
|
13404
|
-
const existingPropertyRecordsUids = new Set();
|
|
13405
|
-
if (existingMetadataRecordsRows && existingMetadataRecordsRows.length > 0) {
|
|
13406
|
-
for (const row of existingMetadataRecordsRows) {
|
|
13407
|
-
if (row.uid) {
|
|
13408
|
-
existingPropertyRecordsUids.add(row.uid);
|
|
13409
|
-
if (row.localId) {
|
|
13410
|
-
propertyUidToLocalId.set(row.uid, row.localId);
|
|
13411
|
-
}
|
|
13412
|
-
}
|
|
13413
|
-
}
|
|
13414
|
-
}
|
|
13415
|
-
const newProperties = itemProperties.filter((property) => !existingPropertyRecordsUids.has(property.id));
|
|
13416
|
-
if (newProperties.length === 0) {
|
|
13417
|
-
return { propertyUidToLocalId, propertyUids };
|
|
13418
|
-
}
|
|
13419
|
-
let insertPropertiesQuery = `INSERT INTO metadata (local_id, uid, schema_uid, property_id, property_name, property_value,
|
|
13420
|
-
eas_data_type, version_uid, version_local_id, seed_uid,
|
|
13421
|
-
seed_local_id, model_type, ref_value_type, ref_seed_type,
|
|
13422
|
-
ref_schema_uid,
|
|
13423
|
-
created_at, attestation_created_at, attestation_raw,
|
|
13424
|
-
local_storage_dir, ref_resolved_value, publisher)
|
|
13425
|
-
VALUES `;
|
|
13426
|
-
for (let i = 0; i < newProperties.length; i++) {
|
|
13427
|
-
const property = newProperties[i];
|
|
13428
|
-
const propertyLocalId = generateId();
|
|
13429
|
-
// Validate and parse decodedDataJson
|
|
13430
|
-
if (!property.decodedDataJson || property.decodedDataJson.trim() === '') {
|
|
13431
|
-
console.warn('[item/events] [syncDbWithEas] empty decodedDataJson for property: ', property.id);
|
|
13432
|
-
continue;
|
|
13433
|
-
}
|
|
13434
|
-
let parsedData;
|
|
13435
|
-
try {
|
|
13436
|
-
parsedData = JSON.parse(property.decodedDataJson);
|
|
13437
|
-
}
|
|
13438
|
-
catch (error) {
|
|
13439
|
-
console.warn('[item/events] [syncDbWithEas] failed to parse decodedDataJson for property: ', property.id, error);
|
|
13440
|
-
continue;
|
|
13441
|
-
}
|
|
13442
|
-
if (!Array.isArray(parsedData) || parsedData.length === 0 || !parsedData[0]?.value) {
|
|
13443
|
-
console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for property: ', property.id);
|
|
13444
|
-
continue;
|
|
13445
|
-
}
|
|
13446
|
-
const metadata = parsedData[0].value;
|
|
13447
|
-
let propertyNameSnake = metadata.name;
|
|
13448
|
-
if (!propertyNameSnake) {
|
|
13449
|
-
console.warn('[item/events] [syncDbWithEas] no propertyName found for property: ', property);
|
|
13450
|
-
continue;
|
|
13451
|
-
}
|
|
13452
|
-
let isRelation = false;
|
|
13453
|
-
let refValueType;
|
|
13454
|
-
let refSeedType;
|
|
13455
|
-
let refSchemaUid;
|
|
13456
|
-
let isList = false;
|
|
13457
|
-
const schemaUid = property.schemaId;
|
|
13458
|
-
setSchemaUidForSchemaDefinition({
|
|
13459
|
-
text: propertyNameSnake,
|
|
13460
|
-
schemaUid,
|
|
14582
|
+
catch (err) {
|
|
14583
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14584
|
+
const details = err instanceof Error && err.stack
|
|
14585
|
+
? err.stack.slice(0, 2000)
|
|
14586
|
+
: undefined;
|
|
14587
|
+
await finalizeEasSyncProcessRow(rowId, {
|
|
14588
|
+
status: 'failed',
|
|
14589
|
+
errorMessage: message,
|
|
14590
|
+
errorDetails: details,
|
|
14591
|
+
persistedSnapshot: {
|
|
14592
|
+
phase: 'failed',
|
|
14593
|
+
correlationIds: input.requestPayload.correlationIds,
|
|
14594
|
+
},
|
|
13461
14595
|
});
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
metadata.value.forEach((value) => {
|
|
13476
|
-
relatedSeedUids.add(value);
|
|
13477
|
-
});
|
|
13478
|
-
}
|
|
13479
|
-
if (!isList) {
|
|
13480
|
-
if (relationValuesToExclude.includes(metadata.value)) {
|
|
13481
|
-
continue;
|
|
13482
|
-
}
|
|
13483
|
-
relatedSeedUids.add(metadata.value);
|
|
13484
|
-
}
|
|
13485
|
-
}
|
|
13486
|
-
let propertyValue = metadata.value;
|
|
13487
|
-
if (typeof propertyValue !== 'string') {
|
|
13488
|
-
propertyValue = JSON.stringify(propertyValue);
|
|
13489
|
-
}
|
|
13490
|
-
if (isRelation && !isList) {
|
|
13491
|
-
const relatedSeed = itemSeeds.find((seed) => seed.id === metadata.value);
|
|
13492
|
-
if (relatedSeed && relatedSeed.schema && relatedSeed.schema.schemaNames) {
|
|
13493
|
-
refSeedType = relatedSeed.schema.schemaNames[0].name;
|
|
13494
|
-
refSchemaUid = relatedSeed.schemaId;
|
|
13495
|
-
}
|
|
13496
|
-
}
|
|
13497
|
-
if (isRelation && isList) {
|
|
13498
|
-
const relatedSeeds = itemSeeds.filter((seed) => metadata.value.includes(seed.id));
|
|
13499
|
-
if (relatedSeeds && relatedSeeds.length > 0) {
|
|
13500
|
-
refSeedType = relatedSeeds[0].schema.schemaNames[0].name;
|
|
13501
|
-
refSchemaUid = relatedSeeds[0].schemaId;
|
|
13502
|
-
}
|
|
13503
|
-
}
|
|
13504
|
-
const propertyName = lodashEs.camelCase(propertyNameSnake);
|
|
13505
|
-
propertyValue = escapeSqliteString(propertyValue);
|
|
13506
|
-
const easDataType = metadata.type;
|
|
13507
|
-
const versionUid = property.refUID;
|
|
13508
|
-
const versionLocalId = versionUidToLocalId.get(versionUid);
|
|
13509
|
-
const attestationCreatedAt = property.timeCreated * 1000;
|
|
13510
|
-
const attestationRaw = escapeSqliteString(JSON.stringify(property));
|
|
13511
|
-
const seedUid = versionUidToSeedUid.get(versionUid);
|
|
13512
|
-
const seedLocalId = seedUidToLocalId.get(seedUid);
|
|
13513
|
-
const modelType = seedUidToModelType.get(seedUid);
|
|
13514
|
-
const modelName = lodashEs.startCase(modelType);
|
|
13515
|
-
const model = models[modelName];
|
|
13516
|
-
const modelSchema = model?.properties ? modelPropertiesToObject(model.properties) : undefined;
|
|
13517
|
-
if (propertyNameSnake === 'storage_transaction_id') {
|
|
13518
|
-
await createMetadataRecordsForStorageTransactionId(property, modelSchema);
|
|
13519
|
-
}
|
|
13520
|
-
const propertyId = modelType != null
|
|
13521
|
-
? await getPropertyIdForModelAndName(modelType, propertyName)
|
|
13522
|
-
: null;
|
|
13523
|
-
const propertyIdSql = propertyId != null ? String(propertyId) : 'NULL';
|
|
13524
|
-
const publisher = escapeSqliteString(property.attester ?? '');
|
|
13525
|
-
const valuesString = `('${propertyLocalId}', '${property.id}',
|
|
13526
|
-
'${property.schemaId}', ${propertyIdSql}, '${propertyName}',
|
|
13527
|
-
'${propertyValue}', '${easDataType}', '${versionUid}',
|
|
13528
|
-
'${versionLocalId}', '${seedUid}', '${seedLocalId}',
|
|
13529
|
-
'${modelType}', ${refValueType ? `'${refValueType}'` : 'NULL'},
|
|
13530
|
-
${refSeedType ? `'${refSeedType}'` : 'NULL'},
|
|
13531
|
-
${refSchemaUid ? `'${refSchemaUid}'` : 'NULL'},
|
|
13532
|
-
${Date.now()}, ${attestationCreatedAt}, '${attestationRaw}',
|
|
13533
|
-
${'NULL'},
|
|
13534
|
-
${'NULL'},
|
|
13535
|
-
'${publisher}')`;
|
|
13536
|
-
if (i < newProperties.length - 1) {
|
|
13537
|
-
insertPropertiesQuery += valuesString + ', ';
|
|
13538
|
-
}
|
|
13539
|
-
if (i === newProperties.length - 1) {
|
|
13540
|
-
insertPropertiesQuery += valuesString + ';';
|
|
13541
|
-
}
|
|
13542
|
-
propertyUidToLocalId.set(property.id, propertyLocalId);
|
|
13543
|
-
}
|
|
13544
|
-
if (insertPropertiesQuery.endsWith('VALUES ')) {
|
|
13545
|
-
return { propertyUids };
|
|
13546
|
-
}
|
|
13547
|
-
if (insertPropertiesQuery.endsWith(', ')) {
|
|
13548
|
-
insertPropertiesQuery = insertPropertiesQuery.slice(0, -2) + ';';
|
|
13549
|
-
}
|
|
13550
|
-
await appDb.run(drizzleOrm.sql.raw(insertPropertiesQuery));
|
|
13551
|
-
isSavingToDb = false;
|
|
13552
|
-
return { propertyUids };
|
|
14596
|
+
throw err;
|
|
14597
|
+
}
|
|
14598
|
+
});
|
|
14599
|
+
const initialContext = {
|
|
14600
|
+
runOptions: {},
|
|
14601
|
+
activeCorrelationIds: [],
|
|
14602
|
+
activePrimarySource: 'event_bus',
|
|
14603
|
+
pendingMergedOptions: undefined,
|
|
14604
|
+
pendingCorrelationIds: [],
|
|
14605
|
+
pendingPrimarySource: null,
|
|
14606
|
+
lastFinishedCorrelationIds: null,
|
|
14607
|
+
lastFinishedStatus: null,
|
|
14608
|
+
lastFinishedError: null,
|
|
13553
14609
|
};
|
|
13554
|
-
const
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
14610
|
+
const easSyncMachine = xstate.setup({
|
|
14611
|
+
types: {
|
|
14612
|
+
context: {},
|
|
14613
|
+
events: {},
|
|
14614
|
+
},
|
|
14615
|
+
actors: {
|
|
14616
|
+
runEasSync,
|
|
14617
|
+
},
|
|
14618
|
+
}).createMachine({
|
|
14619
|
+
id: MachineIds.EAS_SYNC_MANAGER,
|
|
14620
|
+
initial: 'idle',
|
|
14621
|
+
context: initialContext,
|
|
14622
|
+
states: {
|
|
14623
|
+
idle: {
|
|
14624
|
+
on: {
|
|
14625
|
+
REQUEST: {
|
|
14626
|
+
target: 'running',
|
|
14627
|
+
actions: xstate.assign({
|
|
14628
|
+
runOptions: ({ event }) => event.options === undefined
|
|
14629
|
+
? {}
|
|
14630
|
+
: mergeEasSyncRequestIntents([event.options]),
|
|
14631
|
+
activeCorrelationIds: ({ event }) => [event.correlationId],
|
|
14632
|
+
activePrimarySource: ({ event }) => event.source,
|
|
14633
|
+
}),
|
|
14634
|
+
},
|
|
14635
|
+
},
|
|
14636
|
+
},
|
|
14637
|
+
running: {
|
|
14638
|
+
on: {
|
|
14639
|
+
REQUEST: {
|
|
14640
|
+
actions: xstate.assign({
|
|
14641
|
+
pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
|
|
14642
|
+
context.runOptions,
|
|
14643
|
+
context.pendingMergedOptions,
|
|
14644
|
+
event.options === undefined ? {} : event.options,
|
|
14645
|
+
].filter((x) => x != null)),
|
|
14646
|
+
pendingCorrelationIds: ({ context, event }) => [
|
|
14647
|
+
...context.pendingCorrelationIds,
|
|
14648
|
+
event.correlationId,
|
|
14649
|
+
],
|
|
14650
|
+
pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
|
|
14651
|
+
}),
|
|
14652
|
+
},
|
|
13561
14653
|
},
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
14654
|
+
invoke: {
|
|
14655
|
+
src: 'runEasSync',
|
|
14656
|
+
input: ({ context }) => ({
|
|
14657
|
+
options: context.runOptions,
|
|
14658
|
+
requestPayload: {
|
|
14659
|
+
source: context.activePrimarySource,
|
|
14660
|
+
correlationIds: context.activeCorrelationIds,
|
|
14661
|
+
options: context.runOptions,
|
|
14662
|
+
},
|
|
14663
|
+
runningSnapshot: {
|
|
14664
|
+
phase: 'running',
|
|
14665
|
+
correlationIds: context.activeCorrelationIds,
|
|
14666
|
+
},
|
|
14667
|
+
}),
|
|
14668
|
+
onDone: {
|
|
14669
|
+
target: 'afterRun',
|
|
14670
|
+
actions: xstate.assign({
|
|
14671
|
+
lastFinishedCorrelationIds: ({ context }) => [
|
|
14672
|
+
...context.activeCorrelationIds,
|
|
14673
|
+
],
|
|
14674
|
+
lastFinishedStatus: () => 'success',
|
|
14675
|
+
lastFinishedError: () => null,
|
|
14676
|
+
activeCorrelationIds: () => [],
|
|
14677
|
+
runOptions: () => ({}),
|
|
14678
|
+
}),
|
|
14679
|
+
},
|
|
14680
|
+
onError: {
|
|
14681
|
+
target: 'afterRun',
|
|
14682
|
+
actions: [
|
|
14683
|
+
xstate.assign({
|
|
14684
|
+
lastFinishedCorrelationIds: ({ context }) => [
|
|
14685
|
+
...context.activeCorrelationIds,
|
|
14686
|
+
],
|
|
14687
|
+
lastFinishedStatus: () => 'failed',
|
|
14688
|
+
lastFinishedError: ({ event }) => {
|
|
14689
|
+
const e = event.error;
|
|
14690
|
+
if (e instanceof Error) {
|
|
14691
|
+
return e.message;
|
|
14692
|
+
}
|
|
14693
|
+
return e != null ? String(e) : 'EAS sync failed';
|
|
14694
|
+
},
|
|
14695
|
+
activeCorrelationIds: () => [],
|
|
14696
|
+
runOptions: () => ({}),
|
|
14697
|
+
}),
|
|
14698
|
+
({ event }) => {
|
|
14699
|
+
log('runEasSync error', event.error);
|
|
14700
|
+
},
|
|
14701
|
+
],
|
|
14702
|
+
},
|
|
13569
14703
|
},
|
|
13570
14704
|
},
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
14705
|
+
afterRun: {
|
|
14706
|
+
always: [
|
|
14707
|
+
{
|
|
14708
|
+
guard: ({ context }) => context.pendingCorrelationIds.length > 0,
|
|
14709
|
+
target: 'running',
|
|
14710
|
+
actions: xstate.assign({
|
|
14711
|
+
runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
|
|
14712
|
+
activeCorrelationIds: ({ context }) => [
|
|
14713
|
+
...context.pendingCorrelationIds,
|
|
14714
|
+
],
|
|
14715
|
+
activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
|
|
14716
|
+
pendingMergedOptions: () => undefined,
|
|
14717
|
+
pendingCorrelationIds: () => [],
|
|
14718
|
+
pendingPrimarySource: () => null,
|
|
14719
|
+
}),
|
|
14720
|
+
},
|
|
14721
|
+
{ target: 'idle' },
|
|
14722
|
+
],
|
|
13579
14723
|
},
|
|
13580
|
-
}
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
/**
|
|
13587
|
-
* Core sync logic: fetches item attestations from EAS for configured models and given addresses,
|
|
13588
|
-
* then saves seeds, versions, and properties to the local DB.
|
|
13589
|
-
* Uses owned + watched addresses from DB when addresses are not provided.
|
|
13590
|
-
*/
|
|
13591
|
-
const runSyncFromEas = async (options) => {
|
|
13592
|
-
let addresses = options?.addresses ?? (await getAllAddressesFromDb());
|
|
13593
|
-
const additionalGetter = getGetAdditionalSyncAddresses();
|
|
13594
|
-
if (additionalGetter) {
|
|
13595
|
-
const additional = await additionalGetter();
|
|
13596
|
-
if (additional?.length) {
|
|
13597
|
-
const seen = new Set(addresses.map((a) => a.toLowerCase()));
|
|
13598
|
-
for (const addr of additional) {
|
|
13599
|
-
if (addr && !seen.has(addr.toLowerCase())) {
|
|
13600
|
-
seen.add(addr.toLowerCase());
|
|
13601
|
-
addresses = [...addresses, addr];
|
|
13602
|
-
}
|
|
13603
|
-
}
|
|
13604
|
-
}
|
|
13605
|
-
}
|
|
13606
|
-
if (!addresses || addresses.length === 0) {
|
|
14724
|
+
},
|
|
14725
|
+
});
|
|
14726
|
+
const easSyncActor = xstate.createActor(easSyncMachine);
|
|
14727
|
+
let easSyncActorStarted = false;
|
|
14728
|
+
function startEasSyncActor() {
|
|
14729
|
+
if (easSyncActorStarted) {
|
|
13607
14730
|
return;
|
|
13608
14731
|
}
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
// Skip schemas that don't have a corresponding model in the user's config
|
|
13617
|
-
// This can happen with "bytes32 image" if there's no Image model defined
|
|
13618
|
-
console.warn(`[item/events] [syncDbWithEas] Model not found for schema ${modelSchema.schema}, skipping`);
|
|
13619
|
-
continue;
|
|
13620
|
-
}
|
|
13621
|
-
try {
|
|
13622
|
-
await appDb
|
|
13623
|
-
.insert(modelUids)
|
|
13624
|
-
.values({
|
|
13625
|
-
modelId: foundModel.id,
|
|
13626
|
-
uid: modelSchema.id,
|
|
13627
|
-
})
|
|
13628
|
-
.onConflictDoNothing();
|
|
13629
|
-
}
|
|
13630
|
-
catch (err) {
|
|
13631
|
-
// Model may have been deleted by test teardown or another process; skip to avoid unhandled rejection
|
|
13632
|
-
const e = err;
|
|
13633
|
-
const code = e?.code ?? e?.rawCode ?? e?.cause?.code ?? e?.cause?.rawCode;
|
|
13634
|
-
if (code === 'SQLITE_CONSTRAINT_FOREIGNKEY' || code === 787) {
|
|
13635
|
-
continue;
|
|
13636
|
-
}
|
|
13637
|
-
throw err;
|
|
13638
|
-
}
|
|
13639
|
-
schemaUids.push(modelSchema.id);
|
|
13640
|
-
}
|
|
13641
|
-
// If no schemas were found, skip the rest of the sync process
|
|
13642
|
-
// This can happen when models exist but don't have schemas registered in EAS yet
|
|
13643
|
-
if (schemaUids.length === 0) {
|
|
13644
|
-
return;
|
|
14732
|
+
easSyncActorStarted = true;
|
|
14733
|
+
easSyncActor.start();
|
|
14734
|
+
}
|
|
14735
|
+
function newCorrelationId() {
|
|
14736
|
+
const c = globalThis.crypto;
|
|
14737
|
+
if (c?.randomUUID) {
|
|
14738
|
+
return c.randomUUID();
|
|
13645
14739
|
}
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
const itemVersions = await getItemVersionsFromEas({
|
|
13655
|
-
seedUids,
|
|
13656
|
-
excludeRevoked: false,
|
|
14740
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
14741
|
+
}
|
|
14742
|
+
function requestEasSyncFromEventBus() {
|
|
14743
|
+
startEasSyncActor();
|
|
14744
|
+
easSyncActor.send({
|
|
14745
|
+
type: 'REQUEST',
|
|
14746
|
+
correlationId: newCorrelationId(),
|
|
14747
|
+
source: 'event_bus',
|
|
13657
14748
|
});
|
|
13658
|
-
|
|
13659
|
-
|
|
14749
|
+
}
|
|
14750
|
+
function requestEasSyncFromAddressChange(addresses) {
|
|
14751
|
+
startEasSyncActor();
|
|
14752
|
+
easSyncActor.send({
|
|
14753
|
+
type: 'REQUEST',
|
|
14754
|
+
correlationId: newCorrelationId(),
|
|
14755
|
+
options: { addresses },
|
|
14756
|
+
source: 'address_change',
|
|
13660
14757
|
});
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
14758
|
+
}
|
|
14759
|
+
function requestEasSyncFromModelsInit() {
|
|
14760
|
+
startEasSyncActor();
|
|
14761
|
+
easSyncActor.send({
|
|
14762
|
+
type: 'REQUEST',
|
|
14763
|
+
correlationId: newCorrelationId(),
|
|
14764
|
+
source: 'models_init',
|
|
13664
14765
|
});
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
14766
|
+
}
|
|
14767
|
+
function sendEasSyncClientRequest(correlationId, options) {
|
|
14768
|
+
startEasSyncActor();
|
|
14769
|
+
easSyncActor.send({
|
|
14770
|
+
type: 'REQUEST',
|
|
14771
|
+
correlationId,
|
|
14772
|
+
options,
|
|
14773
|
+
source: 'client_api',
|
|
13669
14774
|
});
|
|
13670
|
-
|
|
13671
|
-
};
|
|
13672
|
-
const syncDbWithEasHandler = lodashEs.throttle(async (_) => {
|
|
13673
|
-
await runSyncFromEas();
|
|
13674
|
-
}, 30000, {
|
|
13675
|
-
leading: true,
|
|
13676
|
-
trailing: false,
|
|
13677
|
-
});
|
|
14775
|
+
}
|
|
13678
14776
|
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
};
|
|
14777
|
+
var easSyncManager = /*#__PURE__*/Object.freeze({
|
|
14778
|
+
__proto__: null,
|
|
14779
|
+
easSyncActor: easSyncActor,
|
|
14780
|
+
easSyncMachine: easSyncMachine,
|
|
14781
|
+
requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
|
|
14782
|
+
requestEasSyncFromEventBus: requestEasSyncFromEventBus,
|
|
14783
|
+
requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
|
|
14784
|
+
sendEasSyncClientRequest: sendEasSyncClientRequest,
|
|
14785
|
+
startEasSyncActor: startEasSyncActor
|
|
14786
|
+
});
|
|
13690
14787
|
|
|
13691
14788
|
/**
|
|
13692
14789
|
* @deprecated Use BaseArweaveClient.setHost() instead.
|
|
13693
14790
|
* This function is kept for backward compatibility but will be removed in a future version.
|
|
13694
14791
|
*/
|
|
13695
14792
|
const setArweaveDomain = (newDomain) => {
|
|
13696
|
-
BaseArweaveClient.
|
|
14793
|
+
BaseArweaveClient.setPreferredReadGateway(newDomain);
|
|
13697
14794
|
};
|
|
13698
14795
|
|
|
13699
|
-
const logger$
|
|
14796
|
+
const logger$g = debug('seedSdk:services:events');
|
|
13700
14797
|
const handleServiceSaveState = (event) => {
|
|
13701
14798
|
const { state, serviceId } = event;
|
|
13702
|
-
logger$
|
|
14799
|
+
logger$g(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
|
|
13703
14800
|
// TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
|
|
13704
14801
|
// localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
|
|
13705
14802
|
};
|
|
@@ -13708,7 +14805,8 @@ const setupServicesEventHandlers = () => {
|
|
|
13708
14805
|
};
|
|
13709
14806
|
|
|
13710
14807
|
const setupAllItemsEventHandlers = () => {
|
|
13711
|
-
|
|
14808
|
+
startEasSyncActor();
|
|
14809
|
+
eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
|
|
13712
14810
|
};
|
|
13713
14811
|
// Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
|
|
13714
14812
|
|
|
@@ -13742,9 +14840,9 @@ class BasePathResolver {
|
|
|
13742
14840
|
}
|
|
13743
14841
|
}
|
|
13744
14842
|
|
|
13745
|
-
const logger$
|
|
14843
|
+
const logger$f = debug('seedSdk:ClientManager:initialize');
|
|
13746
14844
|
const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, event } }) => {
|
|
13747
|
-
logger$
|
|
14845
|
+
logger$f('initialize from ClientManager');
|
|
13748
14846
|
const { isInitialized } = context;
|
|
13749
14847
|
if (!event || !('options' in event)) {
|
|
13750
14848
|
throw new Error('Initialize event must include options');
|
|
@@ -13867,11 +14965,14 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
|
|
|
13867
14965
|
dbConfig,
|
|
13868
14966
|
schemaFile,
|
|
13869
14967
|
schema,
|
|
13870
|
-
syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ??
|
|
14968
|
+
syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
|
|
13871
14969
|
} });
|
|
13872
14970
|
if (arweaveDomain) {
|
|
13873
14971
|
setArweaveDomain(arweaveDomain);
|
|
13874
14972
|
}
|
|
14973
|
+
void ensureReadGatewaySelected().catch(() => {
|
|
14974
|
+
/* non-blocking warm-up for read gateway probe */
|
|
14975
|
+
});
|
|
13875
14976
|
// Models are now Model instances, no registration needed
|
|
13876
14977
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
13877
14978
|
setupAllItemsEventHandlers();
|
|
@@ -13907,15 +15008,15 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
|
|
|
13907
15008
|
};
|
|
13908
15009
|
});
|
|
13909
15010
|
|
|
13910
|
-
const logger$
|
|
13911
|
-
const saveAppState
|
|
15011
|
+
const logger$e = debug('seedSdk:client:writeToDb');
|
|
15012
|
+
const saveAppState = xstate.fromCallback(({ sendBack, input: { key, value } }) => {
|
|
13912
15013
|
const _saveAppState = async () => {
|
|
13913
15014
|
try {
|
|
13914
15015
|
const appDb = BaseDb.getAppDb();
|
|
13915
15016
|
if (!appDb) {
|
|
13916
15017
|
// In test environments, continue anyway
|
|
13917
15018
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13918
|
-
logger$
|
|
15019
|
+
logger$e('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
|
|
13919
15020
|
return;
|
|
13920
15021
|
}
|
|
13921
15022
|
throw new Error('App DB not found');
|
|
@@ -13931,13 +15032,13 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
|
|
|
13931
15032
|
value: JSON.stringify(value),
|
|
13932
15033
|
},
|
|
13933
15034
|
});
|
|
13934
|
-
logger$
|
|
15035
|
+
logger$e('result', result);
|
|
13935
15036
|
}
|
|
13936
15037
|
catch (error) {
|
|
13937
|
-
logger$
|
|
15038
|
+
logger$e('[client/actors] [saveAppState] Error saving app state:', error);
|
|
13938
15039
|
// In test environments, continue anyway
|
|
13939
15040
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13940
|
-
logger$
|
|
15041
|
+
logger$e('[client/actors] [saveAppState] Continuing despite error in test environment');
|
|
13941
15042
|
return;
|
|
13942
15043
|
}
|
|
13943
15044
|
throw error;
|
|
@@ -13952,10 +15053,10 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
|
|
|
13952
15053
|
});
|
|
13953
15054
|
})
|
|
13954
15055
|
.catch((error) => {
|
|
13955
|
-
logger$
|
|
15056
|
+
logger$e('[client/actors] [saveAppState] Error in promise chain:', error);
|
|
13956
15057
|
// In test environments, still send success to allow state machine to progress
|
|
13957
15058
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13958
|
-
logger$
|
|
15059
|
+
logger$e('[client/actors] [saveAppState] Sending success despite error in test environment');
|
|
13959
15060
|
sendBack({
|
|
13960
15061
|
type: 'saveAppStateSuccess',
|
|
13961
15062
|
key,
|
|
@@ -13968,222 +15069,6 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
|
|
|
13968
15069
|
});
|
|
13969
15070
|
});
|
|
13970
15071
|
|
|
13971
|
-
const GET_FILES_METADATA = graphql(/* GraphQL */ `
|
|
13972
|
-
query GetFilesMetadata($where: AttestationWhereInput!) {
|
|
13973
|
-
filesMetadata: attestations(
|
|
13974
|
-
where: $where
|
|
13975
|
-
orderBy: [{ timeCreated: desc }]
|
|
13976
|
-
) {
|
|
13977
|
-
...attestationFields
|
|
13978
|
-
}
|
|
13979
|
-
}
|
|
13980
|
-
`);
|
|
13981
|
-
|
|
13982
|
-
const getMetadata = async (props) => {
|
|
13983
|
-
const appDb = BaseDb.getAppDb();
|
|
13984
|
-
let storageTransactionId;
|
|
13985
|
-
if (props) {
|
|
13986
|
-
storageTransactionId = props.storageTransactionId;
|
|
13987
|
-
}
|
|
13988
|
-
const whereClauses = [];
|
|
13989
|
-
if (storageTransactionId) {
|
|
13990
|
-
whereClauses.push(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'));
|
|
13991
|
-
whereClauses.push(drizzleOrm.eq(metadata$1.propertyValue, storageTransactionId));
|
|
13992
|
-
}
|
|
13993
|
-
const metadataRows = await appDb
|
|
13994
|
-
.select()
|
|
13995
|
-
.from(metadata$1)
|
|
13996
|
-
.where(drizzleOrm.and(...whereClauses));
|
|
13997
|
-
if (!metadataRows || metadataRows.length === 0) {
|
|
13998
|
-
return;
|
|
13999
|
-
}
|
|
14000
|
-
return metadataRows[0];
|
|
14001
|
-
};
|
|
14002
|
-
|
|
14003
|
-
const saveMetadata = async (metadataRecord, metadataValues) => {
|
|
14004
|
-
if (!metadataRecord.localId) {
|
|
14005
|
-
return;
|
|
14006
|
-
}
|
|
14007
|
-
const appDb = BaseDb.getAppDb();
|
|
14008
|
-
await appDb
|
|
14009
|
-
.update(metadata$1)
|
|
14010
|
-
.set({
|
|
14011
|
-
...metadataValues,
|
|
14012
|
-
updatedAt: Date.now(),
|
|
14013
|
-
})
|
|
14014
|
-
.where(drizzleOrm.eq(metadata$1.localId, metadataRecord.localId));
|
|
14015
|
-
};
|
|
14016
|
-
|
|
14017
|
-
const saveAppState = async (key, value) => {
|
|
14018
|
-
const appDb = BaseDb.getAppDb();
|
|
14019
|
-
await appDb
|
|
14020
|
-
.insert(appState)
|
|
14021
|
-
.values({
|
|
14022
|
-
key,
|
|
14023
|
-
value,
|
|
14024
|
-
})
|
|
14025
|
-
.onConflictDoUpdate({
|
|
14026
|
-
target: appState.key,
|
|
14027
|
-
set: {
|
|
14028
|
-
value,
|
|
14029
|
-
},
|
|
14030
|
-
});
|
|
14031
|
-
};
|
|
14032
|
-
|
|
14033
|
-
const logger$e = debug('seedSdk:files:download');
|
|
14034
|
-
// syncDbFiles helper - internal service removed, functionality moved here
|
|
14035
|
-
const syncDbFiles = async (endpoints) => {
|
|
14036
|
-
// TODO: Implement syncDbFiles functionality if needed
|
|
14037
|
-
// This was previously in @/services/internal/helpers
|
|
14038
|
-
logger$e('[download] syncDbFiles called but not yet implemented');
|
|
14039
|
-
return Promise.resolve();
|
|
14040
|
-
};
|
|
14041
|
-
const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
|
|
14042
|
-
if (!isBrowser()) {
|
|
14043
|
-
return;
|
|
14044
|
-
}
|
|
14045
|
-
await syncDbFiles();
|
|
14046
|
-
eventEmitter.emit('fs.downloadAll.success', { eventId });
|
|
14047
|
-
eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
|
|
14048
|
-
};
|
|
14049
|
-
const downloadAllFilesBinaryRequestHandler = async () => {
|
|
14050
|
-
let addresses;
|
|
14051
|
-
if (BaseDb.isAppDbReady()) {
|
|
14052
|
-
addresses = await getAllAddressesFromDb();
|
|
14053
|
-
}
|
|
14054
|
-
if (!BaseDb.isAppDbReady()) {
|
|
14055
|
-
// Wait for ClientManager to be ready (DB_INIT state or later)
|
|
14056
|
-
const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
|
|
14057
|
-
const { getClient } = clientManagerMod;
|
|
14058
|
-
const clientManager = getClient();
|
|
14059
|
-
const clientService = clientManager.getService();
|
|
14060
|
-
await xstate.waitFor(clientService, (snapshot) => {
|
|
14061
|
-
const state = snapshot.value;
|
|
14062
|
-
return state === 'dbInit' ||
|
|
14063
|
-
state === 'saveConfig' ||
|
|
14064
|
-
state === 'processSchemaFiles' ||
|
|
14065
|
-
state === 'addModelsToStore' ||
|
|
14066
|
-
state === 'addModelsToDb' ||
|
|
14067
|
-
state === 'idle';
|
|
14068
|
-
}, { timeout: 30000 });
|
|
14069
|
-
addresses = await getAllAddressesFromDb();
|
|
14070
|
-
}
|
|
14071
|
-
if (!addresses || addresses.length === 0) {
|
|
14072
|
-
return;
|
|
14073
|
-
}
|
|
14074
|
-
const queryClient = BaseQueryClient.getQueryClient();
|
|
14075
|
-
const easClient = BaseEasClient.getEasClient();
|
|
14076
|
-
const { filesMetadata } = await queryClient.fetchQuery({
|
|
14077
|
-
queryKey: ['getFilesMetadata', ...addresses],
|
|
14078
|
-
queryFn: async () => easClient.request(GET_FILES_METADATA, {
|
|
14079
|
-
where: {
|
|
14080
|
-
attester: {
|
|
14081
|
-
in: addresses,
|
|
14082
|
-
},
|
|
14083
|
-
schema: {
|
|
14084
|
-
is: {
|
|
14085
|
-
id: {
|
|
14086
|
-
equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
|
|
14087
|
-
},
|
|
14088
|
-
},
|
|
14089
|
-
},
|
|
14090
|
-
},
|
|
14091
|
-
}),
|
|
14092
|
-
});
|
|
14093
|
-
const filesRoot = BaseFileManager.getWorkingDir();
|
|
14094
|
-
await BaseFileManager.createDirIfNotExists(filesRoot);
|
|
14095
|
-
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
|
|
14096
|
-
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
|
|
14097
|
-
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
|
|
14098
|
-
const appDb = BaseDb.getAppDb();
|
|
14099
|
-
if (!appDb) {
|
|
14100
|
-
console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available');
|
|
14101
|
-
return [];
|
|
14102
|
-
}
|
|
14103
|
-
const excludedTransactionsQuery = await appDb
|
|
14104
|
-
.select()
|
|
14105
|
-
.from(appState)
|
|
14106
|
-
.where(drizzleOrm.eq(appState.key, 'excludedTransactions'));
|
|
14107
|
-
let excludedTransactions = new Set();
|
|
14108
|
-
if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
|
|
14109
|
-
const valueString = excludedTransactionsQuery[0].value;
|
|
14110
|
-
if (valueString) {
|
|
14111
|
-
const excludedTransactionsArray = JSON.parse(valueString);
|
|
14112
|
-
excludedTransactions = new Set(excludedTransactionsArray);
|
|
14113
|
-
}
|
|
14114
|
-
}
|
|
14115
|
-
const transactionIds = [];
|
|
14116
|
-
for (const fileMetadata of filesMetadata) {
|
|
14117
|
-
// Validate and parse decodedDataJson
|
|
14118
|
-
if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
|
|
14119
|
-
console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
|
|
14120
|
-
continue;
|
|
14121
|
-
}
|
|
14122
|
-
let json;
|
|
14123
|
-
try {
|
|
14124
|
-
json = JSON.parse(fileMetadata.decodedDataJson);
|
|
14125
|
-
}
|
|
14126
|
-
catch (error) {
|
|
14127
|
-
console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
|
|
14128
|
-
continue;
|
|
14129
|
-
}
|
|
14130
|
-
if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
|
|
14131
|
-
console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
|
|
14132
|
-
continue;
|
|
14133
|
-
}
|
|
14134
|
-
const transactionId = json[0].value.value;
|
|
14135
|
-
if (excludedTransactions.has(transactionId)) {
|
|
14136
|
-
continue;
|
|
14137
|
-
}
|
|
14138
|
-
transactionIds.push(transactionId);
|
|
14139
|
-
}
|
|
14140
|
-
const transactionIdsToDownload = [];
|
|
14141
|
-
for (const transactionId of transactionIds) {
|
|
14142
|
-
try {
|
|
14143
|
-
// Use BaseArweaveClient for transaction status check
|
|
14144
|
-
const status = await BaseArweaveClient.getTransactionStatus(transactionId);
|
|
14145
|
-
if (status.status !== 200) {
|
|
14146
|
-
logger$e(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`);
|
|
14147
|
-
excludedTransactions.add(transactionId);
|
|
14148
|
-
await saveAppState('excludedTransactions', JSON.stringify(Array.from(excludedTransactions)));
|
|
14149
|
-
continue;
|
|
14150
|
-
}
|
|
14151
|
-
// Use BaseArweaveClient for getting transaction tags
|
|
14152
|
-
const tags = await queryClient.fetchQuery({
|
|
14153
|
-
queryKey: ['getTransactionTags', transactionId],
|
|
14154
|
-
queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
|
|
14155
|
-
});
|
|
14156
|
-
if (tags && tags.length > 0) {
|
|
14157
|
-
for (const { name, value } of tags) {
|
|
14158
|
-
if (name === 'Content-SHA-256') {
|
|
14159
|
-
const metadataRecord = await getMetadata({
|
|
14160
|
-
storageTransactionId: transactionId,
|
|
14161
|
-
});
|
|
14162
|
-
if (metadataRecord) {
|
|
14163
|
-
await saveMetadata(metadataRecord, {
|
|
14164
|
-
contentHash: value,
|
|
14165
|
-
});
|
|
14166
|
-
}
|
|
14167
|
-
}
|
|
14168
|
-
}
|
|
14169
|
-
}
|
|
14170
|
-
transactionIdsToDownload.push(transactionId);
|
|
14171
|
-
}
|
|
14172
|
-
catch (error) {
|
|
14173
|
-
logger$e(error);
|
|
14174
|
-
}
|
|
14175
|
-
}
|
|
14176
|
-
await BaseFileManager.downloadAllFiles({
|
|
14177
|
-
transactionIds: transactionIdsToDownload,
|
|
14178
|
-
arweaveHost: BaseArweaveClient.getHost(),
|
|
14179
|
-
excludedTransactions,
|
|
14180
|
-
});
|
|
14181
|
-
await BaseFileManager.resizeAllImages({
|
|
14182
|
-
width: 480,
|
|
14183
|
-
height: 480,
|
|
14184
|
-
});
|
|
14185
|
-
};
|
|
14186
|
-
|
|
14187
15072
|
let isInitialized = false;
|
|
14188
15073
|
const fsInitHandler = async () => {
|
|
14189
15074
|
if (isInitialized) {
|
|
@@ -14349,7 +15234,7 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
14349
15234
|
}
|
|
14350
15235
|
const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
|
|
14351
15236
|
// Fetch schemas from EAS in background - do not block init. EAS can be slow (10s+);
|
|
14352
|
-
// modelUids will be populated async and
|
|
15237
|
+
// modelUids will be populated async and EAS sync orchestrator runs when done.
|
|
14353
15238
|
const fetchEasAndPopulateModelUids = async () => {
|
|
14354
15239
|
try {
|
|
14355
15240
|
const queryClient = BaseQueryClient.getQueryClient();
|
|
@@ -14382,7 +15267,8 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
14382
15267
|
}
|
|
14383
15268
|
}
|
|
14384
15269
|
}
|
|
14385
|
-
|
|
15270
|
+
const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
|
|
15271
|
+
requestEasSyncFromModelsInit();
|
|
14386
15272
|
}
|
|
14387
15273
|
else {
|
|
14388
15274
|
logger$b('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
|
|
@@ -16724,16 +17610,19 @@ function addressesFromPersistedAddressValue(value) {
|
|
|
16724
17610
|
return out;
|
|
16725
17611
|
}
|
|
16726
17612
|
function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
|
|
17613
|
+
const merged = addressesFromPersistedAddressValue(event.value);
|
|
16727
17614
|
if (!context.syncFromEasOnAddressChange)
|
|
16728
17615
|
return;
|
|
16729
17616
|
if (event.key !== "addresses")
|
|
16730
17617
|
return;
|
|
16731
|
-
const merged = addressesFromPersistedAddressValue(event.value);
|
|
16732
17618
|
if (merged.length === 0)
|
|
16733
17619
|
return;
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
}
|
|
17620
|
+
try {
|
|
17621
|
+
requestEasSyncFromAddressChange(merged);
|
|
17622
|
+
}
|
|
17623
|
+
catch (err) {
|
|
17624
|
+
logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
|
|
17625
|
+
}
|
|
16737
17626
|
}
|
|
16738
17627
|
function emitAddressesPersistedIfAddressesKey(event) {
|
|
16739
17628
|
if (event.key !== "addresses")
|
|
@@ -16751,7 +17640,7 @@ const clientManagerMachine = xstate.setup({
|
|
|
16751
17640
|
fileSystemInit,
|
|
16752
17641
|
dbInit,
|
|
16753
17642
|
saveConfig,
|
|
16754
|
-
saveAppState
|
|
17643
|
+
saveAppState,
|
|
16755
17644
|
addModelsToStore,
|
|
16756
17645
|
addModelsToDb,
|
|
16757
17646
|
processSchemaFiles,
|
|
@@ -17075,7 +17964,16 @@ const clientInstance = {
|
|
|
17075
17964
|
*/
|
|
17076
17965
|
syncFromEas: async (options) => {
|
|
17077
17966
|
ensureInitialized();
|
|
17078
|
-
|
|
17967
|
+
startEasSyncActor();
|
|
17968
|
+
const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
|
|
17969
|
+
? globalThis.crypto.randomUUID()
|
|
17970
|
+
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
17971
|
+
sendEasSyncClientRequest(correlationId, options);
|
|
17972
|
+
await xstate.waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
|
|
17973
|
+
const snap = easSyncActor.getSnapshot();
|
|
17974
|
+
if (snap.context.lastFinishedStatus === 'failed') {
|
|
17975
|
+
throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
|
|
17976
|
+
}
|
|
17079
17977
|
},
|
|
17080
17978
|
addModel: async (modelDef) => {
|
|
17081
17979
|
const db = await BaseDb.getAppDb();
|
|
@@ -17285,7 +18183,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
|
|
|
17285
18183
|
// Lazy import cache for ModelProperty to avoid circular dependency
|
|
17286
18184
|
// Eagerly start loading to minimize delay on first access
|
|
17287
18185
|
let ModelPropertyClass = null;
|
|
17288
|
-
const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-
|
|
18186
|
+
const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-Ov1_YL9l.js'); })
|
|
17289
18187
|
.then(module => {
|
|
17290
18188
|
ModelPropertyClass = module.ModelProperty;
|
|
17291
18189
|
return ModelPropertyClass;
|
|
@@ -17302,7 +18200,7 @@ function getModelProperty() {
|
|
|
17302
18200
|
}
|
|
17303
18201
|
// Lazy import cache for Schema to avoid circular dependency
|
|
17304
18202
|
let SchemaClass = null;
|
|
17305
|
-
const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-
|
|
18203
|
+
const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-CeG5iRX_.js'); })
|
|
17306
18204
|
.then(module => {
|
|
17307
18205
|
SchemaClass = module.Schema;
|
|
17308
18206
|
return SchemaClass;
|
|
@@ -19256,7 +20154,7 @@ class Db extends BaseDb {
|
|
|
19256
20154
|
// You can inspect what will happen before applying
|
|
19257
20155
|
await apply();
|
|
19258
20156
|
this.db = db;
|
|
19259
|
-
const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-
|
|
20157
|
+
const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-LDYghZxU.js'); });
|
|
19260
20158
|
await backfillMetadataPropertyIds();
|
|
19261
20159
|
return this.db;
|
|
19262
20160
|
}
|
|
@@ -19903,7 +20801,7 @@ const getTsImport = async (filePath) => {
|
|
|
19903
20801
|
|
|
19904
20802
|
// Get the directory of this file to resolve relative paths
|
|
19905
20803
|
// @ts-ignore - rollup plugin-typescript doesn't recognize import.meta with module: "preserve"
|
|
19906
|
-
const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cjs/index-
|
|
20804
|
+
const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cjs/index-Far6-WGM.js', document.baseURI).href)));
|
|
19907
20805
|
path.dirname(__filename$1);
|
|
19908
20806
|
const commandExists = (command) => {
|
|
19909
20807
|
try {
|
|
@@ -20151,6 +21049,7 @@ QueryClient.getQueryClient = () => {
|
|
|
20151
21049
|
reject(new Error('Not implemented'));
|
|
20152
21050
|
});
|
|
20153
21051
|
},
|
|
21052
|
+
removeQueries: async () => { },
|
|
20154
21053
|
};
|
|
20155
21054
|
};
|
|
20156
21055
|
BaseQueryClient.setPlatformClass(QueryClient);
|
|
@@ -20365,23 +21264,30 @@ immer.enableMapSet();
|
|
|
20365
21264
|
|
|
20366
21265
|
exports.BaseArweaveClient = BaseArweaveClient;
|
|
20367
21266
|
exports.BaseDb = BaseDb;
|
|
21267
|
+
exports.BaseEasClient = BaseEasClient;
|
|
20368
21268
|
exports.BaseFileManager = BaseFileManager;
|
|
20369
21269
|
exports.BaseFileManager$1 = BaseFileManager$1;
|
|
20370
21270
|
exports.BasePathResolver = BasePathResolver;
|
|
21271
|
+
exports.BaseQueryClient = BaseQueryClient;
|
|
20371
21272
|
exports.Boolean = Boolean$1;
|
|
20372
21273
|
exports.ClientManager = ClientManager;
|
|
20373
21274
|
exports.ConflictError = ConflictError;
|
|
20374
21275
|
exports.DEFAULT_TEXT_MAX_LENGTH = DEFAULT_TEXT_MAX_LENGTH;
|
|
20375
21276
|
exports.Date = Date$1;
|
|
20376
21277
|
exports.Db = Db;
|
|
21278
|
+
exports.EAS_SEED_DATA_SYNCED_TO_DB_EVENT = EAS_SEED_DATA_SYNCED_TO_DB_EVENT;
|
|
20377
21279
|
exports.File = File$1;
|
|
20378
21280
|
exports.FileManager = FileManager;
|
|
21281
|
+
exports.GET_PROPERTIES = GET_PROPERTIES;
|
|
21282
|
+
exports.GET_SEEDS = GET_SEEDS;
|
|
21283
|
+
exports.GET_VERSIONS = GET_VERSIONS;
|
|
20379
21284
|
exports.Html = Html;
|
|
20380
21285
|
exports.INIT_SCRIPT_SUCCESS_MESSAGE = INIT_SCRIPT_SUCCESS_MESSAGE;
|
|
20381
21286
|
exports.INTERNAL_DATA_TYPES = INTERNAL_DATA_TYPES;
|
|
20382
21287
|
exports.INTERNAL_PROPERTY_NAMES = INTERNAL_PROPERTY_NAMES;
|
|
20383
21288
|
exports.Image = Image;
|
|
20384
21289
|
exports.Item = Item;
|
|
21290
|
+
exports.Item$1 = Item$1;
|
|
20385
21291
|
exports.ItemProperty = ItemProperty;
|
|
20386
21292
|
exports.Json = Json;
|
|
20387
21293
|
exports.List = List;
|
|
@@ -20422,12 +21328,14 @@ exports.createReactiveProxy = createReactiveProxy;
|
|
|
20422
21328
|
exports.db = db;
|
|
20423
21329
|
exports.defaultAttestationData = defaultAttestationData;
|
|
20424
21330
|
exports.eas = eas;
|
|
21331
|
+
exports.escapeSqliteString = escapeSqliteString;
|
|
20425
21332
|
exports.eventEmitter = eventEmitter;
|
|
20426
21333
|
exports.findEntity = findEntity;
|
|
20427
21334
|
exports.findSeedBinary = findSeedBinary;
|
|
20428
21335
|
exports.forceRemoveFromCaches = forceRemoveFromCaches;
|
|
20429
21336
|
exports.generateId = generateId;
|
|
20430
21337
|
exports.generateModelCode = generateModelCode;
|
|
21338
|
+
exports.getAllAddressesFromDb = getAllAddressesFromDb;
|
|
20431
21339
|
exports.getClient = getClient;
|
|
20432
21340
|
exports.getContentHash = getContentHash;
|
|
20433
21341
|
exports.getCorrectId = getCorrectId;
|
|
@@ -20436,14 +21344,18 @@ exports.getEasSchemaUidForModel = getEasSchemaUidForModel;
|
|
|
20436
21344
|
exports.getEasSchemaUidForSchemaDefinition = getEasSchemaUidForSchemaDefinition;
|
|
20437
21345
|
exports.getGetAdditionalSyncAddresses = getGetAdditionalSyncAddresses;
|
|
20438
21346
|
exports.getItemData = getItemData;
|
|
21347
|
+
exports.getItemPropertiesFromEas = getItemPropertiesFromEas;
|
|
21348
|
+
exports.getItemVersionsFromEas = getItemVersionsFromEas;
|
|
20439
21349
|
exports.getLatestPublishedVersionRow = getLatestPublishedVersionRow;
|
|
20440
21350
|
exports.getLatestSchemaVersion = getLatestSchemaVersion;
|
|
20441
21351
|
exports.getModelId = getModelId;
|
|
20442
21352
|
exports.getModelIdByFileId = getModelIdByFileId;
|
|
21353
|
+
exports.getModelSchemasFromEas = getModelSchemasFromEas;
|
|
20443
21354
|
exports.getOwnedAddressesFromDb = getOwnedAddressesFromDb;
|
|
20444
21355
|
exports.getPropertyData = getPropertyData$1;
|
|
20445
21356
|
exports.getPropertyIdForModelAndName = getPropertyIdForModelAndName;
|
|
20446
21357
|
exports.getRefValueType = getRefValueType;
|
|
21358
|
+
exports.getSeedsFromSchemaUids = getSeedsFromSchemaUids;
|
|
20447
21359
|
exports.getTsImport = getTsImport;
|
|
20448
21360
|
exports.htmlEmbeddedImageCoPublish = htmlEmbeddedImageCoPublish;
|
|
20449
21361
|
exports.importJsonSchema = importJsonSchema;
|
|
@@ -20460,8 +21372,10 @@ exports.modelUids = modelUids;
|
|
|
20460
21372
|
exports.models = models$1;
|
|
20461
21373
|
exports.normalizeDataType = normalizeDataType;
|
|
20462
21374
|
exports.normalizeRelationPropertyValue = normalizeRelationPropertyValue;
|
|
21375
|
+
exports.parseEasRelationPropertyName = parseEasRelationPropertyName;
|
|
20463
21376
|
exports.parseListPropertyValueFromStorage = parseListPropertyValueFromStorage;
|
|
20464
21377
|
exports.parseMarkdownFrontmatter = parseMarkdownFrontmatter;
|
|
21378
|
+
exports.pickLatestPropertyAttestationsByRefAndSchema = pickLatestPropertyAttestationsByRefAndSchema;
|
|
20465
21379
|
exports.processSeedConfig = processSeedConfig;
|
|
20466
21380
|
exports.properties = properties;
|
|
20467
21381
|
exports.readJsonImportFile = readJsonImportFile;
|
|
@@ -20470,10 +21384,12 @@ exports.resolveStorageNameToSchemaName = resolveStorageNameToSchemaName;
|
|
|
20470
21384
|
exports.runDestroyLifecycle = runDestroyLifecycle;
|
|
20471
21385
|
exports.runSeedInit = runSeedInit;
|
|
20472
21386
|
exports.saveModelsFromMarkdown = saveModelsFromMarkdown;
|
|
21387
|
+
exports.scheduleBulkFilesDownloadFromEasSync = scheduleBulkFilesDownloadFromEasSync;
|
|
20473
21388
|
exports.schema = schema$1;
|
|
20474
21389
|
exports.schema$1 = schema;
|
|
20475
21390
|
exports.schemas = schemas;
|
|
20476
21391
|
exports.seeds = seeds;
|
|
21392
|
+
exports.setSchemaUidForSchemaDefinition = setSchemaUidForSchemaDefinition;
|
|
20477
21393
|
exports.setupEntityLiveQuery = setupEntityLiveQuery;
|
|
20478
21394
|
exports.syncSchemaFromSource = syncSchemaFromSource;
|
|
20479
21395
|
exports.toSnakeCase = toSnakeCase;
|
|
@@ -20483,4 +21399,4 @@ exports.versions = versions;
|
|
|
20483
21399
|
exports.waitForEntityIdle = waitForEntityIdle;
|
|
20484
21400
|
exports.withSeed = withSeed;
|
|
20485
21401
|
exports.writeProcessMachine = writeProcessMachine;
|
|
20486
|
-
//# sourceMappingURL=index-
|
|
21402
|
+
//# sourceMappingURL=index-Far6-WGM.js.map
|