@seedprotocol/sdk 0.4.21 → 0.4.22
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-B-vm2Xae.js} +3 -3
- package/dist/{ArweaveClient-DxpJnJXU.js.map → ArweaveClient-B-vm2Xae.js.map} +1 -1
- package/dist/{ArweaveClient-Cz9ZLiEV.js → ArweaveClient-C-eLH0zU.js} +3 -3
- package/dist/{ArweaveClient-Cz9ZLiEV.js.map → ArweaveClient-C-eLH0zU.js.map} +1 -1
- package/dist/{Db-CXwQVLZv.js → Db-B7whB3oJ.js} +107 -6
- package/dist/Db-B7whB3oJ.js.map +1 -0
- package/dist/{Db-DkTBncAM.js → Db-nir1xVHg.js} +4 -4
- package/dist/{Db-DkTBncAM.js.map → Db-nir1xVHg.js.map} +1 -1
- package/dist/{EasClient-DjpbHjU9.js → EasClient-BH_feMaX.js} +2 -2
- package/dist/{EasClient-JYkmHxu1.js.map → EasClient-BH_feMaX.js.map} +1 -1
- package/dist/{EasClient-JYkmHxu1.js → EasClient-CFguAKBp.js} +2 -2
- package/dist/{EasClient-DjpbHjU9.js.map → EasClient-CFguAKBp.js.map} +1 -1
- package/dist/{FileManager-CKyoLrBP.js → FileManager-BR3jtuSl.js} +2 -2
- package/dist/{FileManager-CKyoLrBP.js.map → FileManager-BR3jtuSl.js.map} +1 -1
- package/dist/{FileManager-DHnyb040.js → FileManager-C2uXql_C.js} +18 -2
- package/dist/FileManager-C2uXql_C.js.map +1 -0
- package/dist/{ModelProperty-DWtv9fQr.js → ModelProperty-CIeLasI4.js} +24 -24
- package/dist/{ModelProperty-DWtv9fQr.js.map → ModelProperty-CIeLasI4.js.map} +1 -1
- package/dist/{PathResolver-Ce4K9acQ.js → PathResolver-CZoSnHBU.js} +2 -2
- package/dist/{PathResolver-Ce4K9acQ.js.map → PathResolver-CZoSnHBU.js.map} +1 -1
- package/dist/{PathResolver-pmw--Ea2.js → PathResolver-DnrG1hUX.js} +2 -2
- package/dist/{PathResolver-pmw--Ea2.js.map → PathResolver-DnrG1hUX.js.map} +1 -1
- package/dist/{QueryClient-OUjfvY3g.js → QueryClient-DJOrJZRR.js} +3 -2
- package/dist/QueryClient-DJOrJZRR.js.map +1 -0
- package/dist/{QueryClient-unspcsWa.js → QueryClient-PqOg8mcw.js} +7 -3
- package/dist/QueryClient-PqOg8mcw.js.map +1 -0
- package/dist/{Schema-CqqcEexA.js → Schema-B3YQHTtu.js} +38 -38
- package/dist/{Schema-CqqcEexA.js.map → Schema-B3YQHTtu.js.map} +1 -1
- package/dist/{SchemaValidationService-Cb-b4kpD.js → SchemaValidationService-C4DIwn8Z.js} +2 -2
- package/dist/{SchemaValidationService-Cb-b4kpD.js.map → SchemaValidationService-C4DIwn8Z.js.map} +1 -1
- package/dist/{backfillMetadataPropertyIds-CRyRez3h.js → backfillMetadataPropertyIds-CBlRaU_M.js} +2 -2
- package/dist/{backfillMetadataPropertyIds-CRyRez3h.js.map → backfillMetadataPropertyIds-CBlRaU_M.js.map} +1 -1
- package/dist/cjs/{ModelProperty-sNx_ZQZX.js → ModelProperty-tfM38NL4.js} +17 -17
- package/dist/cjs/{ModelProperty-sNx_ZQZX.js.map → ModelProperty-tfM38NL4.js.map} +1 -1
- package/dist/cjs/{Schema-B4RRA-0g.js → Schema-44NqLqMV.js} +20 -20
- package/dist/cjs/{Schema-B4RRA-0g.js.map → Schema-44NqLqMV.js.map} +1 -1
- package/dist/cjs/{SchemaValidationService-DCflhpcI.js → SchemaValidationService-Cq_YBzFN.js} +2 -2
- package/dist/cjs/{SchemaValidationService-DCflhpcI.js.map → SchemaValidationService-Cq_YBzFN.js.map} +1 -1
- package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js → backfillMetadataPropertyIds-D1nLJAhB.js} +2 -2
- package/dist/cjs/{backfillMetadataPropertyIds-DhAXAuSf.js.map → backfillMetadataPropertyIds-D1nLJAhB.js.map} +1 -1
- package/dist/cjs/{getItem-lyM2x5pT.js → getItem-BRoq91YU.js} +2 -2
- package/dist/cjs/{getItem-lyM2x5pT.js.map → getItem-BRoq91YU.js.map} +1 -1
- package/dist/cjs/{getPublishPayload-DP2fm4q8.js → getPublishPayload-ddl-1x6R.js} +11 -11
- package/dist/cjs/{getPublishPayload-DP2fm4q8.js.map → getPublishPayload-ddl-1x6R.js.map} +1 -1
- package/dist/cjs/{getPublishUploads-DdVy-5fK.js → getPublishUploads-BljRx4o4.js} +39 -6
- package/dist/cjs/getPublishUploads-BljRx4o4.js.map +1 -0
- package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js → getSegmentedItemProperties-iK5kepzl.js} +3 -3
- package/dist/cjs/{getSegmentedItemProperties-DtHofn5i.js.map → getSegmentedItemProperties-iK5kepzl.js.map} +1 -1
- package/dist/cjs/{index-D1qR8xnb.js → index-C6rrqy3z.js} +1980 -1113
- package/dist/cjs/index-C6rrqy3z.js.map +1 -0
- package/dist/cjs/{index-DTkoTvcq.js → index-DqSDhOp3.js} +3 -3
- package/dist/cjs/index-DqSDhOp3.js.map +1 -0
- package/dist/cjs/{ownership-DanM_n8E.js → ownership-CXlKAj4o.js} +2 -2
- package/dist/cjs/{ownership-DanM_n8E.js.map → ownership-CXlKAj4o.js.map} +1 -1
- package/dist/cjs/{property-BQokoaRe.js → property-2D7P6a2q.js} +4 -4
- package/dist/cjs/{property-BQokoaRe.js.map → property-2D7P6a2q.js.map} +1 -1
- package/dist/cjs/syncDbWithEas-DcKL-_Pb.js +610 -0
- package/dist/cjs/syncDbWithEas-DcKL-_Pb.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-CV3yTCRt.js} +2 -2
- package/dist/{getItem-VI3QqdZH.js.map → getItem-CV3yTCRt.js.map} +1 -1
- package/dist/{getPublishPayload-DpYwi-rd.js → getPublishPayload-Ddc_LGPs.js} +14 -14
- package/dist/{getPublishPayload-DpYwi-rd.js.map → getPublishPayload-Ddc_LGPs.js.map} +1 -1
- package/dist/{getPublishUploads-DS2dQ4Ho.js → getPublishUploads-Cf2J-5FR.js} +39 -6
- package/dist/getPublishUploads-Cf2J-5FR.js.map +1 -0
- package/dist/{getSegmentedItemProperties-Bz5B4DSA.js → getSegmentedItemProperties-B2mzArFD.js} +3 -3
- package/dist/{getSegmentedItemProperties-Bz5B4DSA.js.map → getSegmentedItemProperties-B2mzArFD.js.map} +1 -1
- package/dist/{index-Cqf_DxkJ.js → index-3Ekqb4QB.js} +3 -3
- package/dist/index-3Ekqb4QB.js.map +1 -0
- package/dist/{index-DdzhrbkF.js → index-BRo7D3s1.js} +3 -2
- package/dist/index-BRo7D3s1.js.map +1 -0
- package/dist/{index-BrD_NNaX.js → index-DUMXLKJr.js} +1991 -1125
- package/dist/index-DUMXLKJr.js.map +1 -0
- package/dist/main.cjs +1 -1
- package/dist/main.js +16 -41
- package/dist/main.js.map +1 -1
- package/dist/node.js +10 -10
- package/dist/{ownership-BK6suksO.js → ownership-TR-mIjJh.js} +2 -2
- package/dist/{ownership-BK6suksO.js.map → ownership-TR-mIjJh.js.map} +1 -1
- package/dist/{property-C63Ddzap.js → property-BSNWvgei.js} +6 -6
- package/dist/{property-C63Ddzap.js.map → property-BSNWvgei.js.map} +1 -1
- package/dist/{queries-BGuWjEqt.js → queries-0FZBThGQ.js} +2 -2
- package/dist/{queries-BGuWjEqt.js.map → queries-0FZBThGQ.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/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/syncDbWithEas-CaytdS8D.js +583 -0
- package/dist/syncDbWithEas-CaytdS8D.js.map +1 -0
- package/dist/updateSeedRevokedAt-CfUXirik.js +22 -0
- package/dist/updateSeedRevokedAt-CfUXirik.js.map +1 -0
- package/package.json +1 -1
- package/dist/Db-CXwQVLZv.js.map +0 -1
- package/dist/FileManager-DHnyb040.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/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
|
@@ -198,6 +198,13 @@ class BaseFileManager {
|
|
|
198
198
|
static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
|
|
199
199
|
return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
|
|
200
200
|
}
|
|
201
|
+
static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
|
|
202
|
+
return this.PlatformClass.downloadAllFiles({
|
|
203
|
+
transactionIds: [transactionId],
|
|
204
|
+
arweaveHost,
|
|
205
|
+
excludedTransactions,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
201
208
|
static resizeImage({ filePath, width, height }) {
|
|
202
209
|
return this.PlatformClass.resizeImage({ filePath, width, height });
|
|
203
210
|
}
|
|
@@ -406,8 +413,51 @@ var SeedModels;
|
|
|
406
413
|
// Internal SDK schema that should not be created in app's files directory
|
|
407
414
|
const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
|
|
408
415
|
const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
|
|
409
|
-
/** Default Arweave gateway host used across all packages */
|
|
410
|
-
const DEFAULT_ARWEAVE_HOST = '
|
|
416
|
+
/** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
|
|
417
|
+
const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
|
|
418
|
+
/**
|
|
419
|
+
* Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
|
|
420
|
+
* Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
|
|
421
|
+
*/
|
|
422
|
+
const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
|
|
423
|
+
const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
|
|
424
|
+
/** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
|
|
425
|
+
function getDefaultArweaveReadGatewayHostsOrdered() {
|
|
426
|
+
if (typeof process === 'undefined' || !process.env) {
|
|
427
|
+
return [...DEFAULT_ARWEAVE_GATEWAYS];
|
|
428
|
+
}
|
|
429
|
+
for (const key of READ_GATEWAYS_ENV_KEYS) {
|
|
430
|
+
const raw = process.env[key]?.trim();
|
|
431
|
+
if (raw) {
|
|
432
|
+
return raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return [...DEFAULT_ARWEAVE_GATEWAYS];
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Deduped host list: primary first, then each default not already present (case-insensitive).
|
|
439
|
+
*/
|
|
440
|
+
function mergePrimaryHostWithDefaults(primary, defaults) {
|
|
441
|
+
const seen = new Set();
|
|
442
|
+
const out = [];
|
|
443
|
+
const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
|
|
444
|
+
const add = (h) => {
|
|
445
|
+
const t = h.trim().replace(/\/$/, '');
|
|
446
|
+
if (!t)
|
|
447
|
+
return;
|
|
448
|
+
const k = keyOf(t);
|
|
449
|
+
if (seen.has(k))
|
|
450
|
+
return;
|
|
451
|
+
seen.add(k);
|
|
452
|
+
out.push(t);
|
|
453
|
+
};
|
|
454
|
+
add(primary);
|
|
455
|
+
for (const d of defaults)
|
|
456
|
+
add(d);
|
|
457
|
+
return out;
|
|
458
|
+
}
|
|
459
|
+
/** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
|
|
460
|
+
const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
|
|
411
461
|
/**
|
|
412
462
|
* Check if a schema is an internal SDK schema that should not be created in app files
|
|
413
463
|
*/
|
|
@@ -419,7 +469,9 @@ function isInternalSchema(schemaName, schemaId) {
|
|
|
419
469
|
var constants = /*#__PURE__*/Object.freeze({
|
|
420
470
|
__proto__: null,
|
|
421
471
|
CLIENT_NOT_INITIALIZED: CLIENT_NOT_INITIALIZED,
|
|
472
|
+
DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
|
|
422
473
|
DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
|
|
474
|
+
EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
|
|
423
475
|
INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
|
|
424
476
|
INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
|
|
425
477
|
INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
|
|
@@ -437,7 +489,9 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
437
489
|
ZERO_BYTES: ZERO_BYTES,
|
|
438
490
|
ZERO_BYTES32: ZERO_BYTES32,
|
|
439
491
|
defaultAttestationData: defaultAttestationData,
|
|
440
|
-
|
|
492
|
+
getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
|
|
493
|
+
isInternalSchema: isInternalSchema,
|
|
494
|
+
mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
|
|
441
495
|
});
|
|
442
496
|
|
|
443
497
|
function parseGateway(input) {
|
|
@@ -454,6 +508,8 @@ function parseGateway(input) {
|
|
|
454
508
|
let _host = DEFAULT_ARWEAVE_HOST;
|
|
455
509
|
let _protocol = 'https';
|
|
456
510
|
let _hostExplicitlySet = false;
|
|
511
|
+
/** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
|
|
512
|
+
let _suppressEnvGatewayOverride = false;
|
|
457
513
|
class BaseArweaveClient {
|
|
458
514
|
static setPlatformClass(platformClass) {
|
|
459
515
|
this.PlatformClass = platformClass;
|
|
@@ -466,7 +522,7 @@ class BaseArweaveClient {
|
|
|
466
522
|
const envHost = typeof process !== 'undefined' && process.env
|
|
467
523
|
? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
|
|
468
524
|
: undefined;
|
|
469
|
-
if (envHost && !_hostExplicitlySet) {
|
|
525
|
+
if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
|
|
470
526
|
return parseGateway(envHost);
|
|
471
527
|
}
|
|
472
528
|
}
|
|
@@ -504,6 +560,39 @@ class BaseArweaveClient {
|
|
|
504
560
|
_host = parsed.host;
|
|
505
561
|
_protocol = parsed.protocol;
|
|
506
562
|
_hostExplicitlySet = true;
|
|
563
|
+
_suppressEnvGatewayOverride = false;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* When true, read-path gateway probing does not change the host ({@link setHost}).
|
|
567
|
+
*/
|
|
568
|
+
static isReadGatewayLocked() {
|
|
569
|
+
return _hostExplicitlySet;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* @internal Clears env override suppression after probing (for test isolation).
|
|
573
|
+
*/
|
|
574
|
+
static resetReadGatewaySelectionStateForTests() {
|
|
575
|
+
_suppressEnvGatewayOverride = false;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
|
|
579
|
+
* Used for seed `arweaveDomain`.
|
|
580
|
+
*/
|
|
581
|
+
static setPreferredReadGateway(host) {
|
|
582
|
+
const parsed = parseGateway(host);
|
|
583
|
+
_host = parsed.host;
|
|
584
|
+
_protocol = parsed.protocol;
|
|
585
|
+
_hostExplicitlySet = false;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
|
|
589
|
+
*/
|
|
590
|
+
static applyProbedReadGateway(host) {
|
|
591
|
+
const parsed = parseGateway(host);
|
|
592
|
+
_host = parsed.host;
|
|
593
|
+
_protocol = parsed.protocol;
|
|
594
|
+
_hostExplicitlySet = false;
|
|
595
|
+
_suppressEnvGatewayOverride = true;
|
|
507
596
|
}
|
|
508
597
|
/**
|
|
509
598
|
* Get the GraphQL endpoint URL
|
|
@@ -587,6 +676,11 @@ class BaseArweaveClient {
|
|
|
587
676
|
}
|
|
588
677
|
}
|
|
589
678
|
|
|
679
|
+
var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
|
|
680
|
+
__proto__: null,
|
|
681
|
+
BaseArweaveClient: BaseArweaveClient
|
|
682
|
+
});
|
|
683
|
+
|
|
590
684
|
/**
|
|
591
685
|
* Trim and strip a trailing slash from an upload API base URL.
|
|
592
686
|
*/
|
|
@@ -638,6 +732,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
|
|
|
638
732
|
}
|
|
639
733
|
}
|
|
640
734
|
|
|
735
|
+
const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
|
|
736
|
+
const PROBE_TIMEOUT_MS = 5000;
|
|
737
|
+
let readGatewayCache = null;
|
|
738
|
+
let ensureInFlight = null;
|
|
739
|
+
/** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
|
|
740
|
+
function invalidateReadGatewayCache() {
|
|
741
|
+
readGatewayCache = null;
|
|
742
|
+
ensureInFlight = null;
|
|
743
|
+
}
|
|
744
|
+
/** Clears probe cache, env override suppression, and preferred host (for tests). */
|
|
745
|
+
function resetArweaveReadGatewayForTests() {
|
|
746
|
+
invalidateReadGatewayCache();
|
|
747
|
+
BaseArweaveClient.resetReadGatewaySelectionStateForTests();
|
|
748
|
+
if (!BaseArweaveClient.isReadGatewayLocked()) {
|
|
749
|
+
BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* GET /info with timeout. Treat 2xx + JSON object as healthy.
|
|
754
|
+
*/
|
|
755
|
+
async function probeGateway(baseUrl, signal) {
|
|
756
|
+
const url = `${baseUrl.replace(/\/$/, '')}/info`;
|
|
757
|
+
let timer;
|
|
758
|
+
const controller = new AbortController();
|
|
759
|
+
const effectiveSignal = signal ?? controller.signal;
|
|
760
|
+
if (!signal) {
|
|
761
|
+
timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
762
|
+
}
|
|
763
|
+
try {
|
|
764
|
+
const response = await fetch(url, {
|
|
765
|
+
method: 'GET',
|
|
766
|
+
signal: effectiveSignal,
|
|
767
|
+
headers: { Accept: 'application/json' },
|
|
768
|
+
});
|
|
769
|
+
if (!response.ok)
|
|
770
|
+
return false;
|
|
771
|
+
const text = await response.text();
|
|
772
|
+
if (!text.trim())
|
|
773
|
+
return false;
|
|
774
|
+
try {
|
|
775
|
+
const json = JSON.parse(text);
|
|
776
|
+
return typeof json === 'object' && json !== null;
|
|
777
|
+
}
|
|
778
|
+
catch {
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
catch {
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
finally {
|
|
786
|
+
if (timer)
|
|
787
|
+
clearTimeout(timer);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
|
|
791
|
+
for (const host of hosts) {
|
|
792
|
+
const h = host.trim().replace(/\/$/, '');
|
|
793
|
+
if (!h)
|
|
794
|
+
continue;
|
|
795
|
+
const baseUrl = `${protocol}://${h}`;
|
|
796
|
+
if (await probeGateway(baseUrl, signal)) {
|
|
797
|
+
return h;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
function buildOrderedHostsForProbe() {
|
|
803
|
+
const primary = BaseArweaveClient.getHost();
|
|
804
|
+
const defaults = getDefaultArweaveReadGatewayHostsOrdered();
|
|
805
|
+
return mergePrimaryHostWithDefaults(primary, defaults);
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
|
|
809
|
+
* No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
|
|
810
|
+
* Uses a short TTL cache to avoid probing on every read.
|
|
811
|
+
*/
|
|
812
|
+
async function ensureReadGatewaySelected(signal) {
|
|
813
|
+
if (BaseArweaveClient.isReadGatewayLocked()) {
|
|
814
|
+
return BaseArweaveClient.getHost();
|
|
815
|
+
}
|
|
816
|
+
const now = Date.now();
|
|
817
|
+
if (readGatewayCache && now < readGatewayCache.expiresAt) {
|
|
818
|
+
return readGatewayCache.host;
|
|
819
|
+
}
|
|
820
|
+
if (ensureInFlight) {
|
|
821
|
+
return ensureInFlight;
|
|
822
|
+
}
|
|
823
|
+
ensureInFlight = (async () => {
|
|
824
|
+
const ordered = buildOrderedHostsForProbe();
|
|
825
|
+
const protocol = BaseArweaveClient.getProtocol();
|
|
826
|
+
const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
|
|
827
|
+
if (!BaseArweaveClient.isReadGatewayLocked()) {
|
|
828
|
+
if (picked) {
|
|
829
|
+
BaseArweaveClient.applyProbedReadGateway(picked);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
readGatewayCache = {
|
|
833
|
+
host: BaseArweaveClient.getHost(),
|
|
834
|
+
expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
|
|
835
|
+
};
|
|
836
|
+
return readGatewayCache.host;
|
|
837
|
+
})();
|
|
838
|
+
try {
|
|
839
|
+
return await ensureInFlight;
|
|
840
|
+
}
|
|
841
|
+
finally {
|
|
842
|
+
ensureInFlight = null;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
var selectReadGateway = /*#__PURE__*/Object.freeze({
|
|
847
|
+
__proto__: null,
|
|
848
|
+
ensureReadGatewaySelected: ensureReadGatewaySelected,
|
|
849
|
+
invalidateReadGatewayCache: invalidateReadGatewayCache,
|
|
850
|
+
probeGateway: probeGateway,
|
|
851
|
+
resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
|
|
852
|
+
selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
|
|
853
|
+
});
|
|
854
|
+
|
|
641
855
|
const GATEWAY_TX_QUERY = `
|
|
642
856
|
query ArweaveGatewayTransaction($id: String!) {
|
|
643
857
|
transaction(id: $id) {
|
|
@@ -734,6 +948,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
|
|
|
734
948
|
return null;
|
|
735
949
|
}
|
|
736
950
|
}
|
|
951
|
+
/**
|
|
952
|
+
* Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
|
|
953
|
+
* {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
|
|
954
|
+
* {@link getDefaultArweaveReadGatewayHostsOrdered}.
|
|
955
|
+
*/
|
|
956
|
+
async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
|
|
957
|
+
const defaults = getDefaultArweaveReadGatewayHostsOrdered();
|
|
958
|
+
const trimmed = graphqlUrl?.trim();
|
|
959
|
+
let protocol = 'https';
|
|
960
|
+
let preferredHost = null;
|
|
961
|
+
if (trimmed) {
|
|
962
|
+
try {
|
|
963
|
+
const u = new URL(trimmed);
|
|
964
|
+
protocol = u.protocol === 'http:' ? 'http' : 'https';
|
|
965
|
+
preferredHost = u.hostname || null;
|
|
966
|
+
}
|
|
967
|
+
catch {
|
|
968
|
+
preferredHost = null;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
const ordered = preferredHost && preferredHost.length > 0
|
|
972
|
+
? mergePrimaryHostWithDefaults(preferredHost, defaults)
|
|
973
|
+
: [...defaults];
|
|
974
|
+
const signal = init?.signal;
|
|
975
|
+
for (const host of ordered) {
|
|
976
|
+
const base = `${protocol}://${host}`;
|
|
977
|
+
if (!(await probeGateway(base, signal ?? undefined)))
|
|
978
|
+
continue;
|
|
979
|
+
const gqlUrl = `${protocol}://${host}/graphql`;
|
|
980
|
+
const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
|
|
981
|
+
if (result !== null) {
|
|
982
|
+
return result;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return null;
|
|
986
|
+
}
|
|
737
987
|
|
|
738
988
|
class BaseEasClient {
|
|
739
989
|
static setPlatformClass(platformClass) {
|
|
@@ -1409,6 +1659,19 @@ const arweaveL1FinalizeJobs = sqliteCore.sqliteTable('arweave_l1_finalize_jobs',
|
|
|
1409
1659
|
dataItemIdUnique: sqliteCore.uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
|
|
1410
1660
|
}));
|
|
1411
1661
|
|
|
1662
|
+
const easSyncProcesses = sqliteCore.sqliteTable('eas_sync_processes', {
|
|
1663
|
+
id: sqliteCore.int('id').primaryKey({ autoIncrement: true }),
|
|
1664
|
+
status: sqliteCore.text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
|
|
1665
|
+
startedAt: sqliteCore.int('started_at').notNull(),
|
|
1666
|
+
completedAt: sqliteCore.int('completed_at'),
|
|
1667
|
+
requestPayload: sqliteCore.text('request_payload').notNull(),
|
|
1668
|
+
errorMessage: sqliteCore.text('error_message'),
|
|
1669
|
+
errorDetails: sqliteCore.text('error_details'),
|
|
1670
|
+
persistedSnapshot: sqliteCore.text('persisted_snapshot').notNull(),
|
|
1671
|
+
createdAt: sqliteCore.int('created_at'),
|
|
1672
|
+
updatedAt: sqliteCore.int('updated_at'),
|
|
1673
|
+
});
|
|
1674
|
+
|
|
1412
1675
|
/**
|
|
1413
1676
|
* Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
|
|
1414
1677
|
* Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
|
|
@@ -1430,6 +1693,7 @@ var schema$1 = /*#__PURE__*/Object.freeze({
|
|
|
1430
1693
|
appState: appState,
|
|
1431
1694
|
arweaveL1FinalizeJobs: arweaveL1FinalizeJobs,
|
|
1432
1695
|
config: config,
|
|
1696
|
+
easSyncProcesses: easSyncProcesses,
|
|
1433
1697
|
htmlEmbeddedImageCoPublish: htmlEmbeddedImageCoPublish,
|
|
1434
1698
|
metadata: metadata$1,
|
|
1435
1699
|
modelRelations: modelRelations,
|
|
@@ -1922,6 +2186,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1922
2186
|
capitalizeFirstLetter: capitalizeFirstLetter,
|
|
1923
2187
|
classifyMediaRef: classifyMediaRef,
|
|
1924
2188
|
convertTxIdToImage: convertTxIdToImage,
|
|
2189
|
+
ensureReadGatewaySelected: ensureReadGatewaySelected,
|
|
1925
2190
|
generateId: generateId,
|
|
1926
2191
|
getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
|
|
1927
2192
|
getArweaveUploadStatus: getArweaveUploadStatus,
|
|
@@ -1941,6 +2206,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1941
2206
|
getUploadExecutor: getUploadExecutor,
|
|
1942
2207
|
getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
|
|
1943
2208
|
identifyString: identifyString,
|
|
2209
|
+
invalidateReadGatewayCache: invalidateReadGatewayCache,
|
|
1944
2210
|
isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
|
|
1945
2211
|
isBinary: isBinary,
|
|
1946
2212
|
isPlaceholderUid: isPlaceholderUid,
|
|
@@ -1953,11 +2219,15 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1953
2219
|
normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
|
|
1954
2220
|
parseEasRelationPropertyName: parseEasRelationPropertyName,
|
|
1955
2221
|
pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
|
|
2222
|
+
probeGateway: probeGateway,
|
|
1956
2223
|
queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
|
|
2224
|
+
queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
|
|
2225
|
+
resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
|
|
1957
2226
|
resolveMediaRef: resolveMediaRef,
|
|
1958
2227
|
resolveMetadataRecord: resolveMetadataRecord,
|
|
1959
2228
|
resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
|
|
1960
2229
|
resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
|
|
2230
|
+
selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
|
|
1961
2231
|
setAdditionalSyncAddresses: setAdditionalSyncAddresses,
|
|
1962
2232
|
setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
|
|
1963
2233
|
setRevokeExecutor: setRevokeExecutor,
|
|
@@ -1980,7 +2250,7 @@ const createPropertyInstances = async (propertyFileIds) => {
|
|
|
1980
2250
|
return;
|
|
1981
2251
|
}
|
|
1982
2252
|
try {
|
|
1983
|
-
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-
|
|
2253
|
+
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); });
|
|
1984
2254
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
1985
2255
|
if (!ModelProperty) {
|
|
1986
2256
|
logger$y('createPropertyInstances: ModelProperty not available from dynamic import');
|
|
@@ -2164,7 +2434,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
|
|
|
2164
2434
|
// Step 2: Fallback to Schema context (only if database doesn't have the model)
|
|
2165
2435
|
// This handles the case where model exists in schema file but not yet in database
|
|
2166
2436
|
try {
|
|
2167
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2437
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
|
|
2168
2438
|
const { Schema } = schemaMod;
|
|
2169
2439
|
const schema = Schema.create(schemaName, { waitForReady: false });
|
|
2170
2440
|
const schemaSnapshot = schema.getService().getSnapshot();
|
|
@@ -2408,7 +2678,7 @@ const loadOrCreateModel = xstate.fromCallback(({ sendBack, input: { context } })
|
|
|
2408
2678
|
}
|
|
2409
2679
|
// Mark schema as draft when a new model is created so saveNewVersion() can persist it
|
|
2410
2680
|
try {
|
|
2411
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2681
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
|
|
2412
2682
|
const { Schema } = schemaMod;
|
|
2413
2683
|
const schema = Schema.create(schemaName, { waitForReady: false });
|
|
2414
2684
|
schema.getService().send({ type: 'markAsDraft', propertyKey: 'schema:models' });
|
|
@@ -2452,10 +2722,10 @@ const validateModel = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
2452
2722
|
const _validateModel = async () => {
|
|
2453
2723
|
try {
|
|
2454
2724
|
// Use dynamic imports to break circular dependencies
|
|
2455
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
2725
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
|
|
2456
2726
|
const { SchemaValidationService } = validationServiceMod;
|
|
2457
2727
|
const validationService = new SchemaValidationService();
|
|
2458
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2728
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
|
|
2459
2729
|
const { Schema } = schemaMod;
|
|
2460
2730
|
// Validate model structure
|
|
2461
2731
|
const structureResult = validationService.validateModelStructure(context);
|
|
@@ -2565,7 +2835,7 @@ const createModelProperties = xstate.fromCallback(({ sendBack, input }) => {
|
|
|
2565
2835
|
return;
|
|
2566
2836
|
}
|
|
2567
2837
|
logger$w(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
|
|
2568
|
-
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-
|
|
2838
|
+
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); });
|
|
2569
2839
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
2570
2840
|
if (!ModelProperty) {
|
|
2571
2841
|
logger$w('ModelProperty not available from dynamic import');
|
|
@@ -2669,7 +2939,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2669
2939
|
const structureMsg = `[validateEntity] Validating model structure`;
|
|
2670
2940
|
logger$v(structureMsg);
|
|
2671
2941
|
// Use existing Model validation
|
|
2672
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
2942
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
|
|
2673
2943
|
const { SchemaValidationService } = validationServiceMod;
|
|
2674
2944
|
const validationService = new SchemaValidationService();
|
|
2675
2945
|
// Validate model structure
|
|
@@ -2687,7 +2957,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2687
2957
|
if (entityInput.entityData.schemaName) {
|
|
2688
2958
|
try {
|
|
2689
2959
|
logger$v(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
|
|
2690
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
2960
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
|
|
2691
2961
|
const { Schema } = schemaMod;
|
|
2692
2962
|
const schema = Schema.create(entityInput.entityData.schemaName, {
|
|
2693
2963
|
waitForReady: false,
|
|
@@ -2723,7 +2993,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2723
2993
|
}
|
|
2724
2994
|
else if (entityInput.entityType === 'modelProperty') {
|
|
2725
2995
|
// Use existing ModelProperty validation
|
|
2726
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
2996
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
|
|
2727
2997
|
const { SchemaValidationService } = validationServiceMod;
|
|
2728
2998
|
const validationService = new SchemaValidationService();
|
|
2729
2999
|
// Validate property structure
|
|
@@ -2738,7 +3008,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2738
3008
|
// If schema name and model name provided, validate against schema
|
|
2739
3009
|
if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
|
|
2740
3010
|
try {
|
|
2741
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-
|
|
3011
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
|
|
2742
3012
|
const { Schema } = schemaMod;
|
|
2743
3013
|
const schema = Schema.create(entityInput.entityData._schemaName, {
|
|
2744
3014
|
waitForReady: false,
|
|
@@ -2767,7 +3037,7 @@ const validateEntity = xstate.fromPromise(async ({ input }) => {
|
|
|
2767
3037
|
}
|
|
2768
3038
|
else if (entityInput.entityType === 'schema') {
|
|
2769
3039
|
// Schema validation - use existing validation
|
|
2770
|
-
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
3040
|
+
const validationServiceMod = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
|
|
2771
3041
|
const { SchemaValidationService } = validationServiceMod;
|
|
2772
3042
|
const validationService = new SchemaValidationService();
|
|
2773
3043
|
const schemaResult = validationService.validateSchema(entityInput.entityData);
|
|
@@ -4719,7 +4989,7 @@ const writeToDatabase = xstate.fromCallback(({ sendBack, input }) => {
|
|
|
4719
4989
|
// initial write completes is not overwritten by the stale requestWrite payload.
|
|
4720
4990
|
let dataToWrite = input.entityData;
|
|
4721
4991
|
try {
|
|
4722
|
-
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-
|
|
4992
|
+
const mod = await Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); });
|
|
4723
4993
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
4724
4994
|
if (ModelProperty && typeof ModelProperty.getById === 'function') {
|
|
4725
4995
|
const instance = ModelProperty.getById(input.entityId);
|
|
@@ -5099,7 +5369,7 @@ const modelMachine = xstate.setup({
|
|
|
5099
5369
|
// Create ModelProperty instances for any new property IDs
|
|
5100
5370
|
if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
|
|
5101
5371
|
// Import and create instances asynchronously (fire-and-forget)
|
|
5102
|
-
Promise.resolve().then(function () { return require('./ModelProperty-
|
|
5372
|
+
Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); }).then(({ ModelProperty }) => {
|
|
5103
5373
|
const createPromises = newPropertyIds.map(async (propertyFileId) => {
|
|
5104
5374
|
try {
|
|
5105
5375
|
const property = await ModelProperty.createById(propertyFileId);
|
|
@@ -5402,6 +5672,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
|
|
|
5402
5672
|
var MachineIds;
|
|
5403
5673
|
(function (MachineIds) {
|
|
5404
5674
|
MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
|
|
5675
|
+
MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
|
|
5405
5676
|
MachineIds["GLOBAL"] = "@seedSdk/global";
|
|
5406
5677
|
MachineIds["INTERNAL"] = "@seedSdk/internal";
|
|
5407
5678
|
MachineIds["EAS"] = "@seedSdk/eas";
|
|
@@ -5474,7 +5745,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
|
|
|
5474
5745
|
* This constant is kept for backward compatibility but will be removed in a future version.
|
|
5475
5746
|
* Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
|
|
5476
5747
|
*/
|
|
5477
|
-
ENV.NEXT_PUBLIC_ARWEAVE_HOST || '
|
|
5748
|
+
ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
|
|
5478
5749
|
|
|
5479
5750
|
debug('seedSdk:item:service:actors:waitForDb');
|
|
5480
5751
|
const waitForDb$1 = xstate.fromCallback(({ sendBack }) => {
|
|
@@ -6357,7 +6628,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
|
|
|
6357
6628
|
rowNum: drizzleOrm.sql.raw(`
|
|
6358
6629
|
ROW_NUMBER() OVER (
|
|
6359
6630
|
PARTITION BY property_name
|
|
6360
|
-
ORDER BY COALESCE(attestation_created_at, created_at) DESC
|
|
6631
|
+
ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
|
|
6361
6632
|
)
|
|
6362
6633
|
`).as('rowNum')
|
|
6363
6634
|
})
|
|
@@ -6370,6 +6641,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
|
|
|
6370
6641
|
getMetadataLatest: getMetadataLatest
|
|
6371
6642
|
});
|
|
6372
6643
|
|
|
6644
|
+
/**
|
|
6645
|
+
* Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
|
|
6646
|
+
* `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
|
|
6647
|
+
*/
|
|
6648
|
+
function metadataLatestFirstSortKey(row) {
|
|
6649
|
+
return {
|
|
6650
|
+
t: row.attestationCreatedAt ?? row.createdAt ?? 0,
|
|
6651
|
+
localId: String(row.localId ?? ''),
|
|
6652
|
+
};
|
|
6653
|
+
}
|
|
6654
|
+
/** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
|
|
6655
|
+
function compareMetadataRowsLatestFirst(a, b) {
|
|
6656
|
+
const ka = metadataLatestFirstSortKey(a);
|
|
6657
|
+
const kb = metadataLatestFirstSortKey(b);
|
|
6658
|
+
if (kb.t !== ka.t)
|
|
6659
|
+
return kb.t - ka.t;
|
|
6660
|
+
return kb.localId.localeCompare(ka.localId);
|
|
6661
|
+
}
|
|
6662
|
+
|
|
6373
6663
|
const logger$q = debug('seedSdk:item:actors:loadOrCreateItem');
|
|
6374
6664
|
/**
|
|
6375
6665
|
* Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
|
|
@@ -6411,9 +6701,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
|
|
|
6411
6701
|
return b;
|
|
6412
6702
|
if (sa !== sb)
|
|
6413
6703
|
return sa > sb ? a : b;
|
|
6414
|
-
const
|
|
6415
|
-
|
|
6416
|
-
return ta >= tb ? a : b;
|
|
6704
|
+
const cmp = compareMetadataRowsLatestFirst(a, b);
|
|
6705
|
+
return cmp < 0 ? a : b;
|
|
6417
6706
|
}
|
|
6418
6707
|
function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
|
|
6419
6708
|
const byKey = new Map();
|
|
@@ -6461,7 +6750,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6461
6750
|
const schemaNameToTry = model$1?.schemaName;
|
|
6462
6751
|
if (schemaNameToTry) {
|
|
6463
6752
|
try {
|
|
6464
|
-
const { Schema } = await Promise.resolve().then(function () { return require('./Schema-
|
|
6753
|
+
const { Schema } = await Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); });
|
|
6465
6754
|
const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
|
|
6466
6755
|
const schemaContext = schemaInstance.getService().getSnapshot().context;
|
|
6467
6756
|
if (schemaContext.models?.[modelName]?.properties) {
|
|
@@ -6510,7 +6799,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6510
6799
|
}
|
|
6511
6800
|
}
|
|
6512
6801
|
if (Object.keys(propertySchemas).length === 0) {
|
|
6513
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
6802
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
6514
6803
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
6515
6804
|
const KNOWN_MODEL_FALLBACKS = {
|
|
6516
6805
|
Post: {
|
|
@@ -6557,7 +6846,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6557
6846
|
// Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
|
|
6558
6847
|
let propSchema = propertySchemas[propertyName];
|
|
6559
6848
|
if (!propSchema && isRefTypeFromMeta) {
|
|
6560
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
6849
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
6561
6850
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
6562
6851
|
propSchema = {
|
|
6563
6852
|
dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
|
|
@@ -6814,9 +7103,9 @@ const runPublish = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
|
6814
7103
|
sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
|
|
6815
7104
|
return;
|
|
6816
7105
|
}
|
|
6817
|
-
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-
|
|
7106
|
+
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-BljRx4o4.js'); });
|
|
6818
7107
|
const { getPublishUploads } = getPublishUploadsMod;
|
|
6819
|
-
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-
|
|
7108
|
+
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-ddl-1x6R.js'); });
|
|
6820
7109
|
const { getPublishPayload } = getPublishPayloadMod;
|
|
6821
7110
|
const uploads = await getPublishUploads(item);
|
|
6822
7111
|
let uploadedTransactions = [];
|
|
@@ -7162,6 +7451,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
|
|
|
7162
7451
|
return rows[0];
|
|
7163
7452
|
};
|
|
7164
7453
|
|
|
7454
|
+
var getSeedData$1 = /*#__PURE__*/Object.freeze({
|
|
7455
|
+
__proto__: null,
|
|
7456
|
+
getSeedData: getSeedData
|
|
7457
|
+
});
|
|
7458
|
+
|
|
7165
7459
|
/**
|
|
7166
7460
|
* Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
|
|
7167
7461
|
* Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
|
|
@@ -7651,7 +7945,7 @@ const resolveRelatedValue = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
7651
7945
|
const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
|
|
7652
7946
|
const _resolveRelatedValue = async () => {
|
|
7653
7947
|
// Use dynamic import to break circular dependency
|
|
7654
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
7948
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
7655
7949
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
7656
7950
|
if (!propertyValue || !isRelation || populatedFromDb) {
|
|
7657
7951
|
return;
|
|
@@ -8014,174 +8308,814 @@ function parseListPropertyValueFromStorage(raw) {
|
|
|
8014
8308
|
return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
|
|
8015
8309
|
}
|
|
8016
8310
|
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
const
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8311
|
+
const eventEmitter = new EventEmitter();
|
|
8312
|
+
|
|
8313
|
+
const GET_FILES_METADATA = graphql(/* GraphQL */ `
|
|
8314
|
+
query GetFilesMetadata($where: AttestationWhereInput!) {
|
|
8315
|
+
filesMetadata: attestations(
|
|
8316
|
+
where: $where
|
|
8317
|
+
orderBy: [{ timeCreated: desc }]
|
|
8318
|
+
) {
|
|
8319
|
+
...attestationFields
|
|
8024
8320
|
}
|
|
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
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
}
|
|
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
|
-
|
|
8321
|
+
}
|
|
8322
|
+
`);
|
|
8323
|
+
|
|
8324
|
+
const getMetadata = async (props) => {
|
|
8325
|
+
const appDb = BaseDb.getAppDb();
|
|
8326
|
+
let storageTransactionId;
|
|
8327
|
+
if (props) {
|
|
8328
|
+
storageTransactionId = props.storageTransactionId;
|
|
8329
|
+
}
|
|
8330
|
+
const whereClauses = [];
|
|
8331
|
+
if (storageTransactionId) {
|
|
8332
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'));
|
|
8333
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.propertyValue, storageTransactionId));
|
|
8334
|
+
}
|
|
8335
|
+
const metadataRows = await appDb
|
|
8336
|
+
.select()
|
|
8337
|
+
.from(metadata$1)
|
|
8338
|
+
.where(drizzleOrm.and(...whereClauses));
|
|
8339
|
+
if (!metadataRows || metadataRows.length === 0) {
|
|
8340
|
+
return;
|
|
8341
|
+
}
|
|
8342
|
+
return metadataRows[0];
|
|
8343
|
+
};
|
|
8344
|
+
|
|
8345
|
+
const saveMetadata = async (metadataRecord, metadataValues) => {
|
|
8346
|
+
if (!metadataRecord.localId) {
|
|
8347
|
+
return;
|
|
8348
|
+
}
|
|
8349
|
+
const appDb = BaseDb.getAppDb();
|
|
8350
|
+
await appDb
|
|
8351
|
+
.update(metadata$1)
|
|
8352
|
+
.set({
|
|
8353
|
+
...metadataValues,
|
|
8354
|
+
updatedAt: Date.now(),
|
|
8355
|
+
})
|
|
8356
|
+
.where(drizzleOrm.eq(metadata$1.localId, metadataRecord.localId));
|
|
8357
|
+
};
|
|
8358
|
+
|
|
8359
|
+
const isNode = () => {
|
|
8360
|
+
return (typeof process !== 'undefined' &&
|
|
8361
|
+
process.versions != null &&
|
|
8362
|
+
process.versions.node != null);
|
|
8363
|
+
};
|
|
8364
|
+
const isBrowser = () => {
|
|
8365
|
+
return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
|
|
8366
|
+
};
|
|
8367
|
+
const isElectron = () => {
|
|
8368
|
+
return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
|
|
8369
|
+
};
|
|
8370
|
+
/**
|
|
8371
|
+
* Detects if code is running in an Electron renderer process.
|
|
8372
|
+
*
|
|
8373
|
+
* Uses multiple detection methods for robustness:
|
|
8374
|
+
* 1. Checks process.type === 'renderer' (most reliable)
|
|
8375
|
+
* 2. Falls back to checking if Electron is present and window/document exist
|
|
8376
|
+
*
|
|
8377
|
+
* @returns true if running in Electron renderer process, false otherwise
|
|
8378
|
+
*/
|
|
8379
|
+
const isElectronRenderer = () => {
|
|
8380
|
+
// Method 1: Check process.type (most reliable - official Electron API)
|
|
8381
|
+
if (typeof process !== 'undefined' &&
|
|
8382
|
+
process.type === 'renderer') {
|
|
8383
|
+
return true;
|
|
8384
|
+
}
|
|
8385
|
+
// Method 2: Fallback - Electron + browser-like environment
|
|
8386
|
+
// Renderer processes have window/document, main process doesn't (in modern Electron)
|
|
8387
|
+
if (isElectron() &&
|
|
8388
|
+
typeof window !== 'undefined' &&
|
|
8389
|
+
typeof document !== 'undefined') {
|
|
8390
|
+
return true;
|
|
8391
|
+
}
|
|
8392
|
+
return false;
|
|
8393
|
+
};
|
|
8394
|
+
/**
|
|
8395
|
+
* True where OPFS-backed Arweave file downloads should run: normal browsers and
|
|
8396
|
+
* Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
|
|
8397
|
+
*/
|
|
8398
|
+
const supportsOpfsFileDownloads = () => {
|
|
8399
|
+
return isBrowser() || isElectronRenderer();
|
|
8400
|
+
};
|
|
8401
|
+
|
|
8402
|
+
const logger$l = debug('seedSdk:files:download');
|
|
8403
|
+
const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
|
|
8404
|
+
/** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
|
|
8405
|
+
const GET_FILES_METADATA_STALE_MS = 120000;
|
|
8406
|
+
let bulkDownloadInFlight = null;
|
|
8407
|
+
const lazyDownloadInFlightByTransactionId = new Map();
|
|
8408
|
+
// syncDbFiles helper - internal service removed, functionality moved here
|
|
8409
|
+
const syncDbFiles = async (endpoints) => {
|
|
8410
|
+
// TODO: Implement syncDbFiles functionality if needed
|
|
8411
|
+
// This was previously in @/services/internal/helpers
|
|
8412
|
+
logger$l('[download] syncDbFiles called but not yet implemented');
|
|
8413
|
+
return Promise.resolve();
|
|
8414
|
+
};
|
|
8415
|
+
const getAppDbReady = async () => {
|
|
8416
|
+
if (!BaseDb.isAppDbReady()) {
|
|
8417
|
+
// Wait for ClientManager to be ready (DB_INIT state or later)
|
|
8418
|
+
const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
|
|
8419
|
+
const { getClient } = clientManagerMod;
|
|
8420
|
+
const clientManager = getClient();
|
|
8421
|
+
const clientService = clientManager.getService();
|
|
8422
|
+
await xstate.waitFor(clientService, (snapshot) => {
|
|
8423
|
+
const state = snapshot.value;
|
|
8424
|
+
return state === 'dbInit' ||
|
|
8425
|
+
state === 'saveConfig' ||
|
|
8426
|
+
state === 'processSchemaFiles' ||
|
|
8427
|
+
state === 'addModelsToStore' ||
|
|
8428
|
+
state === 'addModelsToDb' ||
|
|
8429
|
+
state === 'idle';
|
|
8430
|
+
}, { timeout: 30000 });
|
|
8431
|
+
}
|
|
8432
|
+
return BaseDb.getAppDb();
|
|
8433
|
+
};
|
|
8434
|
+
const getExcludedTransactions = async () => {
|
|
8435
|
+
const appDb = await getAppDbReady();
|
|
8436
|
+
if (!appDb) {
|
|
8437
|
+
return new Set();
|
|
8438
|
+
}
|
|
8439
|
+
const excludedTransactionsQuery = await appDb
|
|
8440
|
+
.select()
|
|
8441
|
+
.from(appState)
|
|
8442
|
+
.where(drizzleOrm.eq(appState.key, 'excludedTransactions'));
|
|
8443
|
+
const excludedTransactions = new Set();
|
|
8444
|
+
if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
|
|
8445
|
+
const valueString = excludedTransactionsQuery[0].value;
|
|
8446
|
+
if (valueString) {
|
|
8447
|
+
const excludedTransactionsArray = JSON.parse(valueString);
|
|
8448
|
+
for (const txId of excludedTransactionsArray) {
|
|
8449
|
+
excludedTransactions.add(txId);
|
|
8450
|
+
}
|
|
8451
|
+
}
|
|
8452
|
+
}
|
|
8453
|
+
return excludedTransactions;
|
|
8454
|
+
};
|
|
8455
|
+
/** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
|
|
8456
|
+
const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
|
|
8457
|
+
const normalizeArweaveTxId = (raw) => {
|
|
8458
|
+
if (raw == null || raw === '')
|
|
8459
|
+
return undefined;
|
|
8460
|
+
const t = String(raw).trim();
|
|
8461
|
+
if (ARWEAVE_TX_ID_RE.test(t))
|
|
8462
|
+
return t;
|
|
8463
|
+
const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
|
|
8464
|
+
if (m)
|
|
8465
|
+
return m[1];
|
|
8466
|
+
// Values may be full gateway URLs or paths; scan for the embedded tx id.
|
|
8467
|
+
const embedded = t.match(/[a-z0-9_-]{43}/gi);
|
|
8468
|
+
if (embedded) {
|
|
8469
|
+
for (const candidate of embedded) {
|
|
8470
|
+
if (ARWEAVE_TX_ID_RE.test(candidate))
|
|
8471
|
+
return candidate;
|
|
8472
|
+
}
|
|
8473
|
+
}
|
|
8474
|
+
return undefined;
|
|
8475
|
+
};
|
|
8476
|
+
const mergeAddressLists = (a, b) => {
|
|
8477
|
+
const seen = new Set();
|
|
8478
|
+
const out = [];
|
|
8479
|
+
for (const addr of [...(a ?? []), ...(b ?? [])]) {
|
|
8480
|
+
if (!addr || !addr.trim())
|
|
8481
|
+
continue;
|
|
8482
|
+
const k = addr.toLowerCase();
|
|
8483
|
+
if (seen.has(k))
|
|
8484
|
+
continue;
|
|
8485
|
+
seen.add(k);
|
|
8486
|
+
out.push(addr);
|
|
8487
|
+
}
|
|
8488
|
+
return out;
|
|
8489
|
+
};
|
|
8490
|
+
const collectTransactionIdsFromLocalMetadata = async () => {
|
|
8491
|
+
const appDb = await getAppDbReady();
|
|
8492
|
+
if (!appDb) {
|
|
8493
|
+
return [];
|
|
8494
|
+
}
|
|
8495
|
+
const nameOr = drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'storage_transaction_id'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'));
|
|
8496
|
+
const propRows = await appDb
|
|
8497
|
+
.select({ propertyValue: metadata$1.propertyValue })
|
|
8498
|
+
.from(metadata$1)
|
|
8499
|
+
.where(drizzleOrm.and(nameOr, drizzleOrm.isNotNull(metadata$1.propertyValue)));
|
|
8500
|
+
const refRows = await appDb
|
|
8501
|
+
.select({ refResolvedValue: metadata$1.refResolvedValue })
|
|
8502
|
+
.from(metadata$1)
|
|
8503
|
+
.where(drizzleOrm.isNotNull(metadata$1.refResolvedValue));
|
|
8504
|
+
const ids = new Set();
|
|
8505
|
+
for (const row of propRows) {
|
|
8506
|
+
const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
|
|
8507
|
+
if (id)
|
|
8508
|
+
ids.add(id);
|
|
8509
|
+
}
|
|
8510
|
+
for (const row of refRows) {
|
|
8511
|
+
const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
|
|
8512
|
+
if (id)
|
|
8513
|
+
ids.add(id);
|
|
8514
|
+
}
|
|
8515
|
+
return Array.from(ids);
|
|
8516
|
+
};
|
|
8517
|
+
const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
|
|
8518
|
+
const transactionIds = [];
|
|
8519
|
+
for (const fileMetadata of filesMetadata) {
|
|
8520
|
+
// Validate and parse decodedDataJson
|
|
8521
|
+
if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
|
|
8522
|
+
console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
|
|
8523
|
+
continue;
|
|
8524
|
+
}
|
|
8525
|
+
let json;
|
|
8526
|
+
try {
|
|
8527
|
+
json = JSON.parse(fileMetadata.decodedDataJson);
|
|
8528
|
+
}
|
|
8529
|
+
catch (error) {
|
|
8530
|
+
console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
|
|
8531
|
+
continue;
|
|
8532
|
+
}
|
|
8533
|
+
if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
|
|
8534
|
+
console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
|
|
8535
|
+
continue;
|
|
8536
|
+
}
|
|
8537
|
+
const rawTx = json[0].value.value;
|
|
8538
|
+
if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
|
|
8539
|
+
continue;
|
|
8540
|
+
}
|
|
8541
|
+
const transactionId = normalizeArweaveTxId(rawTx.trim());
|
|
8542
|
+
if (!transactionId) {
|
|
8543
|
+
continue;
|
|
8544
|
+
}
|
|
8545
|
+
if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
|
|
8546
|
+
continue;
|
|
8547
|
+
}
|
|
8548
|
+
transactionIds.push(transactionId);
|
|
8549
|
+
}
|
|
8550
|
+
return transactionIds;
|
|
8551
|
+
};
|
|
8552
|
+
const downloadTransactionIds = async (rawTransactionIds, options) => {
|
|
8553
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8554
|
+
return false;
|
|
8555
|
+
}
|
|
8556
|
+
const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
|
|
8557
|
+
if (transactionIds.length === 0) {
|
|
8558
|
+
return false;
|
|
8559
|
+
}
|
|
8560
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
8561
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
8562
|
+
const transactionIdsToDownload = [];
|
|
8563
|
+
await ensureReadGatewaySelected();
|
|
8564
|
+
for (const transactionId of transactionIds) {
|
|
8565
|
+
if (excludedTransactions.has(transactionId)) {
|
|
8566
|
+
continue;
|
|
8567
|
+
}
|
|
8568
|
+
try {
|
|
8569
|
+
// Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
|
|
8570
|
+
// CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
|
|
8571
|
+
let tags = [];
|
|
8572
|
+
try {
|
|
8573
|
+
tags = await queryClient.fetchQuery({
|
|
8574
|
+
queryKey: ['getTransactionTags', transactionId],
|
|
8575
|
+
queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
|
|
8576
|
+
});
|
|
8577
|
+
}
|
|
8578
|
+
catch {
|
|
8579
|
+
tags = [];
|
|
8580
|
+
}
|
|
8581
|
+
if (tags && tags.length > 0) {
|
|
8582
|
+
for (const { name, value } of tags) {
|
|
8583
|
+
if (name !== 'Content-SHA-256')
|
|
8584
|
+
continue;
|
|
8585
|
+
const metadataRecord = await getMetadata({
|
|
8586
|
+
storageTransactionId: transactionId,
|
|
8587
|
+
});
|
|
8588
|
+
if (metadataRecord) {
|
|
8589
|
+
await saveMetadata(metadataRecord, {
|
|
8590
|
+
contentHash: value,
|
|
8591
|
+
});
|
|
8592
|
+
}
|
|
8593
|
+
}
|
|
8594
|
+
}
|
|
8595
|
+
transactionIdsToDownload.push(transactionId);
|
|
8596
|
+
}
|
|
8597
|
+
catch (error) {
|
|
8598
|
+
logger$l(error);
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8601
|
+
if (transactionIdsToDownload.length === 0) {
|
|
8602
|
+
return false;
|
|
8603
|
+
}
|
|
8604
|
+
if (transactionIdsToDownload.length === 1) {
|
|
8605
|
+
await BaseFileManager.downloadFileByTransactionId({
|
|
8606
|
+
transactionId: transactionIdsToDownload[0],
|
|
8607
|
+
arweaveHost: BaseArweaveClient.getHost(),
|
|
8608
|
+
excludedTransactions,
|
|
8609
|
+
});
|
|
8610
|
+
}
|
|
8611
|
+
else {
|
|
8612
|
+
await BaseFileManager.downloadAllFiles({
|
|
8613
|
+
transactionIds: transactionIdsToDownload,
|
|
8614
|
+
arweaveHost: BaseArweaveClient.getHost(),
|
|
8615
|
+
excludedTransactions,
|
|
8616
|
+
});
|
|
8617
|
+
}
|
|
8618
|
+
if (options?.resizeAllImages !== false) {
|
|
8619
|
+
await BaseFileManager.resizeAllImages({
|
|
8620
|
+
width: 480,
|
|
8621
|
+
height: 480,
|
|
8622
|
+
});
|
|
8623
|
+
}
|
|
8624
|
+
return true;
|
|
8625
|
+
};
|
|
8626
|
+
const runBulkDownloadWithDedupe = async (transactionIds) => {
|
|
8627
|
+
if (bulkDownloadInFlight) {
|
|
8628
|
+
return bulkDownloadInFlight;
|
|
8629
|
+
}
|
|
8630
|
+
bulkDownloadInFlight = (async () => {
|
|
8631
|
+
try {
|
|
8632
|
+
await downloadTransactionIds(transactionIds, { resizeAllImages: true });
|
|
8633
|
+
}
|
|
8634
|
+
finally {
|
|
8635
|
+
bulkDownloadInFlight = null;
|
|
8636
|
+
}
|
|
8637
|
+
})();
|
|
8638
|
+
return bulkDownloadInFlight;
|
|
8639
|
+
};
|
|
8640
|
+
const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
|
|
8641
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8642
|
+
return;
|
|
8643
|
+
}
|
|
8644
|
+
await syncDbFiles();
|
|
8645
|
+
eventEmitter.emit('fs.downloadAll.success', { eventId });
|
|
8646
|
+
eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
|
|
8647
|
+
};
|
|
8648
|
+
const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
|
|
8649
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8650
|
+
return;
|
|
8651
|
+
}
|
|
8652
|
+
const addressesHint = Array.isArray(addressesHintOrPayload)
|
|
8653
|
+
? addressesHintOrPayload
|
|
8654
|
+
: undefined;
|
|
8655
|
+
let fromDb = [];
|
|
8656
|
+
if (BaseDb.isAppDbReady()) {
|
|
8657
|
+
fromDb = await getAllAddressesFromDb();
|
|
8658
|
+
}
|
|
8659
|
+
if (!BaseDb.isAppDbReady()) {
|
|
8660
|
+
await getAppDbReady();
|
|
8661
|
+
fromDb = await getAllAddressesFromDb();
|
|
8662
|
+
}
|
|
8663
|
+
const addresses = mergeAddressLists(addressesHint, fromDb);
|
|
8664
|
+
if (!addresses || addresses.length === 0) {
|
|
8665
|
+
return;
|
|
8666
|
+
}
|
|
8667
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
8668
|
+
const easClient = BaseEasClient.getEasClient();
|
|
8669
|
+
const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
|
|
8670
|
+
const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
|
|
8671
|
+
where: {
|
|
8672
|
+
attester: {
|
|
8673
|
+
in: addresses,
|
|
8674
|
+
},
|
|
8675
|
+
schema: {
|
|
8676
|
+
is: {
|
|
8677
|
+
id: {
|
|
8678
|
+
equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
|
|
8679
|
+
},
|
|
8680
|
+
},
|
|
8681
|
+
},
|
|
8682
|
+
},
|
|
8683
|
+
});
|
|
8684
|
+
let { filesMetadata } = await queryClient.fetchQuery({
|
|
8685
|
+
queryKey: filesMetadataQueryKey,
|
|
8686
|
+
queryFn: fetchFilesMetadata,
|
|
8687
|
+
staleTime: GET_FILES_METADATA_STALE_MS,
|
|
8688
|
+
});
|
|
8689
|
+
if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
|
|
8690
|
+
await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
|
|
8691
|
+
({ filesMetadata } = await queryClient.fetchQuery({
|
|
8692
|
+
queryKey: filesMetadataQueryKey,
|
|
8693
|
+
queryFn: fetchFilesMetadata,
|
|
8694
|
+
staleTime: GET_FILES_METADATA_STALE_MS,
|
|
8695
|
+
}));
|
|
8696
|
+
}
|
|
8697
|
+
const filesRoot = BaseFileManager.getWorkingDir();
|
|
8698
|
+
await BaseFileManager.createDirIfNotExists(filesRoot);
|
|
8699
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
|
|
8700
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
|
|
8701
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
|
|
8702
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
8703
|
+
const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
|
|
8704
|
+
const fromLocal = await collectTransactionIdsFromLocalMetadata();
|
|
8705
|
+
const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
|
|
8706
|
+
await runBulkDownloadWithDedupe(transactionIds);
|
|
8707
|
+
};
|
|
8708
|
+
const downloadTransactionIdWithDedupe = async (transactionId) => {
|
|
8709
|
+
if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
|
|
8710
|
+
return false;
|
|
8711
|
+
}
|
|
8712
|
+
const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
|
|
8713
|
+
const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
|
|
8714
|
+
if (existing) {
|
|
8715
|
+
return existing;
|
|
8716
|
+
}
|
|
8717
|
+
const inFlight = (async () => {
|
|
8718
|
+
try {
|
|
8719
|
+
const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
|
|
8720
|
+
return ok;
|
|
8721
|
+
}
|
|
8722
|
+
finally {
|
|
8723
|
+
lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
|
|
8724
|
+
}
|
|
8725
|
+
})();
|
|
8726
|
+
lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
|
|
8727
|
+
return inFlight;
|
|
8728
|
+
};
|
|
8729
|
+
const scheduleBulkFilesDownloadFromEasSyncThrottled = lodashEs.throttle((addressesHint) => {
|
|
8730
|
+
void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
|
|
8731
|
+
logger$l('[scheduleBulkFilesDownloadFromEasSync] failed', error);
|
|
8732
|
+
});
|
|
8733
|
+
}, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
|
|
8734
|
+
const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
|
|
8735
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8736
|
+
return;
|
|
8737
|
+
}
|
|
8738
|
+
scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
|
|
8739
|
+
};
|
|
8740
|
+
|
|
8741
|
+
var download = /*#__PURE__*/Object.freeze({
|
|
8742
|
+
__proto__: null,
|
|
8743
|
+
downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
|
|
8744
|
+
downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
|
|
8745
|
+
downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
|
|
8746
|
+
scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
|
|
8747
|
+
});
|
|
8748
|
+
|
|
8749
|
+
/** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
|
|
8750
|
+
const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
8751
|
+
/** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
|
|
8752
|
+
const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
|
|
8753
|
+
function extractArweaveTransactionId(raw) {
|
|
8754
|
+
const t = raw.trim();
|
|
8755
|
+
const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
|
|
8756
|
+
if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
|
|
8757
|
+
return embedded[0];
|
|
8758
|
+
}
|
|
8759
|
+
return t;
|
|
8760
|
+
}
|
|
8761
|
+
/**
|
|
8762
|
+
* GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
|
|
8763
|
+
* arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
|
|
8764
|
+
*/
|
|
8765
|
+
async function fetchHtmlViaRawAcrossGateways(txId) {
|
|
8766
|
+
const id = extractArweaveTransactionId(txId);
|
|
8767
|
+
if (!id || SEED_UID_HEX_RE.test(id))
|
|
8768
|
+
return undefined;
|
|
8769
|
+
try {
|
|
8770
|
+
const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
|
|
8771
|
+
await ensureReadGatewaySelected().catch(() => { });
|
|
8772
|
+
}
|
|
8773
|
+
catch {
|
|
8774
|
+
/* optional */
|
|
8775
|
+
}
|
|
8776
|
+
const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
|
|
8777
|
+
const protocol = BaseArweaveClient.getProtocol();
|
|
8778
|
+
const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
|
|
8779
|
+
for (const host of hosts) {
|
|
8780
|
+
const h = host.trim().replace(/\/$/, '');
|
|
8781
|
+
if (!h)
|
|
8782
|
+
continue;
|
|
8783
|
+
const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
|
|
8784
|
+
try {
|
|
8785
|
+
const res = await fetch(url, { method: 'GET', credentials: 'omit' });
|
|
8786
|
+
if (!res.ok)
|
|
8787
|
+
continue;
|
|
8788
|
+
const text = await res.text();
|
|
8789
|
+
if (typeof text === 'string' && text.length > 0) {
|
|
8790
|
+
return text;
|
|
8791
|
+
}
|
|
8792
|
+
}
|
|
8793
|
+
catch {
|
|
8794
|
+
/* next gateway */
|
|
8795
|
+
}
|
|
8796
|
+
}
|
|
8797
|
+
return undefined;
|
|
8798
|
+
}
|
|
8799
|
+
/**
|
|
8800
|
+
* Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
|
|
8801
|
+
* `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
|
|
8802
|
+
*/
|
|
8803
|
+
async function resolveHtmlStorageSeedLocalId(propertyValue) {
|
|
8804
|
+
const pv = String(propertyValue ?? '').trim();
|
|
8805
|
+
if (!pv)
|
|
8806
|
+
return undefined;
|
|
8807
|
+
if (SEED_UID_HEX_RE.test(pv)) {
|
|
8808
|
+
const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
|
|
8809
|
+
return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
|
|
8810
|
+
}
|
|
8811
|
+
return pv;
|
|
8812
|
+
}
|
|
8813
|
+
/**
|
|
8814
|
+
* When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
|
|
8815
|
+
* Html storage seed's published Arweave transaction id on that child seed.
|
|
8816
|
+
*/
|
|
8817
|
+
async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
|
|
8818
|
+
const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
|
|
8819
|
+
const pickTx = async (name) => {
|
|
8820
|
+
const row = await getPropertyData({ propertyName: name, seedLocalId });
|
|
8821
|
+
const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
|
|
8822
|
+
return v || undefined;
|
|
8823
|
+
};
|
|
8824
|
+
const txId = (await pickTx('storageTransactionId')) ??
|
|
8825
|
+
(await pickTx('transactionId')) ??
|
|
8826
|
+
(await pickTx('storage_transaction_id'));
|
|
8827
|
+
if (!txId || SEED_UID_HEX_RE.test(txId)) {
|
|
8828
|
+
return { txIdLen: 0, gatewayStringLen: 0 };
|
|
8829
|
+
}
|
|
8830
|
+
const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
|
|
8831
|
+
if (rawHtml && rawHtml.length > 0) {
|
|
8832
|
+
return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
|
|
8833
|
+
}
|
|
8834
|
+
try {
|
|
8835
|
+
const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
|
|
8836
|
+
const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
|
|
8837
|
+
string: true,
|
|
8838
|
+
});
|
|
8839
|
+
if (typeof data === 'string' && data.length > 0) {
|
|
8840
|
+
return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
|
|
8841
|
+
}
|
|
8842
|
+
}
|
|
8843
|
+
catch {
|
|
8844
|
+
/* offline / bad tx id */
|
|
8845
|
+
}
|
|
8846
|
+
try {
|
|
8847
|
+
const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
|
|
8848
|
+
await downloadTransactionIdWithDedupe(txId);
|
|
8849
|
+
const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
|
|
8850
|
+
if (await BaseFileManager.pathExists(retryFp)) {
|
|
8851
|
+
const s = await BaseFileManager.readFileAsString(retryFp);
|
|
8852
|
+
return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8853
|
+
}
|
|
8854
|
+
const dirPath = BaseFileManager.getFilesPath('html');
|
|
8855
|
+
if (await BaseFileManager.pathExists(dirPath)) {
|
|
8856
|
+
const fs = await BaseFileManager.getFs();
|
|
8857
|
+
const pathMod = BaseFileManager.getPathModule();
|
|
8858
|
+
const files = await fs.promises.readdir(dirPath);
|
|
8859
|
+
const needle = txId.replace(/\.[^/.]+$/, '');
|
|
8860
|
+
const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
|
|
8861
|
+
if (match) {
|
|
8862
|
+
const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
|
|
8863
|
+
return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8864
|
+
}
|
|
8865
|
+
}
|
|
8866
|
+
}
|
|
8867
|
+
catch {
|
|
8868
|
+
/* OPFS unsupported or download failed */
|
|
8869
|
+
}
|
|
8870
|
+
return { txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8871
|
+
}
|
|
8872
|
+
/** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
|
|
8873
|
+
async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
|
|
8874
|
+
const pv = String(propertyValue ?? '').trim();
|
|
8875
|
+
if (!pv)
|
|
8876
|
+
return undefined;
|
|
8877
|
+
const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
|
|
8878
|
+
const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
|
|
8879
|
+
let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
|
|
8880
|
+
// OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
|
|
8881
|
+
if (!fileExists && fp) {
|
|
8882
|
+
await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
|
|
8883
|
+
fileExists = await BaseFileManager.pathExists(fp);
|
|
8884
|
+
}
|
|
8885
|
+
let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
|
|
8886
|
+
if (!body && localId) {
|
|
8887
|
+
const ar = await readHtmlBodyFromChildStorageArweave(localId);
|
|
8888
|
+
body = ar.body;
|
|
8889
|
+
}
|
|
8890
|
+
return body;
|
|
8891
|
+
}
|
|
8892
|
+
|
|
8893
|
+
// Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
|
|
8894
|
+
// import { ModelPropertyDataTypes } from '@/schema'
|
|
8895
|
+
const logger$k = debug('seedSdk:property:actors:hydrateFromDb');
|
|
8896
|
+
const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
8897
|
+
const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
|
|
8898
|
+
if (!propertyNameRaw) {
|
|
8899
|
+
throw new Error('propertyName is required');
|
|
8900
|
+
}
|
|
8901
|
+
let propertyName = propertyNameRaw;
|
|
8902
|
+
// Note: isRelation, isImage, isFile checks moved inside async function
|
|
8903
|
+
// to use dynamically imported ModelPropertyDataTypes
|
|
8904
|
+
const _hydrateFromDb = async () => {
|
|
8905
|
+
// Use dynamic import to break circular dependency
|
|
8906
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
8907
|
+
const { ModelPropertyDataTypes } = schemaMod;
|
|
8908
|
+
const appDb = BaseDb.getAppDb();
|
|
8909
|
+
const whereClauses = [];
|
|
8910
|
+
// Re-check types with dynamically imported ModelPropertyDataTypes
|
|
8911
|
+
// Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
|
|
8912
|
+
const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
|
|
8913
|
+
const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
|
|
8914
|
+
propertyRecordSchema &&
|
|
8915
|
+
propertyRecordSchema.ref &&
|
|
8916
|
+
normalizedDataType === ModelPropertyDataTypes.Relation;
|
|
8917
|
+
const isImageDynamic = propertyRecordSchema &&
|
|
8918
|
+
(normalizedDataType === ModelPropertyDataTypes.Image ||
|
|
8919
|
+
normalizedRefValueType === ModelPropertyDataTypes.Image);
|
|
8920
|
+
const isFileDynamic = propertyRecordSchema &&
|
|
8921
|
+
normalizedDataType === ModelPropertyDataTypes.File;
|
|
8922
|
+
const isHtmlDynamic = propertyRecordSchema &&
|
|
8923
|
+
normalizedDataType === ModelPropertyDataTypes.Html;
|
|
8924
|
+
// Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
|
|
8925
|
+
const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
|
|
8926
|
+
whereClauses.push(propertyNames.length > 1
|
|
8927
|
+
? drizzleOrm.or(...propertyNames.map((n) => drizzleOrm.eq(metadata$1.propertyName, n)))
|
|
8928
|
+
: drizzleOrm.eq(metadata$1.propertyName, propertyNames[0]));
|
|
8929
|
+
// Draft rows often have only seed_local_id populated; on-chain rows may have uid.
|
|
8930
|
+
// Requiring both with AND misses valid metadata when only one column is set.
|
|
8931
|
+
if (seedUid && seedLocalId) {
|
|
8932
|
+
whereClauses.push(drizzleOrm.or(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId), drizzleOrm.eq(metadata$1.seedUid, seedUid)));
|
|
8933
|
+
}
|
|
8934
|
+
else if (seedUid) {
|
|
8935
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.seedUid, seedUid));
|
|
8936
|
+
}
|
|
8937
|
+
else if (seedLocalId) {
|
|
8938
|
+
whereClauses.push(drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId));
|
|
8939
|
+
}
|
|
8940
|
+
const rows = await appDb
|
|
8941
|
+
.select()
|
|
8942
|
+
.from(metadata$1)
|
|
8943
|
+
.where(drizzleOrm.and(...whereClauses))
|
|
8944
|
+
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
|
|
8945
|
+
if (!rows || !rows.length) {
|
|
8946
|
+
return;
|
|
8947
|
+
}
|
|
8948
|
+
const firstRow = rows[0];
|
|
8949
|
+
const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
|
|
8950
|
+
let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
|
|
8951
|
+
let propertyValueProcessed = propertyValueFromDb;
|
|
8952
|
+
let renderValue = refResolvedDisplayValue ?? undefined;
|
|
8953
|
+
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
8954
|
+
if (isImageDynamic) {
|
|
8955
|
+
let dir = localStorageDir;
|
|
8956
|
+
if (!dir && isImageDynamic) {
|
|
8957
|
+
dir = 'images';
|
|
8958
|
+
}
|
|
8959
|
+
dir = dir.replace(/^\//, '');
|
|
8960
|
+
if (propertyValueFromDb &&
|
|
8961
|
+
propertyValueFromDb.length === 66) {
|
|
8962
|
+
// Here the storageTransactionId is stored on a different record and
|
|
8963
|
+
// we want to add it as the refResolvedValue
|
|
8964
|
+
const storageTransactionQuery = await appDb
|
|
8965
|
+
.select({
|
|
8966
|
+
propertyValue: metadata$1.propertyValue,
|
|
8967
|
+
})
|
|
8968
|
+
.from(metadata$1)
|
|
8969
|
+
.where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, propertyValueFromDb), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))));
|
|
8970
|
+
if (storageTransactionQuery && storageTransactionQuery.length > 0) {
|
|
8971
|
+
const row = storageTransactionQuery[0];
|
|
8972
|
+
refResolvedValue = row.propertyValue;
|
|
8973
|
+
await updateMetadata({
|
|
8974
|
+
localId,
|
|
8975
|
+
refResolvedValue,
|
|
8976
|
+
localStorageDir: '/images',
|
|
8977
|
+
});
|
|
8978
|
+
}
|
|
8979
|
+
}
|
|
8980
|
+
const resolveMatchingFilePath = async (dir, needle) => {
|
|
8981
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
8982
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
8983
|
+
if (!dirExists)
|
|
8984
|
+
return undefined;
|
|
8985
|
+
const fs = await BaseFileManager.getFs();
|
|
8986
|
+
const path = BaseFileManager.getPathModule();
|
|
8987
|
+
const files = await fs.promises.readdir(dirPath);
|
|
8988
|
+
const matchingFiles = files.filter((file) => {
|
|
8989
|
+
return path.basename(file).includes(needle);
|
|
8990
|
+
});
|
|
8991
|
+
if (!matchingFiles?.length)
|
|
8992
|
+
return undefined;
|
|
8993
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
8994
|
+
};
|
|
8995
|
+
if (refResolvedValue) {
|
|
8996
|
+
try {
|
|
8997
|
+
let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
|
|
8998
|
+
if (!filePath) {
|
|
8999
|
+
await downloadTransactionIdWithDedupe(refResolvedValue);
|
|
9000
|
+
filePath = await resolveMatchingFilePath(dir, refResolvedValue);
|
|
9001
|
+
}
|
|
9002
|
+
localStorageDir = `/${dir}`;
|
|
9003
|
+
if (filePath) {
|
|
9004
|
+
const file = await BaseFileManager.readFile(filePath);
|
|
9005
|
+
refResolvedDisplayValue = URL.createObjectURL(file);
|
|
9006
|
+
renderValue = refResolvedDisplayValue;
|
|
9007
|
+
// Do not persist blob URL - it is session-scoped
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
catch (e) {
|
|
9011
|
+
logger$k('[hydrateFromDb] Image file resolution error', e);
|
|
9012
|
+
}
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
9015
|
+
if (isFileDynamic && refResolvedValue) {
|
|
9016
|
+
try {
|
|
9017
|
+
const dir = (localStorageDir ?? '/files').replace(/^\//, '');
|
|
9018
|
+
const resolveMatchingFilePath = async (needle) => {
|
|
9019
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9020
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9021
|
+
if (!dirExists)
|
|
9022
|
+
return undefined;
|
|
9023
|
+
const fs = await BaseFileManager.getFs();
|
|
9024
|
+
const path = BaseFileManager.getPathModule();
|
|
9025
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9026
|
+
const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
|
|
9027
|
+
if (!matchingFiles?.length)
|
|
9028
|
+
return undefined;
|
|
9029
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9030
|
+
};
|
|
9031
|
+
let filePath = await resolveMatchingFilePath(refResolvedValue);
|
|
9032
|
+
if (!filePath) {
|
|
9033
|
+
await downloadTransactionIdWithDedupe(refResolvedValue);
|
|
9034
|
+
filePath = await resolveMatchingFilePath(refResolvedValue);
|
|
9035
|
+
}
|
|
9036
|
+
if (filePath) {
|
|
9037
|
+
localStorageDir = `/${dir}`;
|
|
9038
|
+
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
catch (e) {
|
|
9042
|
+
logger$k('[hydrateFromDb] File resolution error', e);
|
|
9043
|
+
}
|
|
9044
|
+
}
|
|
9045
|
+
if (propertyRecordSchema &&
|
|
9046
|
+
normalizedDataType === ModelPropertyDataTypes.List &&
|
|
9047
|
+
typeof propertyValueFromDb === 'string') {
|
|
9048
|
+
propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
|
|
9049
|
+
}
|
|
9050
|
+
sendBack({
|
|
9051
|
+
type: 'updateContext',
|
|
9052
|
+
localId,
|
|
9053
|
+
uid,
|
|
9054
|
+
propertyValue: propertyValueProcessed,
|
|
9055
|
+
seedLocalId: seedLocalIdFromDb,
|
|
9056
|
+
seedUid: seedUidFromDb,
|
|
9057
|
+
versionLocalId: versionLocalIdFromDb,
|
|
9058
|
+
versionUid: versionUidFromDb,
|
|
9059
|
+
schemaUid: schemaUidFromDb,
|
|
9060
|
+
refValueType,
|
|
9061
|
+
localStorageDir,
|
|
9062
|
+
refResolvedValue,
|
|
9063
|
+
refResolvedDisplayValue,
|
|
9064
|
+
renderValue,
|
|
9065
|
+
populatedFromDb: true,
|
|
9066
|
+
});
|
|
9067
|
+
if (propertyRecordSchema &&
|
|
9068
|
+
propertyRecordSchema.storageType &&
|
|
9069
|
+
propertyRecordSchema.storageType === 'ItemStorage') {
|
|
9070
|
+
const itemMod = await Promise.resolve().then(function () { return Item$1; });
|
|
9071
|
+
const { Item } = itemMod;
|
|
9072
|
+
const item = await Item.find({
|
|
9073
|
+
seedLocalId: seedLocalId ?? undefined,
|
|
9074
|
+
modelName,
|
|
9075
|
+
});
|
|
9076
|
+
if (item) {
|
|
9077
|
+
const dir = localStorageDir?.replace(/^\//, '') || 'files';
|
|
9078
|
+
const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
|
|
9079
|
+
const exists = await BaseFileManager.pathExists(filePath);
|
|
9080
|
+
if (!exists) {
|
|
9081
|
+
return;
|
|
9082
|
+
}
|
|
9083
|
+
const renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
9084
|
+
const property = item.properties.find(p => p.propertyName === propertyName);
|
|
8170
9085
|
if (property) {
|
|
8171
9086
|
property.getService().send({ type: 'updateContext', renderValue });
|
|
8172
9087
|
}
|
|
8173
9088
|
return;
|
|
8174
9089
|
}
|
|
8175
9090
|
}
|
|
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
|
|
9091
|
+
// Html: read file content for renderValue (blob URLs from DB are invalid after reload).
|
|
9092
|
+
// When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
|
|
9093
|
+
if (isHtmlDynamic) {
|
|
9094
|
+
const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
|
|
9095
|
+
let htmlContent;
|
|
9096
|
+
let outRef = refResolvedValue;
|
|
9097
|
+
let outDir = htmlLocalStorageDir;
|
|
9098
|
+
if (refResolvedValue && htmlLocalStorageDir) {
|
|
9099
|
+
const dir = htmlLocalStorageDir.replace(/^\//, '');
|
|
9100
|
+
const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
|
|
9101
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
9102
|
+
if (!exists) {
|
|
9103
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
9104
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
9105
|
+
}
|
|
9106
|
+
if (exists) {
|
|
9107
|
+
htmlContent = await BaseFileManager.readFileAsString(filePath);
|
|
9108
|
+
}
|
|
9109
|
+
}
|
|
9110
|
+
if (!htmlContent && propertyValueFromDb) {
|
|
9111
|
+
htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
|
|
9112
|
+
const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
|
|
9113
|
+
if (lid) {
|
|
9114
|
+
outRef = `${lid}.html`;
|
|
9115
|
+
outDir = '/html';
|
|
9116
|
+
}
|
|
9117
|
+
}
|
|
9118
|
+
if (htmlContent) {
|
|
8185
9119
|
sendBack({
|
|
8186
9120
|
type: 'updateContext',
|
|
8187
9121
|
localId,
|
|
@@ -8193,8 +9127,8 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8193
9127
|
versionUid: versionUidFromDb,
|
|
8194
9128
|
schemaUid: schemaUidFromDb,
|
|
8195
9129
|
refValueType,
|
|
8196
|
-
localStorageDir:
|
|
8197
|
-
refResolvedValue,
|
|
9130
|
+
localStorageDir: outDir,
|
|
9131
|
+
refResolvedValue: outRef ?? refResolvedValue,
|
|
8198
9132
|
refResolvedDisplayValue,
|
|
8199
9133
|
renderValue: htmlContent,
|
|
8200
9134
|
populatedFromDb: true,
|
|
@@ -8208,11 +9142,11 @@ const hydrateFromDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8208
9142
|
});
|
|
8209
9143
|
});
|
|
8210
9144
|
|
|
8211
|
-
const logger$
|
|
9145
|
+
const logger$j = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
|
|
8212
9146
|
const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context } }) => {
|
|
8213
9147
|
const _loadOrCreateProperty = async () => {
|
|
8214
9148
|
const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
|
|
8215
|
-
logger$
|
|
9149
|
+
logger$j(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
|
|
8216
9150
|
if (!seedLocalId && !seedUid) {
|
|
8217
9151
|
throw new Error('seedLocalId or seedUid is required');
|
|
8218
9152
|
}
|
|
@@ -8258,15 +9192,15 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8258
9192
|
const schemas = modelPropertiesToObject(model$1.properties);
|
|
8259
9193
|
propertyRecordSchema = schemas[propertyName];
|
|
8260
9194
|
if (propertyRecordSchema) {
|
|
8261
|
-
logger$
|
|
9195
|
+
logger$j(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
|
|
8262
9196
|
}
|
|
8263
9197
|
}
|
|
8264
9198
|
}
|
|
8265
9199
|
catch (error) {
|
|
8266
|
-
logger$
|
|
9200
|
+
logger$j(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
|
|
8267
9201
|
}
|
|
8268
9202
|
}
|
|
8269
|
-
logger$
|
|
9203
|
+
logger$j(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
|
|
8270
9204
|
sendBack({
|
|
8271
9205
|
type: 'loadOrCreatePropertySuccess',
|
|
8272
9206
|
property: {
|
|
@@ -8332,7 +9266,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8332
9266
|
};
|
|
8333
9267
|
// Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
|
|
8334
9268
|
try {
|
|
8335
|
-
const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-
|
|
9269
|
+
const { getPropertySchema } = await Promise.resolve().then(function () { return require('./property-2D7P6a2q.js'); });
|
|
8336
9270
|
let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
|
|
8337
9271
|
if (!schemaFromFile?.validation) {
|
|
8338
9272
|
// Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
|
|
@@ -8370,7 +9304,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8370
9304
|
}
|
|
8371
9305
|
}
|
|
8372
9306
|
catch (error) {
|
|
8373
|
-
logger$
|
|
9307
|
+
logger$j(`Error loading propertyRecordSchema from database: ${error}`);
|
|
8374
9308
|
// Continue without propertyRecordSchema
|
|
8375
9309
|
}
|
|
8376
9310
|
}
|
|
@@ -8388,22 +9322,27 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8388
9322
|
const schemas = modelPropertiesToObject(model$1.properties);
|
|
8389
9323
|
propertyRecordSchema = schemas[propertyName];
|
|
8390
9324
|
if (propertyRecordSchema) {
|
|
8391
|
-
logger$
|
|
9325
|
+
logger$j(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
|
|
8392
9326
|
}
|
|
8393
9327
|
}
|
|
8394
9328
|
}
|
|
8395
9329
|
catch (error) {
|
|
8396
|
-
logger$
|
|
9330
|
+
logger$j(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
|
|
8397
9331
|
}
|
|
8398
9332
|
}
|
|
8399
9333
|
// For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
|
|
8400
9334
|
let renderValue = metadataRecord.propertyValue || undefined;
|
|
8401
9335
|
const refSeedType = metadataRecord.refSeedType;
|
|
8402
|
-
const
|
|
8403
|
-
|
|
9336
|
+
const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
|
|
9337
|
+
const isHtml = refSeedType === 'html' || normalizedHtmlDt === exports.ModelPropertyDataTypes.Html;
|
|
9338
|
+
// Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
|
|
9339
|
+
// After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
|
|
8404
9340
|
if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
|
|
8405
|
-
|
|
8406
|
-
|
|
9341
|
+
const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
|
|
9342
|
+
if (lid) {
|
|
9343
|
+
metadataRecord.refResolvedValue = `${lid}.html`;
|
|
9344
|
+
metadataRecord.localStorageDir = '/html';
|
|
9345
|
+
}
|
|
8407
9346
|
}
|
|
8408
9347
|
// Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
|
|
8409
9348
|
if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
|
|
@@ -8413,13 +9352,34 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8413
9352
|
try {
|
|
8414
9353
|
const dir = metadataRecord.localStorageDir.replace(/^\//, '');
|
|
8415
9354
|
const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
|
|
8416
|
-
|
|
9355
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
9356
|
+
if (!exists) {
|
|
9357
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
9358
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
9359
|
+
}
|
|
8417
9360
|
if (exists) {
|
|
8418
9361
|
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
8419
9362
|
}
|
|
9363
|
+
else {
|
|
9364
|
+
const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
|
|
9365
|
+
if (viaSeedPointer) {
|
|
9366
|
+
renderValue = viaSeedPointer;
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
8420
9369
|
}
|
|
8421
9370
|
catch (e) {
|
|
8422
|
-
logger$
|
|
9371
|
+
logger$j(`Failed to read Html file for ${propertyName}: ${e}`);
|
|
9372
|
+
}
|
|
9373
|
+
}
|
|
9374
|
+
// Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
|
|
9375
|
+
if (isHtml && metadataRecord.propertyValue) {
|
|
9376
|
+
const pv = String(metadataRecord.propertyValue).trim();
|
|
9377
|
+
const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
|
|
9378
|
+
if (!rv || rv === pv) {
|
|
9379
|
+
const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
|
|
9380
|
+
if (recovered) {
|
|
9381
|
+
renderValue = recovered;
|
|
9382
|
+
}
|
|
8423
9383
|
}
|
|
8424
9384
|
}
|
|
8425
9385
|
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
@@ -8429,28 +9389,83 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8429
9389
|
const isImage = refSeedType === 'image' ||
|
|
8430
9390
|
normalizedDataType === 'Image' ||
|
|
8431
9391
|
normalizedRefValueType === 'Image';
|
|
9392
|
+
const resolveMatchingFilePath = async (dir, needle) => {
|
|
9393
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9394
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9395
|
+
if (!dirExists)
|
|
9396
|
+
return undefined;
|
|
9397
|
+
const fs = await BaseFileManager.getFs();
|
|
9398
|
+
const path = BaseFileManager.getPathModule();
|
|
9399
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9400
|
+
const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
|
|
9401
|
+
if (!matchingFiles?.length)
|
|
9402
|
+
return undefined;
|
|
9403
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9404
|
+
};
|
|
9405
|
+
// EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
|
|
9406
|
+
// hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
|
|
9407
|
+
if (isImage &&
|
|
9408
|
+
!metadataRecord.refResolvedValue &&
|
|
9409
|
+
typeof metadataRecord.propertyValue === 'string' &&
|
|
9410
|
+
metadataRecord.propertyValue.length === 66) {
|
|
9411
|
+
const storageTxRows = await db
|
|
9412
|
+
.select({ propertyValue: metadata$1.propertyValue })
|
|
9413
|
+
.from(metadata$1)
|
|
9414
|
+
.where(drizzleOrm.and(drizzleOrm.eq(metadata$1.seedUid, metadataRecord.propertyValue), drizzleOrm.or(drizzleOrm.eq(metadata$1.propertyName, 'storageTransactionId'), drizzleOrm.eq(metadata$1.propertyName, 'transactionId'))))
|
|
9415
|
+
.limit(1);
|
|
9416
|
+
const derivedTxId = storageTxRows[0]?.propertyValue;
|
|
9417
|
+
if (derivedTxId) {
|
|
9418
|
+
metadataRecord.refResolvedValue = derivedTxId;
|
|
9419
|
+
metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
|
|
9420
|
+
if (metadataRecord.localId) {
|
|
9421
|
+
try {
|
|
9422
|
+
await updateMetadata({
|
|
9423
|
+
localId: metadataRecord.localId,
|
|
9424
|
+
refResolvedValue: derivedTxId,
|
|
9425
|
+
localStorageDir: '/images',
|
|
9426
|
+
});
|
|
9427
|
+
}
|
|
9428
|
+
catch (e) {
|
|
9429
|
+
logger$j(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
}
|
|
9433
|
+
}
|
|
8432
9434
|
if (isImage && metadataRecord.refResolvedValue) {
|
|
8433
9435
|
try {
|
|
8434
9436
|
const dir = (metadataRecord.localStorageDir ?? '/images').replace(/^\//, '');
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
const
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
9437
|
+
let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9438
|
+
if (!filePath) {
|
|
9439
|
+
await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
|
|
9440
|
+
filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9441
|
+
}
|
|
9442
|
+
if (filePath) {
|
|
9443
|
+
const file = await BaseFileManager.readFile(filePath);
|
|
9444
|
+
const freshBlobUrl = URL.createObjectURL(file);
|
|
9445
|
+
renderValue = freshBlobUrl;
|
|
9446
|
+
refResolvedDisplayValue = freshBlobUrl;
|
|
9447
|
+
}
|
|
9448
|
+
}
|
|
9449
|
+
catch (e) {
|
|
9450
|
+
logger$j(`Failed to resolve Image file for ${propertyName}: ${e}`);
|
|
9451
|
+
}
|
|
9452
|
+
}
|
|
9453
|
+
const isFile = refSeedType === 'file' ||
|
|
9454
|
+
normalizedDataType === 'File';
|
|
9455
|
+
if (isFile && metadataRecord.refResolvedValue) {
|
|
9456
|
+
try {
|
|
9457
|
+
const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
|
|
9458
|
+
let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9459
|
+
if (!filePath) {
|
|
9460
|
+
await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
|
|
9461
|
+
filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9462
|
+
}
|
|
9463
|
+
if (filePath) {
|
|
9464
|
+
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
8450
9465
|
}
|
|
8451
9466
|
}
|
|
8452
9467
|
catch (e) {
|
|
8453
|
-
logger$
|
|
9468
|
+
logger$j(`Failed to resolve File for ${propertyName}: ${e}`);
|
|
8454
9469
|
}
|
|
8455
9470
|
}
|
|
8456
9471
|
let propertyValueOut = metadataRecord.propertyValue || undefined;
|
|
@@ -8482,7 +9497,7 @@ const loadOrCreateProperty = xstate.fromCallback(({ sendBack, input: { context }
|
|
|
8482
9497
|
});
|
|
8483
9498
|
};
|
|
8484
9499
|
_loadOrCreateProperty().catch((error) => {
|
|
8485
|
-
logger$
|
|
9500
|
+
logger$j(`Error in loadOrCreateProperty: ${error}`);
|
|
8486
9501
|
sendBack({
|
|
8487
9502
|
type: 'loadOrCreatePropertyError',
|
|
8488
9503
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -8512,10 +9527,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
|
|
|
8512
9527
|
return queryRows[0];
|
|
8513
9528
|
};
|
|
8514
9529
|
|
|
8515
|
-
const logger$
|
|
9530
|
+
const logger$i = debug('seedSdk:write:updateItemPropertyValue');
|
|
8516
9531
|
const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
|
|
8517
9532
|
if (!localIdParam && !seedLocalId) {
|
|
8518
|
-
logger$
|
|
9533
|
+
logger$i(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
|
|
8519
9534
|
return;
|
|
8520
9535
|
}
|
|
8521
9536
|
let safeNewValue = newValue;
|
|
@@ -8543,7 +9558,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8543
9558
|
.select()
|
|
8544
9559
|
.from(metadata$1)
|
|
8545
9560
|
.where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
|
|
8546
|
-
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
|
|
9561
|
+
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
|
|
8547
9562
|
}
|
|
8548
9563
|
}
|
|
8549
9564
|
else if (localIdParam) {
|
|
@@ -8563,7 +9578,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8563
9578
|
.select()
|
|
8564
9579
|
.from(metadata$1)
|
|
8565
9580
|
.where(drizzleOrm.and(propertyNameWhere, drizzleOrm.eq(metadata$1.seedLocalId, seedLocalId)))
|
|
8566
|
-
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
|
|
9581
|
+
.orderBy(drizzleOrm.sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
|
|
8567
9582
|
}
|
|
8568
9583
|
// const mostRecentRecordStatement = `SELECT local_id,
|
|
8569
9584
|
// uid,
|
|
@@ -8579,7 +9594,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8579
9594
|
// FROM metadata
|
|
8580
9595
|
// WHERE property_name = '${propertyName}'
|
|
8581
9596
|
// AND seed_local_id = '${seedLocalId}'
|
|
8582
|
-
// ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
|
|
9597
|
+
// ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
|
|
8583
9598
|
//
|
|
8584
9599
|
// const { rows } = await runQueryForStatement(mostRecentRecordStatement)
|
|
8585
9600
|
if (rows && rows.length > 0) {
|
|
@@ -8588,7 +9603,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8588
9603
|
modelType === modelName?.toLowerCase() &&
|
|
8589
9604
|
refSeedTypeFromDb === refSeedType &&
|
|
8590
9605
|
refResolvedValueFromDb === refResolvedValue) {
|
|
8591
|
-
logger$
|
|
9606
|
+
logger$i(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
|
|
8592
9607
|
return;
|
|
8593
9608
|
}
|
|
8594
9609
|
// This means we already have a local-only record so we should just update that one
|
|
@@ -8716,9 +9731,9 @@ const analyzeInput = xstate.fromCallback(({ sendBack, input: { context, event }
|
|
|
8716
9731
|
}
|
|
8717
9732
|
const _analyzeInput = async () => {
|
|
8718
9733
|
// Use dynamic import to break circular dependency
|
|
8719
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
9734
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
8720
9735
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
8721
|
-
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
9736
|
+
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
|
|
8722
9737
|
let propertyName = propertyNameRaw;
|
|
8723
9738
|
if (!propertyName) {
|
|
8724
9739
|
throw new Error('propertyName is required');
|
|
@@ -8916,7 +9931,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
|
|
|
8916
9931
|
propertyRecordSchema?.validation &&
|
|
8917
9932
|
metadataValues.propertyValue != null &&
|
|
8918
9933
|
metadataValues.propertyValue !== '') {
|
|
8919
|
-
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-
|
|
9934
|
+
const { SchemaValidationService } = await Promise.resolve().then(function () { return require('./SchemaValidationService-Cq_YBzFN.js'); });
|
|
8920
9935
|
const validationService = new SchemaValidationService();
|
|
8921
9936
|
const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
|
|
8922
9937
|
if (!validationResult.isValid && validationResult.errors.length > 0) {
|
|
@@ -8994,8 +10009,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
|
|
|
8994
10009
|
return inserted[0];
|
|
8995
10010
|
};
|
|
8996
10011
|
|
|
8997
|
-
const eventEmitter = new EventEmitter();
|
|
8998
|
-
|
|
8999
10012
|
const readFileAsArrayBuffer$1 = async (file) => {
|
|
9000
10013
|
return new Promise((resolve) => {
|
|
9001
10014
|
const reader = new FileReader();
|
|
@@ -9142,6 +10155,12 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
|
|
|
9142
10155
|
}
|
|
9143
10156
|
const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
|
|
9144
10157
|
let newLocalId;
|
|
10158
|
+
const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
|
|
10159
|
+
? schemaUid
|
|
10160
|
+
: (await getEasSchemaForItemProperty({
|
|
10161
|
+
propertyName,
|
|
10162
|
+
easDataType: 'bytes32',
|
|
10163
|
+
}))?.id;
|
|
9145
10164
|
if (!localId) {
|
|
9146
10165
|
const result = await createMetadata({
|
|
9147
10166
|
propertyName,
|
|
@@ -9151,7 +10170,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
|
|
|
9151
10170
|
versionLocalId,
|
|
9152
10171
|
versionUid,
|
|
9153
10172
|
modelName,
|
|
9154
|
-
schemaUid:
|
|
10173
|
+
schemaUid: resolvedPropertySchemaUid,
|
|
9155
10174
|
refSeedType: 'image',
|
|
9156
10175
|
refModelUid: imageSchemaUid,
|
|
9157
10176
|
refResolvedValue: fileName,
|
|
@@ -9170,7 +10189,7 @@ const saveImage = xstate.fromCallback(({ sendBack, input: { context, event } })
|
|
|
9170
10189
|
seedLocalId,
|
|
9171
10190
|
versionLocalId,
|
|
9172
10191
|
modelName,
|
|
9173
|
-
schemaUid,
|
|
10192
|
+
schemaUid: resolvedPropertySchemaUid,
|
|
9174
10193
|
refSeedType: 'image',
|
|
9175
10194
|
refResolvedValue: fileName,
|
|
9176
10195
|
localStorageDir: '/images',
|
|
@@ -9503,7 +10522,7 @@ const saveRelation = xstate.fromCallback(({ sendBack, input: { context, event }
|
|
|
9503
10522
|
}
|
|
9504
10523
|
const _saveRelation = async () => {
|
|
9505
10524
|
// Use dynamic import to break circular dependency
|
|
9506
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
10525
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
9507
10526
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
9508
10527
|
if (!propertyNameRaw) {
|
|
9509
10528
|
throw new Error('propertyName is required');
|
|
@@ -9712,6 +10731,10 @@ const propertyMachine = xstate.setup({
|
|
|
9712
10731
|
context: {},
|
|
9713
10732
|
input: {},
|
|
9714
10733
|
},
|
|
10734
|
+
guards: {
|
|
10735
|
+
// stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
|
|
10736
|
+
propertyMachineIsIdle: xstate.stateIn('idle'),
|
|
10737
|
+
},
|
|
9715
10738
|
// actions: {
|
|
9716
10739
|
// updateContext: updateMachineContext,
|
|
9717
10740
|
// },
|
|
@@ -9734,7 +10757,11 @@ const propertyMachine = xstate.setup({
|
|
|
9734
10757
|
initial: 'waitingForDb',
|
|
9735
10758
|
context: ({ input }) => input,
|
|
9736
10759
|
on: {
|
|
9737
|
-
|
|
10760
|
+
/** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
|
|
10761
|
+
rehydrateFromDb: {
|
|
10762
|
+
guard: 'propertyMachineIsIdle',
|
|
10763
|
+
target: '.hydratingFromDb',
|
|
10764
|
+
},
|
|
9738
10765
|
save: {
|
|
9739
10766
|
actions: xstate.assign({
|
|
9740
10767
|
isSaving: true,
|
|
@@ -10333,6 +11360,8 @@ function createReactiveProxy(config) {
|
|
|
10333
11360
|
return proxy;
|
|
10334
11361
|
}
|
|
10335
11362
|
|
|
11363
|
+
/** Parent Html property `propertyValue` after publish (66-char seed uid). */
|
|
11364
|
+
const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
10336
11365
|
// Start loading Model at module load time (non-blocking)
|
|
10337
11366
|
Promise.resolve().then(function () { return Model$1; }).then(module => {
|
|
10338
11367
|
module.Model;
|
|
@@ -10432,7 +11461,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
|
|
|
10432
11461
|
};
|
|
10433
11462
|
/** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
|
|
10434
11463
|
const modelTypeToModelName = (modelType) => modelType ? lodashEs.upperFirst(lodashEs.camelCase(modelType)) : '';
|
|
10435
|
-
const logger$
|
|
11464
|
+
const logger$h = debug('seedSdk:property:class');
|
|
10436
11465
|
// Define tracked properties for the Proxy
|
|
10437
11466
|
// These properties will be read from/written to the actor context
|
|
10438
11467
|
const TRACKED_PROPERTIES$2 = [
|
|
@@ -10514,7 +11543,7 @@ class ItemProperty {
|
|
|
10514
11543
|
serviceInput.propertyValue = JSON.parse(propertyValue);
|
|
10515
11544
|
}
|
|
10516
11545
|
catch (e) {
|
|
10517
|
-
logger$
|
|
11546
|
+
logger$h('List property value is not JSON', e);
|
|
10518
11547
|
}
|
|
10519
11548
|
}
|
|
10520
11549
|
}
|
|
@@ -10537,7 +11566,7 @@ class ItemProperty {
|
|
|
10537
11566
|
return;
|
|
10538
11567
|
}
|
|
10539
11568
|
// Use dynamic import to break circular dependency
|
|
10540
|
-
const schemaMod = await Promise.resolve().then(function () { return require('./index-
|
|
11569
|
+
const schemaMod = await Promise.resolve().then(function () { return require('./index-DqSDhOp3.js'); });
|
|
10541
11570
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
10542
11571
|
const { context } = snapshot;
|
|
10543
11572
|
const { propertyRecordSchema } = context;
|
|
@@ -10560,7 +11589,8 @@ class ItemProperty {
|
|
|
10560
11589
|
propertyRecordSchema.storageType === 'ItemStorage' &&
|
|
10561
11590
|
context.refResolvedValue &&
|
|
10562
11591
|
context.localStorageDir;
|
|
10563
|
-
const
|
|
11592
|
+
const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
|
|
11593
|
+
const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
|
|
10564
11594
|
context.refResolvedValue;
|
|
10565
11595
|
// Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
|
|
10566
11596
|
// so the UI can display the filename and preview immediately (these update again when save completes)
|
|
@@ -10596,7 +11626,11 @@ class ItemProperty {
|
|
|
10596
11626
|
const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
|
|
10597
11627
|
const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
|
|
10598
11628
|
try {
|
|
10599
|
-
|
|
11629
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
11630
|
+
if (!exists && isHtml) {
|
|
11631
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
11632
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
11633
|
+
}
|
|
10600
11634
|
if (exists && (isItemStorage || isHtml)) {
|
|
10601
11635
|
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
10602
11636
|
}
|
|
@@ -10616,8 +11650,8 @@ class ItemProperty {
|
|
|
10616
11650
|
if (isFile && isFileValue) {
|
|
10617
11651
|
renderValue = pv.name;
|
|
10618
11652
|
}
|
|
10619
|
-
else if (isImage) {
|
|
10620
|
-
// FS race
|
|
11653
|
+
else if (isImage || isHtml) {
|
|
11654
|
+
// FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
|
|
10621
11655
|
renderValue = undefined;
|
|
10622
11656
|
}
|
|
10623
11657
|
else {
|
|
@@ -10626,13 +11660,21 @@ class ItemProperty {
|
|
|
10626
11660
|
}
|
|
10627
11661
|
}
|
|
10628
11662
|
catch (e) {
|
|
10629
|
-
logger$
|
|
10630
|
-
renderValue = 'No file found';
|
|
11663
|
+
logger$h(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
|
|
11664
|
+
renderValue = isHtml ? undefined : 'No file found';
|
|
10631
11665
|
}
|
|
10632
11666
|
}
|
|
10633
11667
|
if (!renderValue) {
|
|
10634
11668
|
renderValue = context.renderValue || context.propertyValue;
|
|
10635
11669
|
}
|
|
11670
|
+
const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
|
|
11671
|
+
if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
|
|
11672
|
+
HTML_PROP_SEED_UID_RE.test(pvStr) &&
|
|
11673
|
+
renderValue === pvStr &&
|
|
11674
|
+
typeof context.renderValue === 'string' &&
|
|
11675
|
+
context.renderValue.length > pvStr.length) {
|
|
11676
|
+
renderValue = context.renderValue;
|
|
11677
|
+
}
|
|
10636
11678
|
let transformedPropertyName = propertyName;
|
|
10637
11679
|
const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
|
|
10638
11680
|
if (!skipTransform && transformedPropertyName.endsWith('Id')) {
|
|
@@ -11045,6 +12087,35 @@ class ItemProperty {
|
|
|
11045
12087
|
instance._service.send({ type: 'updateContext', ...updates });
|
|
11046
12088
|
}
|
|
11047
12089
|
}
|
|
12090
|
+
// After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
|
|
12091
|
+
// paths would hydrate. Re-run DB hydration without clobbering propertyValue.
|
|
12092
|
+
const svc = instance._service;
|
|
12093
|
+
const snap = svc.getSnapshot();
|
|
12094
|
+
if (snap.status === 'active' && snap.value === 'idle') {
|
|
12095
|
+
const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
|
|
12096
|
+
const dt = normalizeDataType(schema?.dataType);
|
|
12097
|
+
const isHtmlProp = props.refSeedType === 'html' ||
|
|
12098
|
+
ctx.refSeedType === 'html' ||
|
|
12099
|
+
dt === exports.ModelPropertyDataTypes.Html;
|
|
12100
|
+
const isListProp = dt === exports.ModelPropertyDataTypes.List;
|
|
12101
|
+
const isRelationProp = dt === exports.ModelPropertyDataTypes.Relation;
|
|
12102
|
+
const pv = ctx.propertyValue;
|
|
12103
|
+
const pvStr = typeof pv === 'string' ? pv.trim() : '';
|
|
12104
|
+
const renderVal = ctx.renderValue;
|
|
12105
|
+
const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
|
|
12106
|
+
const htmlStuckOnUid = isHtmlProp &&
|
|
12107
|
+
HTML_PROP_SEED_UID_RE.test(pvStr) &&
|
|
12108
|
+
(renderMissing || renderVal === pv);
|
|
12109
|
+
const pvPresent = pv != null &&
|
|
12110
|
+
(Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
|
|
12111
|
+
const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
|
|
12112
|
+
const versionChanged = props.versionLocalId != null &&
|
|
12113
|
+
ctx.versionLocalId != null &&
|
|
12114
|
+
props.versionLocalId !== ctx.versionLocalId;
|
|
12115
|
+
if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
|
|
12116
|
+
svc.send({ type: 'rehydrateFromDb' });
|
|
12117
|
+
}
|
|
12118
|
+
}
|
|
11048
12119
|
// On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
|
|
11049
12120
|
if (!waitForReady)
|
|
11050
12121
|
return instance;
|
|
@@ -11394,7 +12465,7 @@ class ItemProperty {
|
|
|
11394
12465
|
}
|
|
11395
12466
|
async save() {
|
|
11396
12467
|
const ctx = this._getSnapshotContext();
|
|
11397
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
12468
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
|
|
11398
12469
|
await assertItemOwned({
|
|
11399
12470
|
seedLocalId: ctx?.seedLocalId ?? undefined,
|
|
11400
12471
|
seedUid: ctx?.seedUid ?? undefined,
|
|
@@ -11733,7 +12804,7 @@ class Item {
|
|
|
11733
12804
|
});
|
|
11734
12805
|
};
|
|
11735
12806
|
this.unpublish = async () => {
|
|
11736
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
12807
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
|
|
11737
12808
|
const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
|
|
11738
12809
|
await assertItemOwned(this);
|
|
11739
12810
|
const seedUid = this.seedUid;
|
|
@@ -11757,7 +12828,7 @@ class Item {
|
|
|
11757
12828
|
this._service.send({ type: 'updateContext', revokedAt });
|
|
11758
12829
|
};
|
|
11759
12830
|
this.publish = async () => {
|
|
11760
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
12831
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
|
|
11761
12832
|
await assertItemOwned(this);
|
|
11762
12833
|
this._service.send({ type: 'startPublish' });
|
|
11763
12834
|
return new Promise((resolve, reject) => {
|
|
@@ -11793,12 +12864,12 @@ class Item {
|
|
|
11793
12864
|
};
|
|
11794
12865
|
this.getPublishUploads = async (options) => {
|
|
11795
12866
|
// Use dynamic import to break circular dependency
|
|
11796
|
-
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-
|
|
12867
|
+
const getPublishUploadsMod = await Promise.resolve().then(function () { return require('./getPublishUploads-BljRx4o4.js'); });
|
|
11797
12868
|
const { getPublishUploads } = getPublishUploadsMod;
|
|
11798
12869
|
return await getPublishUploads(this, [], undefined, options);
|
|
11799
12870
|
};
|
|
11800
12871
|
this.getPublishPayload = async (uploadedTransactions, options) => {
|
|
11801
|
-
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-
|
|
12872
|
+
const getPublishPayloadMod = await Promise.resolve().then(function () { return require('./getPublishPayload-ddl-1x6R.js'); });
|
|
11802
12873
|
const { getPublishPayload } = getPublishPayloadMod;
|
|
11803
12874
|
return await getPublishPayload(this, uploadedTransactions, options);
|
|
11804
12875
|
};
|
|
@@ -11915,6 +12986,8 @@ class Item {
|
|
|
11915
12986
|
'schemaUid',
|
|
11916
12987
|
'latestVersionLocalId',
|
|
11917
12988
|
'latestVersionUid',
|
|
12989
|
+
'publishedVersionUid',
|
|
12990
|
+
'publishedVersionLocalId',
|
|
11918
12991
|
];
|
|
11919
12992
|
const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
|
|
11920
12993
|
const schemaNameForModel = initialValues.schemaName;
|
|
@@ -11958,6 +13031,128 @@ class Item {
|
|
|
11958
13031
|
});
|
|
11959
13032
|
}
|
|
11960
13033
|
}
|
|
13034
|
+
/** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
|
|
13035
|
+
static findItemInstanceCacheEntryByProps(props) {
|
|
13036
|
+
const l = props.seedLocalId;
|
|
13037
|
+
const u = props.seedUid;
|
|
13038
|
+
if (typeof l === 'string' && l.length > 0) {
|
|
13039
|
+
const e = this.instanceCache.get(l);
|
|
13040
|
+
if (e)
|
|
13041
|
+
return e;
|
|
13042
|
+
}
|
|
13043
|
+
if (typeof u === 'string' && u.length > 0) {
|
|
13044
|
+
const e = this.instanceCache.get(u);
|
|
13045
|
+
if (e)
|
|
13046
|
+
return e;
|
|
13047
|
+
}
|
|
13048
|
+
return undefined;
|
|
13049
|
+
}
|
|
13050
|
+
static findItemInstanceCacheEntryById(id) {
|
|
13051
|
+
const direct = this.instanceCache.get(id);
|
|
13052
|
+
if (direct)
|
|
13053
|
+
return direct;
|
|
13054
|
+
for (const [, entry] of this.instanceCache) {
|
|
13055
|
+
const ctx = entry.instance._getSnapshotContext();
|
|
13056
|
+
if (ctx.seedLocalId === id || ctx.seedUid === id)
|
|
13057
|
+
return entry;
|
|
13058
|
+
}
|
|
13059
|
+
return undefined;
|
|
13060
|
+
}
|
|
13061
|
+
static collectInstanceCacheKeysForInstance(instance) {
|
|
13062
|
+
const keys = [];
|
|
13063
|
+
for (const [k, v] of this.instanceCache) {
|
|
13064
|
+
if (v.instance === instance)
|
|
13065
|
+
keys.push(k);
|
|
13066
|
+
}
|
|
13067
|
+
return keys;
|
|
13068
|
+
}
|
|
13069
|
+
static registerItemInInstanceCache(instance) {
|
|
13070
|
+
const ctx = instance._getSnapshotContext();
|
|
13071
|
+
const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
|
|
13072
|
+
? ctx.seedLocalId
|
|
13073
|
+
: undefined;
|
|
13074
|
+
const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
|
|
13075
|
+
const entry = { instance, refCount: 1 };
|
|
13076
|
+
if (lid)
|
|
13077
|
+
this.instanceCache.set(lid, entry);
|
|
13078
|
+
if (uid && uid !== lid)
|
|
13079
|
+
this.instanceCache.set(uid, entry);
|
|
13080
|
+
if (!lid && !uid) {
|
|
13081
|
+
throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
|
|
13082
|
+
}
|
|
13083
|
+
}
|
|
13084
|
+
static releaseItemInstanceCacheHold(instance) {
|
|
13085
|
+
const keys = this.collectInstanceCacheKeysForInstance(instance);
|
|
13086
|
+
if (keys.length === 0)
|
|
13087
|
+
return;
|
|
13088
|
+
const entry = this.instanceCache.get(keys[0]);
|
|
13089
|
+
entry.refCount -= 1;
|
|
13090
|
+
if (entry.refCount <= 0) {
|
|
13091
|
+
for (const k of keys) {
|
|
13092
|
+
this.instanceCache.delete(k);
|
|
13093
|
+
}
|
|
13094
|
+
}
|
|
13095
|
+
}
|
|
13096
|
+
/**
|
|
13097
|
+
* Item machine can reach `idle` before `propertyInstances` is merged (race) or while
|
|
13098
|
+
* child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
|
|
13099
|
+
*/
|
|
13100
|
+
static async waitForItemInstanceReadyForRead(item, readyTimeout) {
|
|
13101
|
+
await waitForEntityIdle(item, { timeout: readyTimeout });
|
|
13102
|
+
const svc = item.getService();
|
|
13103
|
+
try {
|
|
13104
|
+
await xstate.waitFor(svc, (snap) => {
|
|
13105
|
+
if ('value' in snap && snap.value === 'error') {
|
|
13106
|
+
throw new Error('Entity failed to load');
|
|
13107
|
+
}
|
|
13108
|
+
if (!('value' in snap) || snap.value !== 'idle') {
|
|
13109
|
+
return false;
|
|
13110
|
+
}
|
|
13111
|
+
const ctx = snap.context || {};
|
|
13112
|
+
const versionsCount = ctx.versionsCount ?? 0;
|
|
13113
|
+
const hasHeadVersion = !!ctx.latestVersionLocalId;
|
|
13114
|
+
if (versionsCount === 0 && !hasHeadVersion) {
|
|
13115
|
+
return true;
|
|
13116
|
+
}
|
|
13117
|
+
return (ctx.propertyInstances?.size ?? 0) > 0;
|
|
13118
|
+
}, { timeout: readyTimeout });
|
|
13119
|
+
}
|
|
13120
|
+
catch (e) {
|
|
13121
|
+
if (e?.message === 'Entity failed to load') {
|
|
13122
|
+
throw e;
|
|
13123
|
+
}
|
|
13124
|
+
const msg = typeof e?.message === 'string' ? e.message : '';
|
|
13125
|
+
const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
|
|
13126
|
+
if (!isWaitForTimeout) {
|
|
13127
|
+
throw e;
|
|
13128
|
+
}
|
|
13129
|
+
}
|
|
13130
|
+
const snap = svc.getSnapshot();
|
|
13131
|
+
const pis = snap.context?.propertyInstances;
|
|
13132
|
+
if (!pis || pis.size === 0) {
|
|
13133
|
+
return;
|
|
13134
|
+
}
|
|
13135
|
+
await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
|
|
13136
|
+
timeout: readyTimeout,
|
|
13137
|
+
throwOnError: false,
|
|
13138
|
+
})));
|
|
13139
|
+
}
|
|
13140
|
+
static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
|
|
13141
|
+
const snap = instance.getService().getSnapshot();
|
|
13142
|
+
if (snap.value !== 'idle')
|
|
13143
|
+
return false;
|
|
13144
|
+
const mapSize = snap.context.propertyInstances?.size ?? 0;
|
|
13145
|
+
if (mapSize > 0)
|
|
13146
|
+
return false;
|
|
13147
|
+
const ctx = snap.context;
|
|
13148
|
+
const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
|
|
13149
|
+
const hasVersionHead = versionsCount > 0 ||
|
|
13150
|
+
!!props.latestVersionLocalId ||
|
|
13151
|
+
!!ctx.latestVersionLocalId ||
|
|
13152
|
+
!!props.latestVersionUid ||
|
|
13153
|
+
!!ctx.latestVersionUid;
|
|
13154
|
+
return hasVersionHead;
|
|
13155
|
+
}
|
|
11961
13156
|
static async create(props, options) {
|
|
11962
13157
|
const waitForReady = options?.waitForReady !== false;
|
|
11963
13158
|
const readyTimeout = options?.readyTimeout ?? 5000;
|
|
@@ -11965,45 +13160,66 @@ class Item {
|
|
|
11965
13160
|
props.modelName = lodashEs.startCase(props.type);
|
|
11966
13161
|
}
|
|
11967
13162
|
if (props.seedUid || props.seedLocalId) {
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
13163
|
+
cacheReuse: {
|
|
13164
|
+
const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
|
|
13165
|
+
if (cachedEntry) {
|
|
13166
|
+
const instance = cachedEntry.instance;
|
|
13167
|
+
cachedEntry.refCount += 1;
|
|
13168
|
+
for (const [propertyName, propertyValue] of Object.entries(props)) {
|
|
13169
|
+
const snapshot = instance.getService().getSnapshot();
|
|
13170
|
+
const propertyInstances = snapshot.context.propertyInstances;
|
|
13171
|
+
if (!propertyInstances || !propertyInstances.has(propertyName)) {
|
|
13172
|
+
continue;
|
|
13173
|
+
}
|
|
13174
|
+
const propertyInstance = propertyInstances.get(propertyName);
|
|
13175
|
+
if (!propertyInstance) {
|
|
13176
|
+
continue;
|
|
13177
|
+
}
|
|
13178
|
+
propertyInstance.getService().send({
|
|
13179
|
+
type: 'updateContext',
|
|
13180
|
+
propertyValue,
|
|
13181
|
+
});
|
|
11984
13182
|
}
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
propertyValue,
|
|
11988
|
-
});
|
|
11989
|
-
}
|
|
11990
|
-
if (!waitForReady)
|
|
11991
|
-
return instance;
|
|
11992
|
-
try {
|
|
11993
|
-
await waitForEntityIdle(instance, { timeout: readyTimeout });
|
|
11994
|
-
}
|
|
11995
|
-
catch (err) {
|
|
13183
|
+
if (!waitForReady)
|
|
13184
|
+
return instance;
|
|
11996
13185
|
try {
|
|
11997
|
-
|
|
13186
|
+
await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
|
|
11998
13187
|
}
|
|
11999
|
-
catch {
|
|
12000
|
-
|
|
13188
|
+
catch (err) {
|
|
13189
|
+
try {
|
|
13190
|
+
instance.unload();
|
|
13191
|
+
}
|
|
13192
|
+
catch {
|
|
13193
|
+
/* best-effort cache cleanup */
|
|
13194
|
+
}
|
|
13195
|
+
throw err;
|
|
12001
13196
|
}
|
|
12002
|
-
|
|
13197
|
+
if (waitForReady &&
|
|
13198
|
+
this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
|
|
13199
|
+
forceRemoveFromCaches(instance, {
|
|
13200
|
+
getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
|
|
13201
|
+
caches: [Item.instanceCache],
|
|
13202
|
+
});
|
|
13203
|
+
try {
|
|
13204
|
+
unloadEntity(instance, {
|
|
13205
|
+
getCacheKeys: () => [],
|
|
13206
|
+
caches: [],
|
|
13207
|
+
instanceState: itemInstanceState,
|
|
13208
|
+
getService: (inst) => inst._service,
|
|
13209
|
+
onUnload: (inst) => {
|
|
13210
|
+
inst._subscription?.unsubscribe();
|
|
13211
|
+
},
|
|
13212
|
+
});
|
|
13213
|
+
}
|
|
13214
|
+
catch {
|
|
13215
|
+
/* best-effort teardown for stale cached shell */
|
|
13216
|
+
}
|
|
13217
|
+
break cacheReuse;
|
|
13218
|
+
}
|
|
13219
|
+
return instance;
|
|
12003
13220
|
}
|
|
12004
|
-
return instance;
|
|
12005
13221
|
}
|
|
12006
|
-
if (!this.
|
|
13222
|
+
if (!this.findItemInstanceCacheEntryByProps(props)) {
|
|
12007
13223
|
// Item no longer needs modelInstance - it loads properties from database independently
|
|
12008
13224
|
// Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
|
|
12009
13225
|
const { latestVersionUid, ...propsWithoutVersionUid } = props;
|
|
@@ -12092,14 +13308,11 @@ class Item {
|
|
|
12092
13308
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
12093
13309
|
},
|
|
12094
13310
|
});
|
|
12095
|
-
this.
|
|
12096
|
-
instance: proxiedInstance,
|
|
12097
|
-
refCount: 1,
|
|
12098
|
-
});
|
|
13311
|
+
this.registerItemInInstanceCache(proxiedInstance);
|
|
12099
13312
|
if (!waitForReady)
|
|
12100
13313
|
return proxiedInstance;
|
|
12101
13314
|
try {
|
|
12102
|
-
await
|
|
13315
|
+
await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
|
|
12103
13316
|
}
|
|
12104
13317
|
catch (err) {
|
|
12105
13318
|
try {
|
|
@@ -12275,14 +13488,11 @@ class Item {
|
|
|
12275
13488
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
12276
13489
|
},
|
|
12277
13490
|
});
|
|
12278
|
-
this.
|
|
12279
|
-
instance: proxiedInstance,
|
|
12280
|
-
refCount: 1,
|
|
12281
|
-
});
|
|
13491
|
+
this.registerItemInInstanceCache(proxiedInstance);
|
|
12282
13492
|
if (!waitForReady)
|
|
12283
13493
|
return proxiedInstance;
|
|
12284
13494
|
try {
|
|
12285
|
-
await
|
|
13495
|
+
await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
|
|
12286
13496
|
}
|
|
12287
13497
|
catch (err) {
|
|
12288
13498
|
try {
|
|
@@ -12305,14 +13515,10 @@ class Item {
|
|
|
12305
13515
|
if (!id) {
|
|
12306
13516
|
return null;
|
|
12307
13517
|
}
|
|
12308
|
-
|
|
12309
|
-
if (
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
instance,
|
|
12313
|
-
refCount: refCount + 1,
|
|
12314
|
-
});
|
|
12315
|
-
return instance;
|
|
13518
|
+
const entry = this.findItemInstanceCacheEntryById(id);
|
|
13519
|
+
if (entry) {
|
|
13520
|
+
entry.refCount += 1;
|
|
13521
|
+
return entry.instance;
|
|
12316
13522
|
}
|
|
12317
13523
|
return null;
|
|
12318
13524
|
}
|
|
@@ -12358,8 +13564,8 @@ class Item {
|
|
|
12358
13564
|
if (!seedLocalId && !seedUid) {
|
|
12359
13565
|
return undefined;
|
|
12360
13566
|
}
|
|
12361
|
-
//
|
|
12362
|
-
const id =
|
|
13567
|
+
// Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
|
|
13568
|
+
const id = seedLocalId || seedUid;
|
|
12363
13569
|
if (!id) {
|
|
12364
13570
|
return undefined;
|
|
12365
13571
|
}
|
|
@@ -12390,10 +13596,127 @@ class Item {
|
|
|
12390
13596
|
}));
|
|
12391
13597
|
}
|
|
12392
13598
|
if (waitForReady && itemInstances.length > 0) {
|
|
12393
|
-
await Promise.all(itemInstances.map((item) =>
|
|
13599
|
+
await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
|
|
12394
13600
|
}
|
|
12395
13601
|
return lodashEs.orderBy(itemInstances, ['createdAt'], ['desc']);
|
|
12396
13602
|
}
|
|
13603
|
+
/**
|
|
13604
|
+
* After EAS sync writes metadata for the latest version, merge new property instances and
|
|
13605
|
+
* re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
|
|
13606
|
+
* and useItems may not invalidate when the seed set is unchanged.
|
|
13607
|
+
*/
|
|
13608
|
+
static async rehydrateCachedItemsFromDbAfterEasSync() {
|
|
13609
|
+
const appDb = BaseDb.getAppDb();
|
|
13610
|
+
if (!appDb || Item.instanceCache.size === 0) {
|
|
13611
|
+
return;
|
|
13612
|
+
}
|
|
13613
|
+
const { metadata } = await Promise.resolve().then(function () { return schema$1; });
|
|
13614
|
+
const { eq, and } = await import('drizzle-orm');
|
|
13615
|
+
const dedupedInstances = new Map();
|
|
13616
|
+
for (const entry of Item.instanceCache.values()) {
|
|
13617
|
+
dedupedInstances.set(entry.instance, entry);
|
|
13618
|
+
}
|
|
13619
|
+
const entries = [...dedupedInstances.values()];
|
|
13620
|
+
await Promise.all(entries.map(async ({ instance }) => {
|
|
13621
|
+
try {
|
|
13622
|
+
const svc = instance.getService();
|
|
13623
|
+
if (svc.getSnapshot().status !== 'active') {
|
|
13624
|
+
return;
|
|
13625
|
+
}
|
|
13626
|
+
const ctx = svc.getSnapshot().context;
|
|
13627
|
+
const seedLocalId = ctx.seedLocalId;
|
|
13628
|
+
const seedUid = ctx.seedUid;
|
|
13629
|
+
const versionLocalId = ctx.latestVersionLocalId;
|
|
13630
|
+
const itemModelName = ctx.modelName;
|
|
13631
|
+
const schemaNameForModel = ctx.schemaName;
|
|
13632
|
+
if (!seedLocalId || !versionLocalId || !itemModelName) {
|
|
13633
|
+
return;
|
|
13634
|
+
}
|
|
13635
|
+
const metadataRows = await appDb
|
|
13636
|
+
.select()
|
|
13637
|
+
.from(metadata)
|
|
13638
|
+
.where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
|
|
13639
|
+
let propertySchemas = {};
|
|
13640
|
+
try {
|
|
13641
|
+
const M = getModel();
|
|
13642
|
+
const model = schemaNameForModel !== undefined
|
|
13643
|
+
? M?.getByName(itemModelName, schemaNameForModel)
|
|
13644
|
+
: M?.getByName(itemModelName);
|
|
13645
|
+
if (model?.properties?.length) {
|
|
13646
|
+
propertySchemas = modelPropertiesToObject(model.properties);
|
|
13647
|
+
}
|
|
13648
|
+
}
|
|
13649
|
+
catch {
|
|
13650
|
+
/* Model optional */
|
|
13651
|
+
}
|
|
13652
|
+
const sendToItemMachine = (event) => {
|
|
13653
|
+
if (svc.getSnapshot().status !== 'active') {
|
|
13654
|
+
return;
|
|
13655
|
+
}
|
|
13656
|
+
svc.send(event);
|
|
13657
|
+
};
|
|
13658
|
+
for (const metaRow of metadataRows) {
|
|
13659
|
+
try {
|
|
13660
|
+
let propertyName = metaRow.propertyName;
|
|
13661
|
+
const listSchemaKey = propertyName &&
|
|
13662
|
+
Object.keys(propertySchemas).length > 0 &&
|
|
13663
|
+
resolveStorageNameToSchemaName(propertySchemas, propertyName);
|
|
13664
|
+
if (listSchemaKey) {
|
|
13665
|
+
propertyName = listSchemaKey;
|
|
13666
|
+
}
|
|
13667
|
+
else {
|
|
13668
|
+
const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
|
|
13669
|
+
const refSeedType = metaRow.refSeedType;
|
|
13670
|
+
const isRefTypeFromMeta = refSeedType === 'file' ||
|
|
13671
|
+
refSeedType === 'image' ||
|
|
13672
|
+
refSeedType === 'relation' ||
|
|
13673
|
+
refSeedType === 'html';
|
|
13674
|
+
if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
|
|
13675
|
+
propertyName = baseName;
|
|
13676
|
+
}
|
|
13677
|
+
}
|
|
13678
|
+
if (!propertyName) {
|
|
13679
|
+
continue;
|
|
13680
|
+
}
|
|
13681
|
+
const property = await ItemProperty.find({
|
|
13682
|
+
propertyName,
|
|
13683
|
+
seedLocalId,
|
|
13684
|
+
seedUid,
|
|
13685
|
+
modelName: itemModelName,
|
|
13686
|
+
});
|
|
13687
|
+
if (property) {
|
|
13688
|
+
sendToItemMachine({
|
|
13689
|
+
type: 'addPropertyInstance',
|
|
13690
|
+
propertyName,
|
|
13691
|
+
propertyInstance: property,
|
|
13692
|
+
});
|
|
13693
|
+
}
|
|
13694
|
+
}
|
|
13695
|
+
catch {
|
|
13696
|
+
/* row skipped */
|
|
13697
|
+
}
|
|
13698
|
+
}
|
|
13699
|
+
const instances = svc.getSnapshot().context.propertyInstances;
|
|
13700
|
+
if (!instances) {
|
|
13701
|
+
return;
|
|
13702
|
+
}
|
|
13703
|
+
for (const propertyInstance of instances.values()) {
|
|
13704
|
+
try {
|
|
13705
|
+
const propertySnap = propertyInstance.getService().getSnapshot();
|
|
13706
|
+
if (xstate.isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
|
|
13707
|
+
propertyInstance.getService().send({ type: 'rehydrateFromDb' });
|
|
13708
|
+
}
|
|
13709
|
+
}
|
|
13710
|
+
catch {
|
|
13711
|
+
/* best-effort */
|
|
13712
|
+
}
|
|
13713
|
+
}
|
|
13714
|
+
}
|
|
13715
|
+
catch (e) {
|
|
13716
|
+
itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
|
|
13717
|
+
}
|
|
13718
|
+
}));
|
|
13719
|
+
}
|
|
12397
13720
|
_createPropertyInstance(props) {
|
|
12398
13721
|
if (this._storageTransactionId) {
|
|
12399
13722
|
props.storageTransactionId = this._storageTransactionId;
|
|
@@ -13008,15 +14331,10 @@ class Item {
|
|
|
13008
14331
|
}
|
|
13009
14332
|
unload() {
|
|
13010
14333
|
try {
|
|
13011
|
-
|
|
13012
|
-
const cacheKey = context.seedUid || context.seedLocalId;
|
|
13013
|
-
const cacheKeys = [];
|
|
13014
|
-
if (cacheKey) {
|
|
13015
|
-
cacheKeys.push(cacheKey);
|
|
13016
|
-
}
|
|
14334
|
+
Item.releaseItemInstanceCacheHold(this);
|
|
13017
14335
|
unloadEntity(this, {
|
|
13018
|
-
getCacheKeys: () =>
|
|
13019
|
-
caches: [
|
|
14336
|
+
getCacheKeys: () => [],
|
|
14337
|
+
caches: [],
|
|
13020
14338
|
instanceState: itemInstanceState,
|
|
13021
14339
|
getService: (instance) => instance._service,
|
|
13022
14340
|
onUnload: (instance) => {
|
|
@@ -13045,11 +14363,10 @@ class Item {
|
|
|
13045
14363
|
* Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
|
|
13046
14364
|
*/
|
|
13047
14365
|
async destroy() {
|
|
13048
|
-
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-
|
|
14366
|
+
const { assertItemOwned } = await Promise.resolve().then(function () { return require('./ownership-CXlKAj4o.js'); });
|
|
13049
14367
|
await assertItemOwned(this);
|
|
13050
14368
|
const context = this._getSnapshotContext();
|
|
13051
|
-
const
|
|
13052
|
-
const cacheKeys = cacheKey ? [cacheKey] : [];
|
|
14369
|
+
const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
|
|
13053
14370
|
clearDestroySubscriptions(this, {
|
|
13054
14371
|
instanceState: itemInstanceState,
|
|
13055
14372
|
onUnload: (instance) => instance._subscription?.unsubscribe(),
|
|
@@ -13106,600 +14423,331 @@ function normalizeAddressConfig(addresses) {
|
|
|
13106
14423
|
};
|
|
13107
14424
|
}
|
|
13108
14425
|
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
const
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
const
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
|
|
14426
|
+
let writeTail = Promise.resolve();
|
|
14427
|
+
function enqueueEasSyncDbWrite(fn) {
|
|
14428
|
+
const next = writeTail.then(fn);
|
|
14429
|
+
writeTail = next.catch(() => { });
|
|
14430
|
+
return next;
|
|
14431
|
+
}
|
|
14432
|
+
const MAX_ERROR_MESSAGE_LENGTH = 500;
|
|
14433
|
+
const MAX_ERROR_DETAILS_LENGTH = 2000;
|
|
14434
|
+
async function insertEasSyncProcessRow(params) {
|
|
14435
|
+
return enqueueEasSyncDbWrite(async () => {
|
|
14436
|
+
const db = BaseDb.getAppDb();
|
|
14437
|
+
if (!db) {
|
|
14438
|
+
throw new Error('[easSyncProcess] App DB not available');
|
|
14439
|
+
}
|
|
14440
|
+
const now = Date.now();
|
|
14441
|
+
const [row] = await db
|
|
14442
|
+
.insert(easSyncProcesses)
|
|
14443
|
+
.values({
|
|
14444
|
+
status: 'in_progress',
|
|
14445
|
+
startedAt: now,
|
|
14446
|
+
requestPayload: JSON.stringify(params.requestPayload),
|
|
14447
|
+
persistedSnapshot: JSON.stringify(params.persistedSnapshot),
|
|
14448
|
+
createdAt: now,
|
|
14449
|
+
updatedAt: now,
|
|
13128
14450
|
})
|
|
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);
|
|
14451
|
+
.returning({ id: easSyncProcesses.id });
|
|
14452
|
+
return row.id;
|
|
14453
|
+
});
|
|
14454
|
+
}
|
|
14455
|
+
async function finalizeEasSyncProcessRow(id, params) {
|
|
14456
|
+
return enqueueEasSyncDbWrite(async () => {
|
|
14457
|
+
const db = BaseDb.getAppDb();
|
|
14458
|
+
if (!db) {
|
|
14459
|
+
return;
|
|
13165
14460
|
}
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
14461
|
+
const now = Date.now();
|
|
14462
|
+
await db
|
|
14463
|
+
.update(easSyncProcesses)
|
|
14464
|
+
.set({
|
|
14465
|
+
status: params.status,
|
|
14466
|
+
completedAt: now,
|
|
14467
|
+
updatedAt: now,
|
|
14468
|
+
errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
|
|
14469
|
+
errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
|
|
14470
|
+
persistedSnapshot: JSON.stringify(params.persistedSnapshot),
|
|
14471
|
+
})
|
|
14472
|
+
.where(drizzleOrm.eq(easSyncProcesses.id, id));
|
|
14473
|
+
});
|
|
14474
|
+
}
|
|
13170
14475
|
|
|
13171
14476
|
/**
|
|
13172
|
-
*
|
|
14477
|
+
* Merge multiple EAS sync intents: full sync (no concrete address list) wins;
|
|
14478
|
+
* otherwise union addresses (first-seen casing).
|
|
13173
14479
|
*/
|
|
13174
|
-
|
|
13175
|
-
|
|
13176
|
-
|
|
14480
|
+
function mergeEasSyncRequestIntents(parts) {
|
|
14481
|
+
const norm = parts.filter((p) => p != null);
|
|
14482
|
+
if (norm.length === 0) {
|
|
14483
|
+
return {};
|
|
13177
14484
|
}
|
|
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
|
-
}
|
|
14485
|
+
let full = false;
|
|
14486
|
+
const addressMap = new Map();
|
|
14487
|
+
for (const p of norm) {
|
|
14488
|
+
if (!('addresses' in p) || p.addresses === undefined) {
|
|
14489
|
+
full = true;
|
|
14490
|
+
break;
|
|
14491
|
+
}
|
|
14492
|
+
for (const addr of p.addresses) {
|
|
14493
|
+
const k = addr.toLowerCase();
|
|
14494
|
+
if (!addressMap.has(k)) {
|
|
14495
|
+
addressMap.set(k, addr);
|
|
13215
14496
|
}
|
|
13216
14497
|
}
|
|
13217
14498
|
}
|
|
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);
|
|
14499
|
+
if (full) {
|
|
14500
|
+
return {};
|
|
13261
14501
|
}
|
|
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;
|
|
14502
|
+
if (addressMap.size === 0) {
|
|
14503
|
+
return { addresses: [] };
|
|
13321
14504
|
}
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
14505
|
+
return { addresses: [...addressMap.values()] };
|
|
14506
|
+
}
|
|
14507
|
+
|
|
14508
|
+
const log = debug('seedSdk:events:easSyncManager');
|
|
14509
|
+
function toRunSyncArg(options) {
|
|
14510
|
+
if (options &&
|
|
14511
|
+
'addresses' in options &&
|
|
14512
|
+
options.addresses !== undefined) {
|
|
14513
|
+
return options;
|
|
13326
14514
|
}
|
|
13327
|
-
|
|
14515
|
+
return undefined;
|
|
14516
|
+
}
|
|
14517
|
+
const runEasSync = xstate.fromPromise(async ({ input, }) => {
|
|
14518
|
+
const rowId = await insertEasSyncProcessRow({
|
|
14519
|
+
requestPayload: input.requestPayload,
|
|
14520
|
+
persistedSnapshot: input.runningSnapshot,
|
|
14521
|
+
});
|
|
14522
|
+
const { runSyncFromEas } = await Promise.resolve().then(function () { return require('./syncDbWithEas-DcKL-_Pb.js'); });
|
|
13328
14523
|
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(),
|
|
14524
|
+
await runSyncFromEas(toRunSyncArg(input.options));
|
|
14525
|
+
await finalizeEasSyncProcessRow(rowId, {
|
|
14526
|
+
status: 'completed',
|
|
14527
|
+
persistedSnapshot: {
|
|
14528
|
+
phase: 'completed',
|
|
14529
|
+
correlationIds: input.requestPayload.correlationIds,
|
|
14530
|
+
},
|
|
13384
14531
|
});
|
|
13385
14532
|
}
|
|
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,
|
|
14533
|
+
catch (err) {
|
|
14534
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14535
|
+
const details = err instanceof Error && err.stack
|
|
14536
|
+
? err.stack.slice(0, 2000)
|
|
14537
|
+
: undefined;
|
|
14538
|
+
await finalizeEasSyncProcessRow(rowId, {
|
|
14539
|
+
status: 'failed',
|
|
14540
|
+
errorMessage: message,
|
|
14541
|
+
errorDetails: details,
|
|
14542
|
+
persistedSnapshot: {
|
|
14543
|
+
phase: 'failed',
|
|
14544
|
+
correlationIds: input.requestPayload.correlationIds,
|
|
14545
|
+
},
|
|
13461
14546
|
});
|
|
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 };
|
|
14547
|
+
throw err;
|
|
14548
|
+
}
|
|
14549
|
+
});
|
|
14550
|
+
const initialContext = {
|
|
14551
|
+
runOptions: {},
|
|
14552
|
+
activeCorrelationIds: [],
|
|
14553
|
+
activePrimarySource: 'event_bus',
|
|
14554
|
+
pendingMergedOptions: undefined,
|
|
14555
|
+
pendingCorrelationIds: [],
|
|
14556
|
+
pendingPrimarySource: null,
|
|
14557
|
+
lastFinishedCorrelationIds: null,
|
|
14558
|
+
lastFinishedStatus: null,
|
|
14559
|
+
lastFinishedError: null,
|
|
13553
14560
|
};
|
|
13554
|
-
const
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
14561
|
+
const easSyncMachine = xstate.setup({
|
|
14562
|
+
types: {
|
|
14563
|
+
context: {},
|
|
14564
|
+
events: {},
|
|
14565
|
+
},
|
|
14566
|
+
actors: {
|
|
14567
|
+
runEasSync,
|
|
14568
|
+
},
|
|
14569
|
+
}).createMachine({
|
|
14570
|
+
id: MachineIds.EAS_SYNC_MANAGER,
|
|
14571
|
+
initial: 'idle',
|
|
14572
|
+
context: initialContext,
|
|
14573
|
+
states: {
|
|
14574
|
+
idle: {
|
|
14575
|
+
on: {
|
|
14576
|
+
REQUEST: {
|
|
14577
|
+
target: 'running',
|
|
14578
|
+
actions: xstate.assign({
|
|
14579
|
+
runOptions: ({ event }) => event.options === undefined
|
|
14580
|
+
? {}
|
|
14581
|
+
: mergeEasSyncRequestIntents([event.options]),
|
|
14582
|
+
activeCorrelationIds: ({ event }) => [event.correlationId],
|
|
14583
|
+
activePrimarySource: ({ event }) => event.source,
|
|
14584
|
+
}),
|
|
14585
|
+
},
|
|
14586
|
+
},
|
|
14587
|
+
},
|
|
14588
|
+
running: {
|
|
14589
|
+
on: {
|
|
14590
|
+
REQUEST: {
|
|
14591
|
+
actions: xstate.assign({
|
|
14592
|
+
pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
|
|
14593
|
+
context.runOptions,
|
|
14594
|
+
context.pendingMergedOptions,
|
|
14595
|
+
event.options === undefined ? {} : event.options,
|
|
14596
|
+
].filter((x) => x != null)),
|
|
14597
|
+
pendingCorrelationIds: ({ context, event }) => [
|
|
14598
|
+
...context.pendingCorrelationIds,
|
|
14599
|
+
event.correlationId,
|
|
14600
|
+
],
|
|
14601
|
+
pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
|
|
14602
|
+
}),
|
|
14603
|
+
},
|
|
13561
14604
|
},
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
14605
|
+
invoke: {
|
|
14606
|
+
src: 'runEasSync',
|
|
14607
|
+
input: ({ context }) => ({
|
|
14608
|
+
options: context.runOptions,
|
|
14609
|
+
requestPayload: {
|
|
14610
|
+
source: context.activePrimarySource,
|
|
14611
|
+
correlationIds: context.activeCorrelationIds,
|
|
14612
|
+
options: context.runOptions,
|
|
14613
|
+
},
|
|
14614
|
+
runningSnapshot: {
|
|
14615
|
+
phase: 'running',
|
|
14616
|
+
correlationIds: context.activeCorrelationIds,
|
|
14617
|
+
},
|
|
14618
|
+
}),
|
|
14619
|
+
onDone: {
|
|
14620
|
+
target: 'afterRun',
|
|
14621
|
+
actions: xstate.assign({
|
|
14622
|
+
lastFinishedCorrelationIds: ({ context }) => [
|
|
14623
|
+
...context.activeCorrelationIds,
|
|
14624
|
+
],
|
|
14625
|
+
lastFinishedStatus: () => 'success',
|
|
14626
|
+
lastFinishedError: () => null,
|
|
14627
|
+
activeCorrelationIds: () => [],
|
|
14628
|
+
runOptions: () => ({}),
|
|
14629
|
+
}),
|
|
14630
|
+
},
|
|
14631
|
+
onError: {
|
|
14632
|
+
target: 'afterRun',
|
|
14633
|
+
actions: [
|
|
14634
|
+
xstate.assign({
|
|
14635
|
+
lastFinishedCorrelationIds: ({ context }) => [
|
|
14636
|
+
...context.activeCorrelationIds,
|
|
14637
|
+
],
|
|
14638
|
+
lastFinishedStatus: () => 'failed',
|
|
14639
|
+
lastFinishedError: ({ event }) => {
|
|
14640
|
+
const e = event.error;
|
|
14641
|
+
if (e instanceof Error) {
|
|
14642
|
+
return e.message;
|
|
14643
|
+
}
|
|
14644
|
+
return e != null ? String(e) : 'EAS sync failed';
|
|
14645
|
+
},
|
|
14646
|
+
activeCorrelationIds: () => [],
|
|
14647
|
+
runOptions: () => ({}),
|
|
14648
|
+
}),
|
|
14649
|
+
({ event }) => {
|
|
14650
|
+
log('runEasSync error', event.error);
|
|
14651
|
+
},
|
|
14652
|
+
],
|
|
14653
|
+
},
|
|
13569
14654
|
},
|
|
13570
14655
|
},
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
14656
|
+
afterRun: {
|
|
14657
|
+
always: [
|
|
14658
|
+
{
|
|
14659
|
+
guard: ({ context }) => context.pendingCorrelationIds.length > 0,
|
|
14660
|
+
target: 'running',
|
|
14661
|
+
actions: xstate.assign({
|
|
14662
|
+
runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
|
|
14663
|
+
activeCorrelationIds: ({ context }) => [
|
|
14664
|
+
...context.pendingCorrelationIds,
|
|
14665
|
+
],
|
|
14666
|
+
activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
|
|
14667
|
+
pendingMergedOptions: () => undefined,
|
|
14668
|
+
pendingCorrelationIds: () => [],
|
|
14669
|
+
pendingPrimarySource: () => null,
|
|
14670
|
+
}),
|
|
14671
|
+
},
|
|
14672
|
+
{ target: 'idle' },
|
|
14673
|
+
],
|
|
13579
14674
|
},
|
|
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) {
|
|
14675
|
+
},
|
|
14676
|
+
});
|
|
14677
|
+
const easSyncActor = xstate.createActor(easSyncMachine);
|
|
14678
|
+
let easSyncActorStarted = false;
|
|
14679
|
+
function startEasSyncActor() {
|
|
14680
|
+
if (easSyncActorStarted) {
|
|
13607
14681
|
return;
|
|
13608
14682
|
}
|
|
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;
|
|
14683
|
+
easSyncActorStarted = true;
|
|
14684
|
+
easSyncActor.start();
|
|
14685
|
+
}
|
|
14686
|
+
function newCorrelationId() {
|
|
14687
|
+
const c = globalThis.crypto;
|
|
14688
|
+
if (c?.randomUUID) {
|
|
14689
|
+
return c.randomUUID();
|
|
13645
14690
|
}
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
const itemVersions = await getItemVersionsFromEas({
|
|
13655
|
-
seedUids,
|
|
13656
|
-
excludeRevoked: false,
|
|
14691
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
14692
|
+
}
|
|
14693
|
+
function requestEasSyncFromEventBus() {
|
|
14694
|
+
startEasSyncActor();
|
|
14695
|
+
easSyncActor.send({
|
|
14696
|
+
type: 'REQUEST',
|
|
14697
|
+
correlationId: newCorrelationId(),
|
|
14698
|
+
source: 'event_bus',
|
|
13657
14699
|
});
|
|
13658
|
-
|
|
13659
|
-
|
|
14700
|
+
}
|
|
14701
|
+
function requestEasSyncFromAddressChange(addresses) {
|
|
14702
|
+
startEasSyncActor();
|
|
14703
|
+
easSyncActor.send({
|
|
14704
|
+
type: 'REQUEST',
|
|
14705
|
+
correlationId: newCorrelationId(),
|
|
14706
|
+
options: { addresses },
|
|
14707
|
+
source: 'address_change',
|
|
13660
14708
|
});
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
14709
|
+
}
|
|
14710
|
+
function requestEasSyncFromModelsInit() {
|
|
14711
|
+
startEasSyncActor();
|
|
14712
|
+
easSyncActor.send({
|
|
14713
|
+
type: 'REQUEST',
|
|
14714
|
+
correlationId: newCorrelationId(),
|
|
14715
|
+
source: 'models_init',
|
|
13664
14716
|
});
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
14717
|
+
}
|
|
14718
|
+
function sendEasSyncClientRequest(correlationId, options) {
|
|
14719
|
+
startEasSyncActor();
|
|
14720
|
+
easSyncActor.send({
|
|
14721
|
+
type: 'REQUEST',
|
|
14722
|
+
correlationId,
|
|
14723
|
+
options,
|
|
14724
|
+
source: 'client_api',
|
|
13669
14725
|
});
|
|
13670
|
-
|
|
13671
|
-
};
|
|
13672
|
-
const syncDbWithEasHandler = lodashEs.throttle(async (_) => {
|
|
13673
|
-
await runSyncFromEas();
|
|
13674
|
-
}, 30000, {
|
|
13675
|
-
leading: true,
|
|
13676
|
-
trailing: false,
|
|
13677
|
-
});
|
|
14726
|
+
}
|
|
13678
14727
|
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
};
|
|
14728
|
+
var easSyncManager = /*#__PURE__*/Object.freeze({
|
|
14729
|
+
__proto__: null,
|
|
14730
|
+
easSyncActor: easSyncActor,
|
|
14731
|
+
easSyncMachine: easSyncMachine,
|
|
14732
|
+
requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
|
|
14733
|
+
requestEasSyncFromEventBus: requestEasSyncFromEventBus,
|
|
14734
|
+
requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
|
|
14735
|
+
sendEasSyncClientRequest: sendEasSyncClientRequest,
|
|
14736
|
+
startEasSyncActor: startEasSyncActor
|
|
14737
|
+
});
|
|
13690
14738
|
|
|
13691
14739
|
/**
|
|
13692
14740
|
* @deprecated Use BaseArweaveClient.setHost() instead.
|
|
13693
14741
|
* This function is kept for backward compatibility but will be removed in a future version.
|
|
13694
14742
|
*/
|
|
13695
14743
|
const setArweaveDomain = (newDomain) => {
|
|
13696
|
-
BaseArweaveClient.
|
|
14744
|
+
BaseArweaveClient.setPreferredReadGateway(newDomain);
|
|
13697
14745
|
};
|
|
13698
14746
|
|
|
13699
|
-
const logger$
|
|
14747
|
+
const logger$g = debug('seedSdk:services:events');
|
|
13700
14748
|
const handleServiceSaveState = (event) => {
|
|
13701
14749
|
const { state, serviceId } = event;
|
|
13702
|
-
logger$
|
|
14750
|
+
logger$g(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
|
|
13703
14751
|
// TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
|
|
13704
14752
|
// localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
|
|
13705
14753
|
};
|
|
@@ -13708,7 +14756,8 @@ const setupServicesEventHandlers = () => {
|
|
|
13708
14756
|
};
|
|
13709
14757
|
|
|
13710
14758
|
const setupAllItemsEventHandlers = () => {
|
|
13711
|
-
|
|
14759
|
+
startEasSyncActor();
|
|
14760
|
+
eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
|
|
13712
14761
|
};
|
|
13713
14762
|
// Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
|
|
13714
14763
|
|
|
@@ -13742,9 +14791,9 @@ class BasePathResolver {
|
|
|
13742
14791
|
}
|
|
13743
14792
|
}
|
|
13744
14793
|
|
|
13745
|
-
const logger$
|
|
14794
|
+
const logger$f = debug('seedSdk:ClientManager:initialize');
|
|
13746
14795
|
const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, event } }) => {
|
|
13747
|
-
logger$
|
|
14796
|
+
logger$f('initialize from ClientManager');
|
|
13748
14797
|
const { isInitialized } = context;
|
|
13749
14798
|
if (!event || !('options' in event)) {
|
|
13750
14799
|
throw new Error('Initialize event must include options');
|
|
@@ -13867,11 +14916,14 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
|
|
|
13867
14916
|
dbConfig,
|
|
13868
14917
|
schemaFile,
|
|
13869
14918
|
schema,
|
|
13870
|
-
syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ??
|
|
14919
|
+
syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
|
|
13871
14920
|
} });
|
|
13872
14921
|
if (arweaveDomain) {
|
|
13873
14922
|
setArweaveDomain(arweaveDomain);
|
|
13874
14923
|
}
|
|
14924
|
+
void ensureReadGatewaySelected().catch(() => {
|
|
14925
|
+
/* non-blocking warm-up for read gateway probe */
|
|
14926
|
+
});
|
|
13875
14927
|
// Models are now Model instances, no registration needed
|
|
13876
14928
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
13877
14929
|
setupAllItemsEventHandlers();
|
|
@@ -13907,15 +14959,15 @@ const platformClassesInit = xstate.fromCallback(({ sendBack, input: { context, e
|
|
|
13907
14959
|
};
|
|
13908
14960
|
});
|
|
13909
14961
|
|
|
13910
|
-
const logger$
|
|
13911
|
-
const saveAppState
|
|
14962
|
+
const logger$e = debug('seedSdk:client:writeToDb');
|
|
14963
|
+
const saveAppState = xstate.fromCallback(({ sendBack, input: { key, value } }) => {
|
|
13912
14964
|
const _saveAppState = async () => {
|
|
13913
14965
|
try {
|
|
13914
14966
|
const appDb = BaseDb.getAppDb();
|
|
13915
14967
|
if (!appDb) {
|
|
13916
14968
|
// In test environments, continue anyway
|
|
13917
14969
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13918
|
-
logger$
|
|
14970
|
+
logger$e('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
|
|
13919
14971
|
return;
|
|
13920
14972
|
}
|
|
13921
14973
|
throw new Error('App DB not found');
|
|
@@ -13931,13 +14983,13 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
|
|
|
13931
14983
|
value: JSON.stringify(value),
|
|
13932
14984
|
},
|
|
13933
14985
|
});
|
|
13934
|
-
logger$
|
|
14986
|
+
logger$e('result', result);
|
|
13935
14987
|
}
|
|
13936
14988
|
catch (error) {
|
|
13937
|
-
logger$
|
|
14989
|
+
logger$e('[client/actors] [saveAppState] Error saving app state:', error);
|
|
13938
14990
|
// In test environments, continue anyway
|
|
13939
14991
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13940
|
-
logger$
|
|
14992
|
+
logger$e('[client/actors] [saveAppState] Continuing despite error in test environment');
|
|
13941
14993
|
return;
|
|
13942
14994
|
}
|
|
13943
14995
|
throw error;
|
|
@@ -13952,10 +15004,10 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
|
|
|
13952
15004
|
});
|
|
13953
15005
|
})
|
|
13954
15006
|
.catch((error) => {
|
|
13955
|
-
logger$
|
|
15007
|
+
logger$e('[client/actors] [saveAppState] Error in promise chain:', error);
|
|
13956
15008
|
// In test environments, still send success to allow state machine to progress
|
|
13957
15009
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13958
|
-
logger$
|
|
15010
|
+
logger$e('[client/actors] [saveAppState] Sending success despite error in test environment');
|
|
13959
15011
|
sendBack({
|
|
13960
15012
|
type: 'saveAppStateSuccess',
|
|
13961
15013
|
key,
|
|
@@ -13968,222 +15020,6 @@ const saveAppState$1 = xstate.fromCallback(({ sendBack, input: { key, value } })
|
|
|
13968
15020
|
});
|
|
13969
15021
|
});
|
|
13970
15022
|
|
|
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
15023
|
let isInitialized = false;
|
|
14188
15024
|
const fsInitHandler = async () => {
|
|
14189
15025
|
if (isInitialized) {
|
|
@@ -14349,7 +15185,7 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
14349
15185
|
}
|
|
14350
15186
|
const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
|
|
14351
15187
|
// Fetch schemas from EAS in background - do not block init. EAS can be slow (10s+);
|
|
14352
|
-
// modelUids will be populated async and
|
|
15188
|
+
// modelUids will be populated async and EAS sync orchestrator runs when done.
|
|
14353
15189
|
const fetchEasAndPopulateModelUids = async () => {
|
|
14354
15190
|
try {
|
|
14355
15191
|
const queryClient = BaseQueryClient.getQueryClient();
|
|
@@ -14382,7 +15218,8 @@ const addModelsToDb = xstate.fromCallback(({ sendBack, input: { context } }) =>
|
|
|
14382
15218
|
}
|
|
14383
15219
|
}
|
|
14384
15220
|
}
|
|
14385
|
-
|
|
15221
|
+
const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
|
|
15222
|
+
requestEasSyncFromModelsInit();
|
|
14386
15223
|
}
|
|
14387
15224
|
else {
|
|
14388
15225
|
logger$b('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
|
|
@@ -16724,16 +17561,19 @@ function addressesFromPersistedAddressValue(value) {
|
|
|
16724
17561
|
return out;
|
|
16725
17562
|
}
|
|
16726
17563
|
function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
|
|
17564
|
+
const merged = addressesFromPersistedAddressValue(event.value);
|
|
16727
17565
|
if (!context.syncFromEasOnAddressChange)
|
|
16728
17566
|
return;
|
|
16729
17567
|
if (event.key !== "addresses")
|
|
16730
17568
|
return;
|
|
16731
|
-
const merged = addressesFromPersistedAddressValue(event.value);
|
|
16732
17569
|
if (merged.length === 0)
|
|
16733
17570
|
return;
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
}
|
|
17571
|
+
try {
|
|
17572
|
+
requestEasSyncFromAddressChange(merged);
|
|
17573
|
+
}
|
|
17574
|
+
catch (err) {
|
|
17575
|
+
logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
|
|
17576
|
+
}
|
|
16737
17577
|
}
|
|
16738
17578
|
function emitAddressesPersistedIfAddressesKey(event) {
|
|
16739
17579
|
if (event.key !== "addresses")
|
|
@@ -16751,7 +17591,7 @@ const clientManagerMachine = xstate.setup({
|
|
|
16751
17591
|
fileSystemInit,
|
|
16752
17592
|
dbInit,
|
|
16753
17593
|
saveConfig,
|
|
16754
|
-
saveAppState
|
|
17594
|
+
saveAppState,
|
|
16755
17595
|
addModelsToStore,
|
|
16756
17596
|
addModelsToDb,
|
|
16757
17597
|
processSchemaFiles,
|
|
@@ -17075,7 +17915,16 @@ const clientInstance = {
|
|
|
17075
17915
|
*/
|
|
17076
17916
|
syncFromEas: async (options) => {
|
|
17077
17917
|
ensureInitialized();
|
|
17078
|
-
|
|
17918
|
+
startEasSyncActor();
|
|
17919
|
+
const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
|
|
17920
|
+
? globalThis.crypto.randomUUID()
|
|
17921
|
+
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
17922
|
+
sendEasSyncClientRequest(correlationId, options);
|
|
17923
|
+
await xstate.waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
|
|
17924
|
+
const snap = easSyncActor.getSnapshot();
|
|
17925
|
+
if (snap.context.lastFinishedStatus === 'failed') {
|
|
17926
|
+
throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
|
|
17927
|
+
}
|
|
17079
17928
|
},
|
|
17080
17929
|
addModel: async (modelDef) => {
|
|
17081
17930
|
const db = await BaseDb.getAppDb();
|
|
@@ -17285,7 +18134,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
|
|
|
17285
18134
|
// Lazy import cache for ModelProperty to avoid circular dependency
|
|
17286
18135
|
// Eagerly start loading to minimize delay on first access
|
|
17287
18136
|
let ModelPropertyClass = null;
|
|
17288
|
-
const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-
|
|
18137
|
+
const modelPropertyImportPromise = Promise.resolve().then(function () { return require('./ModelProperty-tfM38NL4.js'); })
|
|
17289
18138
|
.then(module => {
|
|
17290
18139
|
ModelPropertyClass = module.ModelProperty;
|
|
17291
18140
|
return ModelPropertyClass;
|
|
@@ -17302,7 +18151,7 @@ function getModelProperty() {
|
|
|
17302
18151
|
}
|
|
17303
18152
|
// Lazy import cache for Schema to avoid circular dependency
|
|
17304
18153
|
let SchemaClass = null;
|
|
17305
|
-
const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-
|
|
18154
|
+
const schemaImportPromise = Promise.resolve().then(function () { return require('./Schema-44NqLqMV.js'); })
|
|
17306
18155
|
.then(module => {
|
|
17307
18156
|
SchemaClass = module.Schema;
|
|
17308
18157
|
return SchemaClass;
|
|
@@ -19256,7 +20105,7 @@ class Db extends BaseDb {
|
|
|
19256
20105
|
// You can inspect what will happen before applying
|
|
19257
20106
|
await apply();
|
|
19258
20107
|
this.db = db;
|
|
19259
|
-
const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-
|
|
20108
|
+
const { backfillMetadataPropertyIds } = await Promise.resolve().then(function () { return require('./backfillMetadataPropertyIds-D1nLJAhB.js'); });
|
|
19260
20109
|
await backfillMetadataPropertyIds();
|
|
19261
20110
|
return this.db;
|
|
19262
20111
|
}
|
|
@@ -19903,7 +20752,7 @@ const getTsImport = async (filePath) => {
|
|
|
19903
20752
|
|
|
19904
20753
|
// Get the directory of this file to resolve relative paths
|
|
19905
20754
|
// @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-
|
|
20755
|
+
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-C6rrqy3z.js', document.baseURI).href)));
|
|
19907
20756
|
path.dirname(__filename$1);
|
|
19908
20757
|
const commandExists = (command) => {
|
|
19909
20758
|
try {
|
|
@@ -20151,6 +21000,7 @@ QueryClient.getQueryClient = () => {
|
|
|
20151
21000
|
reject(new Error('Not implemented'));
|
|
20152
21001
|
});
|
|
20153
21002
|
},
|
|
21003
|
+
removeQueries: async () => { },
|
|
20154
21004
|
};
|
|
20155
21005
|
};
|
|
20156
21006
|
BaseQueryClient.setPlatformClass(QueryClient);
|
|
@@ -20365,23 +21215,30 @@ immer.enableMapSet();
|
|
|
20365
21215
|
|
|
20366
21216
|
exports.BaseArweaveClient = BaseArweaveClient;
|
|
20367
21217
|
exports.BaseDb = BaseDb;
|
|
21218
|
+
exports.BaseEasClient = BaseEasClient;
|
|
20368
21219
|
exports.BaseFileManager = BaseFileManager;
|
|
20369
21220
|
exports.BaseFileManager$1 = BaseFileManager$1;
|
|
20370
21221
|
exports.BasePathResolver = BasePathResolver;
|
|
21222
|
+
exports.BaseQueryClient = BaseQueryClient;
|
|
20371
21223
|
exports.Boolean = Boolean$1;
|
|
20372
21224
|
exports.ClientManager = ClientManager;
|
|
20373
21225
|
exports.ConflictError = ConflictError;
|
|
20374
21226
|
exports.DEFAULT_TEXT_MAX_LENGTH = DEFAULT_TEXT_MAX_LENGTH;
|
|
20375
21227
|
exports.Date = Date$1;
|
|
20376
21228
|
exports.Db = Db;
|
|
21229
|
+
exports.EAS_SEED_DATA_SYNCED_TO_DB_EVENT = EAS_SEED_DATA_SYNCED_TO_DB_EVENT;
|
|
20377
21230
|
exports.File = File$1;
|
|
20378
21231
|
exports.FileManager = FileManager;
|
|
21232
|
+
exports.GET_PROPERTIES = GET_PROPERTIES;
|
|
21233
|
+
exports.GET_SEEDS = GET_SEEDS;
|
|
21234
|
+
exports.GET_VERSIONS = GET_VERSIONS;
|
|
20379
21235
|
exports.Html = Html;
|
|
20380
21236
|
exports.INIT_SCRIPT_SUCCESS_MESSAGE = INIT_SCRIPT_SUCCESS_MESSAGE;
|
|
20381
21237
|
exports.INTERNAL_DATA_TYPES = INTERNAL_DATA_TYPES;
|
|
20382
21238
|
exports.INTERNAL_PROPERTY_NAMES = INTERNAL_PROPERTY_NAMES;
|
|
20383
21239
|
exports.Image = Image;
|
|
20384
21240
|
exports.Item = Item;
|
|
21241
|
+
exports.Item$1 = Item$1;
|
|
20385
21242
|
exports.ItemProperty = ItemProperty;
|
|
20386
21243
|
exports.Json = Json;
|
|
20387
21244
|
exports.List = List;
|
|
@@ -20422,12 +21279,14 @@ exports.createReactiveProxy = createReactiveProxy;
|
|
|
20422
21279
|
exports.db = db;
|
|
20423
21280
|
exports.defaultAttestationData = defaultAttestationData;
|
|
20424
21281
|
exports.eas = eas;
|
|
21282
|
+
exports.escapeSqliteString = escapeSqliteString;
|
|
20425
21283
|
exports.eventEmitter = eventEmitter;
|
|
20426
21284
|
exports.findEntity = findEntity;
|
|
20427
21285
|
exports.findSeedBinary = findSeedBinary;
|
|
20428
21286
|
exports.forceRemoveFromCaches = forceRemoveFromCaches;
|
|
20429
21287
|
exports.generateId = generateId;
|
|
20430
21288
|
exports.generateModelCode = generateModelCode;
|
|
21289
|
+
exports.getAllAddressesFromDb = getAllAddressesFromDb;
|
|
20431
21290
|
exports.getClient = getClient;
|
|
20432
21291
|
exports.getContentHash = getContentHash;
|
|
20433
21292
|
exports.getCorrectId = getCorrectId;
|
|
@@ -20436,14 +21295,18 @@ exports.getEasSchemaUidForModel = getEasSchemaUidForModel;
|
|
|
20436
21295
|
exports.getEasSchemaUidForSchemaDefinition = getEasSchemaUidForSchemaDefinition;
|
|
20437
21296
|
exports.getGetAdditionalSyncAddresses = getGetAdditionalSyncAddresses;
|
|
20438
21297
|
exports.getItemData = getItemData;
|
|
21298
|
+
exports.getItemPropertiesFromEas = getItemPropertiesFromEas;
|
|
21299
|
+
exports.getItemVersionsFromEas = getItemVersionsFromEas;
|
|
20439
21300
|
exports.getLatestPublishedVersionRow = getLatestPublishedVersionRow;
|
|
20440
21301
|
exports.getLatestSchemaVersion = getLatestSchemaVersion;
|
|
20441
21302
|
exports.getModelId = getModelId;
|
|
20442
21303
|
exports.getModelIdByFileId = getModelIdByFileId;
|
|
21304
|
+
exports.getModelSchemasFromEas = getModelSchemasFromEas;
|
|
20443
21305
|
exports.getOwnedAddressesFromDb = getOwnedAddressesFromDb;
|
|
20444
21306
|
exports.getPropertyData = getPropertyData$1;
|
|
20445
21307
|
exports.getPropertyIdForModelAndName = getPropertyIdForModelAndName;
|
|
20446
21308
|
exports.getRefValueType = getRefValueType;
|
|
21309
|
+
exports.getSeedsFromSchemaUids = getSeedsFromSchemaUids;
|
|
20447
21310
|
exports.getTsImport = getTsImport;
|
|
20448
21311
|
exports.htmlEmbeddedImageCoPublish = htmlEmbeddedImageCoPublish;
|
|
20449
21312
|
exports.importJsonSchema = importJsonSchema;
|
|
@@ -20460,8 +21323,10 @@ exports.modelUids = modelUids;
|
|
|
20460
21323
|
exports.models = models$1;
|
|
20461
21324
|
exports.normalizeDataType = normalizeDataType;
|
|
20462
21325
|
exports.normalizeRelationPropertyValue = normalizeRelationPropertyValue;
|
|
21326
|
+
exports.parseEasRelationPropertyName = parseEasRelationPropertyName;
|
|
20463
21327
|
exports.parseListPropertyValueFromStorage = parseListPropertyValueFromStorage;
|
|
20464
21328
|
exports.parseMarkdownFrontmatter = parseMarkdownFrontmatter;
|
|
21329
|
+
exports.pickLatestPropertyAttestationsByRefAndSchema = pickLatestPropertyAttestationsByRefAndSchema;
|
|
20465
21330
|
exports.processSeedConfig = processSeedConfig;
|
|
20466
21331
|
exports.properties = properties;
|
|
20467
21332
|
exports.readJsonImportFile = readJsonImportFile;
|
|
@@ -20470,10 +21335,12 @@ exports.resolveStorageNameToSchemaName = resolveStorageNameToSchemaName;
|
|
|
20470
21335
|
exports.runDestroyLifecycle = runDestroyLifecycle;
|
|
20471
21336
|
exports.runSeedInit = runSeedInit;
|
|
20472
21337
|
exports.saveModelsFromMarkdown = saveModelsFromMarkdown;
|
|
21338
|
+
exports.scheduleBulkFilesDownloadFromEasSync = scheduleBulkFilesDownloadFromEasSync;
|
|
20473
21339
|
exports.schema = schema$1;
|
|
20474
21340
|
exports.schema$1 = schema;
|
|
20475
21341
|
exports.schemas = schemas;
|
|
20476
21342
|
exports.seeds = seeds;
|
|
21343
|
+
exports.setSchemaUidForSchemaDefinition = setSchemaUidForSchemaDefinition;
|
|
20477
21344
|
exports.setupEntityLiveQuery = setupEntityLiveQuery;
|
|
20478
21345
|
exports.syncSchemaFromSource = syncSchemaFromSource;
|
|
20479
21346
|
exports.toSnakeCase = toSnakeCase;
|
|
@@ -20483,4 +21350,4 @@ exports.versions = versions;
|
|
|
20483
21350
|
exports.waitForEntityIdle = waitForEntityIdle;
|
|
20484
21351
|
exports.withSeed = withSeed;
|
|
20485
21352
|
exports.writeProcessMachine = writeProcessMachine;
|
|
20486
|
-
//# sourceMappingURL=index-
|
|
21353
|
+
//# sourceMappingURL=index-C6rrqy3z.js.map
|