@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { waitFor, fromCallback, fromPromise, setup, assign, createActor } from 'xstate';
|
|
1
|
+
import { waitFor, fromCallback, fromPromise, setup, assign, stateIn, createActor, isMachineSnapshot } from 'xstate';
|
|
2
2
|
import { sqliteTable, integer, text, unique, int, blob, uniqueIndex } from 'drizzle-orm/sqlite-core';
|
|
3
3
|
import { relations, and, eq, isNull, isNotNull, not, or, max, count, getTableColumns, sql, desc, inArray, gt } from 'drizzle-orm';
|
|
4
4
|
import { customAlphabet } from 'nanoid';
|
|
@@ -8,7 +8,7 @@ import { ZeroAddress, getAddress } from 'ethers';
|
|
|
8
8
|
import pluralize from 'pluralize';
|
|
9
9
|
import { Type } from '@sinclair/typebox';
|
|
10
10
|
import { toSnakeCase as toSnakeCase$1 } from 'drizzle-orm/casing';
|
|
11
|
-
import { upperFirst, camelCase, startCase,
|
|
11
|
+
import { upperFirst, camelCase, startCase, throttle, orderBy } from 'lodash-es';
|
|
12
12
|
import { BehaviorSubject } from 'rxjs';
|
|
13
13
|
import EventEmitter from 'eventemitter3';
|
|
14
14
|
import 'arweave';
|
|
@@ -157,6 +157,13 @@ class BaseFileManager {
|
|
|
157
157
|
static downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions, }) {
|
|
158
158
|
return this.PlatformClass.downloadAllFiles({ transactionIds, arweaveHost, excludedTransactions });
|
|
159
159
|
}
|
|
160
|
+
static downloadFileByTransactionId({ transactionId, arweaveHost, excludedTransactions, }) {
|
|
161
|
+
return this.PlatformClass.downloadAllFiles({
|
|
162
|
+
transactionIds: [transactionId],
|
|
163
|
+
arweaveHost,
|
|
164
|
+
excludedTransactions,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
160
167
|
static resizeImage({ filePath, width, height }) {
|
|
161
168
|
return this.PlatformClass.resizeImage({ filePath, width, height });
|
|
162
169
|
}
|
|
@@ -365,12 +372,71 @@ var SeedModels;
|
|
|
365
372
|
// Internal SDK schema that should not be created in app's files directory
|
|
366
373
|
const SEED_PROTOCOL_SCHEMA_NAME = 'Seed Protocol';
|
|
367
374
|
const INTERNAL_SCHEMA_IDS = ['SEEDPROTOCOL'];
|
|
368
|
-
/** Default Arweave gateway host used across all packages */
|
|
369
|
-
const DEFAULT_ARWEAVE_HOST = '
|
|
375
|
+
/** Default Arweave gateway host used across all packages (first in {@link DEFAULT_ARWEAVE_GATEWAYS}) */
|
|
376
|
+
const DEFAULT_ARWEAVE_HOST = 'ar.seedprotocol.io';
|
|
370
377
|
/** Default Arweave gateway GraphQL endpoint (transaction / block queries). */
|
|
371
|
-
const DEFAULT_ARWEAVE_GRAPHQL_URL =
|
|
372
|
-
/**
|
|
373
|
-
|
|
378
|
+
const DEFAULT_ARWEAVE_GRAPHQL_URL = `https://${DEFAULT_ARWEAVE_HOST}/graphql`;
|
|
379
|
+
/**
|
|
380
|
+
* Default Arweave gateways for read fallback / metadata fetching (ordered by preference).
|
|
381
|
+
* Override order with `ARWEAVE_READ_GATEWAYS` or `NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS` (comma-separated hosts).
|
|
382
|
+
*/
|
|
383
|
+
const DEFAULT_ARWEAVE_GATEWAYS = ['ar.seedprotocol.io', 'arweave.net', 'arweave.dev', 'g8way.io', 'permagate.io', 'zigza.xyz',];
|
|
384
|
+
const READ_GATEWAYS_ENV_KEYS = ['ARWEAVE_READ_GATEWAYS', 'NEXT_PUBLIC_ARWEAVE_READ_GATEWAYS'];
|
|
385
|
+
/** Ordered gateway hostnames for reads: env list if set, otherwise {@link DEFAULT_ARWEAVE_GATEWAYS}. */
|
|
386
|
+
function getDefaultArweaveReadGatewayHostsOrdered() {
|
|
387
|
+
if (typeof process === 'undefined' || !process.env) {
|
|
388
|
+
return [...DEFAULT_ARWEAVE_GATEWAYS];
|
|
389
|
+
}
|
|
390
|
+
for (const key of READ_GATEWAYS_ENV_KEYS) {
|
|
391
|
+
const raw = process.env[key]?.trim();
|
|
392
|
+
if (raw) {
|
|
393
|
+
return raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return [...DEFAULT_ARWEAVE_GATEWAYS];
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Deduped host list: primary first, then each default not already present (case-insensitive).
|
|
400
|
+
*/
|
|
401
|
+
function mergePrimaryHostWithDefaults(primary, defaults) {
|
|
402
|
+
const seen = new Set();
|
|
403
|
+
const out = [];
|
|
404
|
+
const keyOf = (h) => h.trim().toLowerCase().replace(/\/$/, '');
|
|
405
|
+
const add = (h) => {
|
|
406
|
+
const t = h.trim().replace(/\/$/, '');
|
|
407
|
+
if (!t)
|
|
408
|
+
return;
|
|
409
|
+
const k = keyOf(t);
|
|
410
|
+
if (seen.has(k))
|
|
411
|
+
return;
|
|
412
|
+
seen.add(k);
|
|
413
|
+
out.push(t);
|
|
414
|
+
};
|
|
415
|
+
add(primary);
|
|
416
|
+
for (const d of defaults)
|
|
417
|
+
add(d);
|
|
418
|
+
return out;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* True if `hostname` looks like a public Arweave gateway used in stored URLs (hydration / RSS).
|
|
422
|
+
*/
|
|
423
|
+
function isKnownArweaveGatewayHostname(hostname) {
|
|
424
|
+
const h = hostname.trim().toLowerCase();
|
|
425
|
+
if (!h)
|
|
426
|
+
return false;
|
|
427
|
+
if (h.endsWith('arweave.net'))
|
|
428
|
+
return true;
|
|
429
|
+
if (h.endsWith('ar-io.net'))
|
|
430
|
+
return true;
|
|
431
|
+
for (const g of DEFAULT_ARWEAVE_GATEWAYS) {
|
|
432
|
+
const gl = g.toLowerCase();
|
|
433
|
+
if (h === gl || h.endsWith(`.${gl}`))
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
/** Fired after `syncDbWithEas` persists EAS seeds/versions/metadata to SQLite (see `Item.rehydrateCachedItemsFromDbAfterEasSync`). */
|
|
439
|
+
const EAS_SEED_DATA_SYNCED_TO_DB_EVENT = 'easSeedDataSyncedToDb';
|
|
374
440
|
/**
|
|
375
441
|
* Check if a schema is an internal SDK schema that should not be created in app files
|
|
376
442
|
*/
|
|
@@ -385,6 +451,7 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
385
451
|
DEFAULT_ARWEAVE_GATEWAYS: DEFAULT_ARWEAVE_GATEWAYS,
|
|
386
452
|
DEFAULT_ARWEAVE_GRAPHQL_URL: DEFAULT_ARWEAVE_GRAPHQL_URL,
|
|
387
453
|
DEFAULT_ARWEAVE_HOST: DEFAULT_ARWEAVE_HOST,
|
|
454
|
+
EAS_SEED_DATA_SYNCED_TO_DB_EVENT: EAS_SEED_DATA_SYNCED_TO_DB_EVENT,
|
|
388
455
|
INIT_SCRIPT_SUCCESS_MESSAGE: INIT_SCRIPT_SUCCESS_MESSAGE,
|
|
389
456
|
INTERNAL_DATA_TYPES: INTERNAL_DATA_TYPES,
|
|
390
457
|
INTERNAL_PROPERTY_NAMES: INTERNAL_PROPERTY_NAMES,
|
|
@@ -402,7 +469,10 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
402
469
|
ZERO_BYTES: ZERO_BYTES,
|
|
403
470
|
ZERO_BYTES32: ZERO_BYTES32,
|
|
404
471
|
defaultAttestationData: defaultAttestationData,
|
|
405
|
-
|
|
472
|
+
getDefaultArweaveReadGatewayHostsOrdered: getDefaultArweaveReadGatewayHostsOrdered,
|
|
473
|
+
isInternalSchema: isInternalSchema,
|
|
474
|
+
isKnownArweaveGatewayHostname: isKnownArweaveGatewayHostname,
|
|
475
|
+
mergePrimaryHostWithDefaults: mergePrimaryHostWithDefaults
|
|
406
476
|
});
|
|
407
477
|
|
|
408
478
|
function parseGateway(input) {
|
|
@@ -419,6 +489,8 @@ function parseGateway(input) {
|
|
|
419
489
|
let _host = DEFAULT_ARWEAVE_HOST;
|
|
420
490
|
let _protocol = 'https';
|
|
421
491
|
let _hostExplicitlySet = false;
|
|
492
|
+
/** When true, production `ARWEAVE_HOST` / `NEXT_PUBLIC_ARWEAVE_HOST` does not override `_host` (after a successful read-gateway probe). */
|
|
493
|
+
let _suppressEnvGatewayOverride = false;
|
|
422
494
|
class BaseArweaveClient {
|
|
423
495
|
static setPlatformClass(platformClass) {
|
|
424
496
|
this.PlatformClass = platformClass;
|
|
@@ -431,7 +503,7 @@ class BaseArweaveClient {
|
|
|
431
503
|
const envHost = typeof process !== 'undefined' && process.env
|
|
432
504
|
? process.env.NEXT_PUBLIC_ARWEAVE_HOST || process.env.ARWEAVE_HOST
|
|
433
505
|
: undefined;
|
|
434
|
-
if (envHost && !_hostExplicitlySet) {
|
|
506
|
+
if (envHost && !_hostExplicitlySet && !_suppressEnvGatewayOverride) {
|
|
435
507
|
return parseGateway(envHost);
|
|
436
508
|
}
|
|
437
509
|
}
|
|
@@ -469,6 +541,39 @@ class BaseArweaveClient {
|
|
|
469
541
|
_host = parsed.host;
|
|
470
542
|
_protocol = parsed.protocol;
|
|
471
543
|
_hostExplicitlySet = true;
|
|
544
|
+
_suppressEnvGatewayOverride = false;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* When true, read-path gateway probing does not change the host ({@link setHost}).
|
|
548
|
+
*/
|
|
549
|
+
static isReadGatewayLocked() {
|
|
550
|
+
return _hostExplicitlySet;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* @internal Clears env override suppression after probing (for test isolation).
|
|
554
|
+
*/
|
|
555
|
+
static resetReadGatewaySelectionStateForTests() {
|
|
556
|
+
_suppressEnvGatewayOverride = false;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Sets the preferred read gateway without locking. Production env host still takes precedence until a probe applies a host.
|
|
560
|
+
* Used for seed `arweaveDomain`.
|
|
561
|
+
*/
|
|
562
|
+
static setPreferredReadGateway(host) {
|
|
563
|
+
const parsed = parseGateway(host);
|
|
564
|
+
_host = parsed.host;
|
|
565
|
+
_protocol = parsed.protocol;
|
|
566
|
+
_hostExplicitlySet = false;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Applies a gateway chosen by read-path health probing so {@link getHost} uses it instead of env override.
|
|
570
|
+
*/
|
|
571
|
+
static applyProbedReadGateway(host) {
|
|
572
|
+
const parsed = parseGateway(host);
|
|
573
|
+
_host = parsed.host;
|
|
574
|
+
_protocol = parsed.protocol;
|
|
575
|
+
_hostExplicitlySet = false;
|
|
576
|
+
_suppressEnvGatewayOverride = true;
|
|
472
577
|
}
|
|
473
578
|
/**
|
|
474
579
|
* Get the GraphQL endpoint URL
|
|
@@ -552,6 +657,11 @@ class BaseArweaveClient {
|
|
|
552
657
|
}
|
|
553
658
|
}
|
|
554
659
|
|
|
660
|
+
var BaseArweaveClient$1 = /*#__PURE__*/Object.freeze({
|
|
661
|
+
__proto__: null,
|
|
662
|
+
BaseArweaveClient: BaseArweaveClient
|
|
663
|
+
});
|
|
664
|
+
|
|
555
665
|
/**
|
|
556
666
|
* Trim and strip a trailing slash from an upload API base URL.
|
|
557
667
|
*/
|
|
@@ -603,6 +713,126 @@ async function getUploadPipelineTransactionStatus(uploadApiBaseUrl, txOrDataItem
|
|
|
603
713
|
}
|
|
604
714
|
}
|
|
605
715
|
|
|
716
|
+
const READ_GATEWAY_CACHE_TTL_MS = 3 * 60 * 1000;
|
|
717
|
+
const PROBE_TIMEOUT_MS = 5000;
|
|
718
|
+
let readGatewayCache = null;
|
|
719
|
+
let ensureInFlight = null;
|
|
720
|
+
/** Clears cached read gateway (e.g. after tests or to force a fresh probe). */
|
|
721
|
+
function invalidateReadGatewayCache() {
|
|
722
|
+
readGatewayCache = null;
|
|
723
|
+
ensureInFlight = null;
|
|
724
|
+
}
|
|
725
|
+
/** Clears probe cache, env override suppression, and preferred host (for tests). */
|
|
726
|
+
function resetArweaveReadGatewayForTests() {
|
|
727
|
+
invalidateReadGatewayCache();
|
|
728
|
+
BaseArweaveClient.resetReadGatewaySelectionStateForTests();
|
|
729
|
+
if (!BaseArweaveClient.isReadGatewayLocked()) {
|
|
730
|
+
BaseArweaveClient.setPreferredReadGateway(DEFAULT_ARWEAVE_HOST);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* GET /info with timeout. Treat 2xx + JSON object as healthy.
|
|
735
|
+
*/
|
|
736
|
+
async function probeGateway(baseUrl, signal) {
|
|
737
|
+
const url = `${baseUrl.replace(/\/$/, '')}/info`;
|
|
738
|
+
let timer;
|
|
739
|
+
const controller = new AbortController();
|
|
740
|
+
const effectiveSignal = signal ?? controller.signal;
|
|
741
|
+
if (!signal) {
|
|
742
|
+
timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
const response = await fetch(url, {
|
|
746
|
+
method: 'GET',
|
|
747
|
+
signal: effectiveSignal,
|
|
748
|
+
headers: { Accept: 'application/json' },
|
|
749
|
+
});
|
|
750
|
+
if (!response.ok)
|
|
751
|
+
return false;
|
|
752
|
+
const text = await response.text();
|
|
753
|
+
if (!text.trim())
|
|
754
|
+
return false;
|
|
755
|
+
try {
|
|
756
|
+
const json = JSON.parse(text);
|
|
757
|
+
return typeof json === 'object' && json !== null;
|
|
758
|
+
}
|
|
759
|
+
catch {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
catch {
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
finally {
|
|
767
|
+
if (timer)
|
|
768
|
+
clearTimeout(timer);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
async function selectFirstHealthyReadGateway(hosts, protocol = 'https', signal) {
|
|
772
|
+
for (const host of hosts) {
|
|
773
|
+
const h = host.trim().replace(/\/$/, '');
|
|
774
|
+
if (!h)
|
|
775
|
+
continue;
|
|
776
|
+
const baseUrl = `${protocol}://${h}`;
|
|
777
|
+
if (await probeGateway(baseUrl, signal)) {
|
|
778
|
+
return h;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
function buildOrderedHostsForProbe() {
|
|
784
|
+
const primary = BaseArweaveClient.getHost();
|
|
785
|
+
const defaults = getDefaultArweaveReadGatewayHostsOrdered();
|
|
786
|
+
return mergePrimaryHostWithDefaults(primary, defaults);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Probes gateways in order and applies the first healthy host via {@link BaseArweaveClient.applyProbedReadGateway}.
|
|
790
|
+
* No-op when the read gateway is locked ({@link BaseArweaveClient.setHost}).
|
|
791
|
+
* Uses a short TTL cache to avoid probing on every read.
|
|
792
|
+
*/
|
|
793
|
+
async function ensureReadGatewaySelected(signal) {
|
|
794
|
+
if (BaseArweaveClient.isReadGatewayLocked()) {
|
|
795
|
+
return BaseArweaveClient.getHost();
|
|
796
|
+
}
|
|
797
|
+
const now = Date.now();
|
|
798
|
+
if (readGatewayCache && now < readGatewayCache.expiresAt) {
|
|
799
|
+
return readGatewayCache.host;
|
|
800
|
+
}
|
|
801
|
+
if (ensureInFlight) {
|
|
802
|
+
return ensureInFlight;
|
|
803
|
+
}
|
|
804
|
+
ensureInFlight = (async () => {
|
|
805
|
+
const ordered = buildOrderedHostsForProbe();
|
|
806
|
+
const protocol = BaseArweaveClient.getProtocol();
|
|
807
|
+
const picked = await selectFirstHealthyReadGateway(ordered, protocol, signal);
|
|
808
|
+
if (!BaseArweaveClient.isReadGatewayLocked()) {
|
|
809
|
+
if (picked) {
|
|
810
|
+
BaseArweaveClient.applyProbedReadGateway(picked);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
readGatewayCache = {
|
|
814
|
+
host: BaseArweaveClient.getHost(),
|
|
815
|
+
expiresAt: Date.now() + READ_GATEWAY_CACHE_TTL_MS,
|
|
816
|
+
};
|
|
817
|
+
return readGatewayCache.host;
|
|
818
|
+
})();
|
|
819
|
+
try {
|
|
820
|
+
return await ensureInFlight;
|
|
821
|
+
}
|
|
822
|
+
finally {
|
|
823
|
+
ensureInFlight = null;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
var selectReadGateway = /*#__PURE__*/Object.freeze({
|
|
828
|
+
__proto__: null,
|
|
829
|
+
ensureReadGatewaySelected: ensureReadGatewaySelected,
|
|
830
|
+
invalidateReadGatewayCache: invalidateReadGatewayCache,
|
|
831
|
+
probeGateway: probeGateway,
|
|
832
|
+
resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
|
|
833
|
+
selectFirstHealthyReadGateway: selectFirstHealthyReadGateway
|
|
834
|
+
});
|
|
835
|
+
|
|
606
836
|
const GATEWAY_TX_QUERY = `
|
|
607
837
|
query ArweaveGatewayTransaction($id: String!) {
|
|
608
838
|
transaction(id: $id) {
|
|
@@ -699,6 +929,42 @@ async function queryArweaveGatewayTransaction(graphqlUrl, dataItemId, init) {
|
|
|
699
929
|
return null;
|
|
700
930
|
}
|
|
701
931
|
}
|
|
932
|
+
/**
|
|
933
|
+
* Resolves GraphQL against the first healthy gateway (GET /info probe per host), then runs
|
|
934
|
+
* {@link queryArweaveGatewayTransaction}. Host order: optional `graphqlUrl` hostname first, then
|
|
935
|
+
* {@link getDefaultArweaveReadGatewayHostsOrdered}.
|
|
936
|
+
*/
|
|
937
|
+
async function queryArweaveGatewayTransactionWithFallback(graphqlUrl, dataItemId, init) {
|
|
938
|
+
const defaults = getDefaultArweaveReadGatewayHostsOrdered();
|
|
939
|
+
const trimmed = graphqlUrl?.trim();
|
|
940
|
+
let protocol = 'https';
|
|
941
|
+
let preferredHost = null;
|
|
942
|
+
if (trimmed) {
|
|
943
|
+
try {
|
|
944
|
+
const u = new URL(trimmed);
|
|
945
|
+
protocol = u.protocol === 'http:' ? 'http' : 'https';
|
|
946
|
+
preferredHost = u.hostname || null;
|
|
947
|
+
}
|
|
948
|
+
catch {
|
|
949
|
+
preferredHost = null;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
const ordered = preferredHost && preferredHost.length > 0
|
|
953
|
+
? mergePrimaryHostWithDefaults(preferredHost, defaults)
|
|
954
|
+
: [...defaults];
|
|
955
|
+
const signal = init?.signal;
|
|
956
|
+
for (const host of ordered) {
|
|
957
|
+
const base = `${protocol}://${host}`;
|
|
958
|
+
if (!(await probeGateway(base, signal ?? undefined)))
|
|
959
|
+
continue;
|
|
960
|
+
const gqlUrl = `${protocol}://${host}/graphql`;
|
|
961
|
+
const result = await queryArweaveGatewayTransaction(gqlUrl, dataItemId, init);
|
|
962
|
+
if (result !== null) {
|
|
963
|
+
return result;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
702
968
|
|
|
703
969
|
class BaseEasClient {
|
|
704
970
|
static setPlatformClass(platformClass) {
|
|
@@ -1374,6 +1640,19 @@ const arweaveL1FinalizeJobs = sqliteTable('arweave_l1_finalize_jobs', {
|
|
|
1374
1640
|
dataItemIdUnique: uniqueIndex('arweave_l1_finalize_jobs_data_item_id_unique').on(table.dataItemId),
|
|
1375
1641
|
}));
|
|
1376
1642
|
|
|
1643
|
+
const easSyncProcesses = sqliteTable('eas_sync_processes', {
|
|
1644
|
+
id: int('id').primaryKey({ autoIncrement: true }),
|
|
1645
|
+
status: text('status').notNull(), // 'in_progress' | 'completed' | 'failed'
|
|
1646
|
+
startedAt: int('started_at').notNull(),
|
|
1647
|
+
completedAt: int('completed_at'),
|
|
1648
|
+
requestPayload: text('request_payload').notNull(),
|
|
1649
|
+
errorMessage: text('error_message'),
|
|
1650
|
+
errorDetails: text('error_details'),
|
|
1651
|
+
persistedSnapshot: text('persisted_snapshot').notNull(),
|
|
1652
|
+
createdAt: int('created_at'),
|
|
1653
|
+
updatedAt: int('updated_at'),
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1377
1656
|
/**
|
|
1378
1657
|
* Links Image seeds materialized from Html `data:image/*` URIs to the parent Item seed for co-publish.
|
|
1379
1658
|
* Rows are removed after a successful publish (see clearHtmlEmbeddedImageCoPublishRows).
|
|
@@ -1864,6 +2143,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1864
2143
|
capitalizeFirstLetter: capitalizeFirstLetter,
|
|
1865
2144
|
classifyMediaRef: classifyMediaRef,
|
|
1866
2145
|
convertTxIdToImage: convertTxIdToImage,
|
|
2146
|
+
ensureReadGatewaySelected: ensureReadGatewaySelected,
|
|
1867
2147
|
generateId: generateId,
|
|
1868
2148
|
getAlternatePropertyNameForInstanceLookup: getAlternatePropertyNameForInstanceLookup,
|
|
1869
2149
|
getArweaveUploadStatus: getArweaveUploadStatus,
|
|
@@ -1883,6 +2163,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1883
2163
|
getUploadExecutor: getUploadExecutor,
|
|
1884
2164
|
getUploadPipelineTransactionStatus: getUploadPipelineTransactionStatus,
|
|
1885
2165
|
identifyString: identifyString,
|
|
2166
|
+
invalidateReadGatewayCache: invalidateReadGatewayCache,
|
|
1886
2167
|
isArweaveL1AnchoringComplete: isArweaveL1AnchoringComplete,
|
|
1887
2168
|
isBinary: isBinary,
|
|
1888
2169
|
isPlaceholderUid: isPlaceholderUid,
|
|
@@ -1895,11 +2176,15 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
1895
2176
|
normalizeUploadApiBaseUrl: normalizeUploadApiBaseUrl,
|
|
1896
2177
|
parseEasRelationPropertyName: parseEasRelationPropertyName,
|
|
1897
2178
|
pickLatestPropertyAttestationsByRefAndSchema: pickLatestPropertyAttestationsByRefAndSchema,
|
|
2179
|
+
probeGateway: probeGateway,
|
|
1898
2180
|
queryArweaveGatewayTransaction: queryArweaveGatewayTransaction,
|
|
2181
|
+
queryArweaveGatewayTransactionWithFallback: queryArweaveGatewayTransactionWithFallback,
|
|
2182
|
+
resetArweaveReadGatewayForTests: resetArweaveReadGatewayForTests,
|
|
1899
2183
|
resolveMediaRef: resolveMediaRef,
|
|
1900
2184
|
resolveMetadataRecord: resolveMetadataRecord,
|
|
1901
2185
|
resolveSeedIdsFromRefString: resolveSeedIdsFromRefString,
|
|
1902
2186
|
resolveStorageNameToSchemaName: resolveStorageNameToSchemaName,
|
|
2187
|
+
selectFirstHealthyReadGateway: selectFirstHealthyReadGateway,
|
|
1903
2188
|
setAdditionalSyncAddresses: setAdditionalSyncAddresses,
|
|
1904
2189
|
setGetPublisherForNewSeeds: setGetPublisherForNewSeeds,
|
|
1905
2190
|
setRevokeExecutor: setRevokeExecutor,
|
|
@@ -1922,7 +2207,7 @@ const createPropertyInstances = async (propertyFileIds) => {
|
|
|
1922
2207
|
return;
|
|
1923
2208
|
}
|
|
1924
2209
|
try {
|
|
1925
|
-
const mod = await import('./ModelProperty-
|
|
2210
|
+
const mod = await import('./ModelProperty-CIeLasI4.js');
|
|
1926
2211
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
1927
2212
|
if (!ModelProperty) {
|
|
1928
2213
|
logger$t('createPropertyInstances: ModelProperty not available from dynamic import');
|
|
@@ -2106,7 +2391,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
2106
2391
|
// Step 2: Fallback to Schema context (only if database doesn't have the model)
|
|
2107
2392
|
// This handles the case where model exists in schema file but not yet in database
|
|
2108
2393
|
try {
|
|
2109
|
-
const _mod_0 = await import('./Schema-
|
|
2394
|
+
const _mod_0 = await import('./Schema-B3YQHTtu.js');
|
|
2110
2395
|
const _ns_0 = _mod_0.b;
|
|
2111
2396
|
const schemaMod = _ns_0;
|
|
2112
2397
|
const { Schema } = schemaMod;
|
|
@@ -2352,7 +2637,7 @@ const loadOrCreateModel = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
2352
2637
|
}
|
|
2353
2638
|
// Mark schema as draft when a new model is created so saveNewVersion() can persist it
|
|
2354
2639
|
try {
|
|
2355
|
-
const _mod_1 = await import('./Schema-
|
|
2640
|
+
const _mod_1 = await import('./Schema-B3YQHTtu.js');
|
|
2356
2641
|
const _ns_1 = _mod_1.b;
|
|
2357
2642
|
const schemaMod = _ns_1;
|
|
2358
2643
|
const { Schema } = schemaMod;
|
|
@@ -2398,10 +2683,10 @@ const validateModel = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
2398
2683
|
const _validateModel = async () => {
|
|
2399
2684
|
try {
|
|
2400
2685
|
// Use dynamic imports to break circular dependencies
|
|
2401
|
-
const validationServiceMod = await import('./SchemaValidationService-
|
|
2686
|
+
const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
|
|
2402
2687
|
const { SchemaValidationService } = validationServiceMod;
|
|
2403
2688
|
const validationService = new SchemaValidationService();
|
|
2404
|
-
const _mod_2 = await import('./Schema-
|
|
2689
|
+
const _mod_2 = await import('./Schema-B3YQHTtu.js');
|
|
2405
2690
|
const _ns_2 = _mod_2.b;
|
|
2406
2691
|
const schemaMod = _ns_2;
|
|
2407
2692
|
const { Schema } = schemaMod;
|
|
@@ -2513,7 +2798,7 @@ const createModelProperties = fromCallback(({ sendBack, input }) => {
|
|
|
2513
2798
|
return;
|
|
2514
2799
|
}
|
|
2515
2800
|
logger$r(`Creating ${Object.keys(propertyDefinitions).length} properties for model "${modelName}" (id: ${_dbId})`);
|
|
2516
|
-
const mod = await import('./ModelProperty-
|
|
2801
|
+
const mod = await import('./ModelProperty-CIeLasI4.js');
|
|
2517
2802
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
2518
2803
|
if (!ModelProperty) {
|
|
2519
2804
|
logger$r('ModelProperty not available from dynamic import');
|
|
@@ -2617,7 +2902,7 @@ const validateEntity = fromPromise(async ({ input }) => {
|
|
|
2617
2902
|
const structureMsg = `[validateEntity] Validating model structure`;
|
|
2618
2903
|
logger$q(structureMsg);
|
|
2619
2904
|
// Use existing Model validation
|
|
2620
|
-
const validationServiceMod = await import('./SchemaValidationService-
|
|
2905
|
+
const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
|
|
2621
2906
|
const { SchemaValidationService } = validationServiceMod;
|
|
2622
2907
|
const validationService = new SchemaValidationService();
|
|
2623
2908
|
// Validate model structure
|
|
@@ -2635,7 +2920,7 @@ const validateEntity = fromPromise(async ({ input }) => {
|
|
|
2635
2920
|
if (entityInput.entityData.schemaName) {
|
|
2636
2921
|
try {
|
|
2637
2922
|
logger$q(`[validateEntity] Validating model against schema "${entityInput.entityData.schemaName}"`);
|
|
2638
|
-
const _mod_3 = await import('./Schema-
|
|
2923
|
+
const _mod_3 = await import('./Schema-B3YQHTtu.js');
|
|
2639
2924
|
const _ns_3 = _mod_3.b;
|
|
2640
2925
|
const schemaMod = _ns_3;
|
|
2641
2926
|
const { Schema } = schemaMod;
|
|
@@ -2673,7 +2958,7 @@ const validateEntity = fromPromise(async ({ input }) => {
|
|
|
2673
2958
|
}
|
|
2674
2959
|
else if (entityInput.entityType === 'modelProperty') {
|
|
2675
2960
|
// Use existing ModelProperty validation
|
|
2676
|
-
const validationServiceMod = await import('./SchemaValidationService-
|
|
2961
|
+
const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
|
|
2677
2962
|
const { SchemaValidationService } = validationServiceMod;
|
|
2678
2963
|
const validationService = new SchemaValidationService();
|
|
2679
2964
|
// Validate property structure
|
|
@@ -2688,7 +2973,7 @@ const validateEntity = fromPromise(async ({ input }) => {
|
|
|
2688
2973
|
// If schema name and model name provided, validate against schema
|
|
2689
2974
|
if (entityInput.entityData._schemaName && entityInput.entityData.modelName) {
|
|
2690
2975
|
try {
|
|
2691
|
-
const _mod_4 = await import('./Schema-
|
|
2976
|
+
const _mod_4 = await import('./Schema-B3YQHTtu.js');
|
|
2692
2977
|
const _ns_4 = _mod_4.b;
|
|
2693
2978
|
const schemaMod = _ns_4;
|
|
2694
2979
|
const { Schema } = schemaMod;
|
|
@@ -2719,7 +3004,7 @@ const validateEntity = fromPromise(async ({ input }) => {
|
|
|
2719
3004
|
}
|
|
2720
3005
|
else if (entityInput.entityType === 'schema') {
|
|
2721
3006
|
// Schema validation - use existing validation
|
|
2722
|
-
const validationServiceMod = await import('./SchemaValidationService-
|
|
3007
|
+
const validationServiceMod = await import('./SchemaValidationService-C4DIwn8Z.js');
|
|
2723
3008
|
const { SchemaValidationService } = validationServiceMod;
|
|
2724
3009
|
const validationService = new SchemaValidationService();
|
|
2725
3010
|
const schemaResult = validationService.validateSchema(entityInput.entityData);
|
|
@@ -4671,7 +4956,7 @@ const writeToDatabase = fromCallback(({ sendBack, input }) => {
|
|
|
4671
4956
|
// initial write completes is not overwritten by the stale requestWrite payload.
|
|
4672
4957
|
let dataToWrite = input.entityData;
|
|
4673
4958
|
try {
|
|
4674
|
-
const mod = await import('./ModelProperty-
|
|
4959
|
+
const mod = await import('./ModelProperty-CIeLasI4.js');
|
|
4675
4960
|
const ModelProperty = mod?.ModelProperty ?? mod?.default;
|
|
4676
4961
|
if (ModelProperty && typeof ModelProperty.getById === 'function') {
|
|
4677
4962
|
const instance = ModelProperty.getById(input.entityId);
|
|
@@ -5051,7 +5336,7 @@ const modelMachine = setup({
|
|
|
5051
5336
|
// Create ModelProperty instances for any new property IDs
|
|
5052
5337
|
if (Array.isArray(newPropertyIds) && newPropertyIds.length > 0) {
|
|
5053
5338
|
// Import and create instances asynchronously (fire-and-forget)
|
|
5054
|
-
import('./ModelProperty-
|
|
5339
|
+
import('./ModelProperty-CIeLasI4.js').then(({ ModelProperty }) => {
|
|
5055
5340
|
const createPromises = newPropertyIds.map(async (propertyFileId) => {
|
|
5056
5341
|
try {
|
|
5057
5342
|
const property = await ModelProperty.createById(propertyFileId);
|
|
@@ -5354,6 +5639,7 @@ const ENV = (typeof process !== 'undefined' && process.env)
|
|
|
5354
5639
|
var MachineIds;
|
|
5355
5640
|
(function (MachineIds) {
|
|
5356
5641
|
MachineIds["CLIENT_MANAGER"] = "@seedSdk/clientManager";
|
|
5642
|
+
MachineIds["EAS_SYNC_MANAGER"] = "@seedSdk/easSyncManager";
|
|
5357
5643
|
MachineIds["GLOBAL"] = "@seedSdk/global";
|
|
5358
5644
|
MachineIds["INTERNAL"] = "@seedSdk/internal";
|
|
5359
5645
|
MachineIds["EAS"] = "@seedSdk/eas";
|
|
@@ -5426,7 +5712,7 @@ const EAS_ENDPOINT = ENV.NEXT_PUBLIC_EAS_ENDPOINT ||
|
|
|
5426
5712
|
* This constant is kept for backward compatibility but will be removed in a future version.
|
|
5427
5713
|
* Migration: import { BaseArweaveClient } from '@/helpers' and use BaseArweaveClient.getHost()
|
|
5428
5714
|
*/
|
|
5429
|
-
ENV.NEXT_PUBLIC_ARWEAVE_HOST || '
|
|
5715
|
+
ENV.NEXT_PUBLIC_ARWEAVE_HOST || 'ar.seedprotocol.io';
|
|
5430
5716
|
|
|
5431
5717
|
debug('seedSdk:item:service:actors:waitForDb');
|
|
5432
5718
|
const waitForDb$1 = fromCallback(({ sendBack }) => {
|
|
@@ -6347,7 +6633,7 @@ const getMetadataLatest = ({ seedLocalId, seedUid }) => {
|
|
|
6347
6633
|
rowNum: sql.raw(`
|
|
6348
6634
|
ROW_NUMBER() OVER (
|
|
6349
6635
|
PARTITION BY property_name
|
|
6350
|
-
ORDER BY COALESCE(attestation_created_at, created_at) DESC
|
|
6636
|
+
ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC
|
|
6351
6637
|
)
|
|
6352
6638
|
`).as('rowNum')
|
|
6353
6639
|
})
|
|
@@ -6360,6 +6646,25 @@ var metadataLatest = /*#__PURE__*/Object.freeze({
|
|
|
6360
6646
|
getMetadataLatest: getMetadataLatest
|
|
6361
6647
|
});
|
|
6362
6648
|
|
|
6649
|
+
/**
|
|
6650
|
+
* Canonical "latest metadata row first" ordering. Must stay in sync with SQL that uses:
|
|
6651
|
+
* `ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC`
|
|
6652
|
+
*/
|
|
6653
|
+
function metadataLatestFirstSortKey(row) {
|
|
6654
|
+
return {
|
|
6655
|
+
t: row.attestationCreatedAt ?? row.createdAt ?? 0,
|
|
6656
|
+
localId: String(row.localId ?? ''),
|
|
6657
|
+
};
|
|
6658
|
+
}
|
|
6659
|
+
/** Sort comparator: larger time first; on tie, larger localId (lexicographic) first. */
|
|
6660
|
+
function compareMetadataRowsLatestFirst(a, b) {
|
|
6661
|
+
const ka = metadataLatestFirstSortKey(a);
|
|
6662
|
+
const kb = metadataLatestFirstSortKey(b);
|
|
6663
|
+
if (kb.t !== ka.t)
|
|
6664
|
+
return kb.t - ka.t;
|
|
6665
|
+
return kb.localId.localeCompare(ka.localId);
|
|
6666
|
+
}
|
|
6667
|
+
|
|
6363
6668
|
const logger$l = debug('seedSdk:item:actors:loadOrCreateItem');
|
|
6364
6669
|
/**
|
|
6365
6670
|
* Maps metadata.property_name to the ItemProperty Map key (same rules as the instance loop below).
|
|
@@ -6401,9 +6706,8 @@ function pickBetterMetadataRowForSameInstance(a, b) {
|
|
|
6401
6706
|
return b;
|
|
6402
6707
|
if (sa !== sb)
|
|
6403
6708
|
return sa > sb ? a : b;
|
|
6404
|
-
const
|
|
6405
|
-
|
|
6406
|
-
return ta >= tb ? a : b;
|
|
6709
|
+
const cmp = compareMetadataRowsLatestFirst(a, b);
|
|
6710
|
+
return cmp < 0 ? a : b;
|
|
6407
6711
|
}
|
|
6408
6712
|
function dedupeMetadataRowsByInstanceKey(metadataRows, propertySchemas) {
|
|
6409
6713
|
const byKey = new Map();
|
|
@@ -6451,7 +6755,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6451
6755
|
const schemaNameToTry = model$1?.schemaName;
|
|
6452
6756
|
if (schemaNameToTry) {
|
|
6453
6757
|
try {
|
|
6454
|
-
const _mod_5 = await import('./Schema-
|
|
6758
|
+
const _mod_5 = await import('./Schema-B3YQHTtu.js');
|
|
6455
6759
|
const _ns_5 = _mod_5.b;
|
|
6456
6760
|
const { Schema } = _ns_5;
|
|
6457
6761
|
const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
|
|
@@ -6502,7 +6806,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6502
6806
|
}
|
|
6503
6807
|
}
|
|
6504
6808
|
if (Object.keys(propertySchemas).length === 0) {
|
|
6505
|
-
const schemaMod = await import('./index-
|
|
6809
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
6506
6810
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
6507
6811
|
const KNOWN_MODEL_FALLBACKS = {
|
|
6508
6812
|
Post: {
|
|
@@ -6549,7 +6853,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
|
|
|
6549
6853
|
// Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
|
|
6550
6854
|
let propSchema = propertySchemas[propertyName];
|
|
6551
6855
|
if (!propSchema && isRefTypeFromMeta) {
|
|
6552
|
-
const schemaMod = await import('./index-
|
|
6856
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
6553
6857
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
6554
6858
|
propSchema = {
|
|
6555
6859
|
dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
|
|
@@ -6806,9 +7110,9 @@ const runPublish = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
6806
7110
|
sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
|
|
6807
7111
|
return;
|
|
6808
7112
|
}
|
|
6809
|
-
const getPublishUploadsMod = await import('./getPublishUploads-
|
|
7113
|
+
const getPublishUploadsMod = await import('./getPublishUploads-Cf2J-5FR.js');
|
|
6810
7114
|
const { getPublishUploads } = getPublishUploadsMod;
|
|
6811
|
-
const getPublishPayloadMod = await import('./getPublishPayload-
|
|
7115
|
+
const getPublishPayloadMod = await import('./getPublishPayload-Ddc_LGPs.js');
|
|
6812
7116
|
const { getPublishPayload } = getPublishPayloadMod;
|
|
6813
7117
|
const uploads = await getPublishUploads(item);
|
|
6814
7118
|
let uploadedTransactions = [];
|
|
@@ -7154,6 +7458,11 @@ const getSeedData = async ({ seedLocalId, seedUid }) => {
|
|
|
7154
7458
|
return rows[0];
|
|
7155
7459
|
};
|
|
7156
7460
|
|
|
7461
|
+
var getSeedData$1 = /*#__PURE__*/Object.freeze({
|
|
7462
|
+
__proto__: null,
|
|
7463
|
+
getSeedData: getSeedData
|
|
7464
|
+
});
|
|
7465
|
+
|
|
7157
7466
|
/**
|
|
7158
7467
|
* Latest version row for the seed (by createdAt) whose uid is a real EAS attestation id.
|
|
7159
7468
|
* Skips legacy 'NULL' / ZERO_BYTES32 placeholders and non-bytes32 strings.
|
|
@@ -7643,7 +7952,7 @@ const resolveRelatedValue = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
7643
7952
|
const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
|
|
7644
7953
|
const _resolveRelatedValue = async () => {
|
|
7645
7954
|
// Use dynamic import to break circular dependency
|
|
7646
|
-
const schemaMod = await import('./index-
|
|
7955
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
7647
7956
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
7648
7957
|
if (!propertyValue || !isRelation || populatedFromDb) {
|
|
7649
7958
|
return;
|
|
@@ -8006,150 +8315,771 @@ function parseListPropertyValueFromStorage(raw) {
|
|
|
8006
8315
|
return trimmed.split(',').map((s) => s.trim()).filter(Boolean);
|
|
8007
8316
|
}
|
|
8008
8317
|
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
const
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8318
|
+
const eventEmitter = new EventEmitter();
|
|
8319
|
+
|
|
8320
|
+
const GET_FILES_METADATA = graphql(/* GraphQL */ `
|
|
8321
|
+
query GetFilesMetadata($where: AttestationWhereInput!) {
|
|
8322
|
+
filesMetadata: attestations(
|
|
8323
|
+
where: $where
|
|
8324
|
+
orderBy: [{ timeCreated: desc }]
|
|
8325
|
+
) {
|
|
8326
|
+
...attestationFields
|
|
8016
8327
|
}
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
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
|
-
|
|
8328
|
+
}
|
|
8329
|
+
`);
|
|
8330
|
+
|
|
8331
|
+
const getMetadata = async (props) => {
|
|
8332
|
+
const appDb = BaseDb.getAppDb();
|
|
8333
|
+
let storageTransactionId;
|
|
8334
|
+
if (props) {
|
|
8335
|
+
storageTransactionId = props.storageTransactionId;
|
|
8336
|
+
}
|
|
8337
|
+
const whereClauses = [];
|
|
8338
|
+
if (storageTransactionId) {
|
|
8339
|
+
whereClauses.push(eq(metadata$1.propertyName, 'storageTransactionId'));
|
|
8340
|
+
whereClauses.push(eq(metadata$1.propertyValue, storageTransactionId));
|
|
8341
|
+
}
|
|
8342
|
+
const metadataRows = await appDb
|
|
8343
|
+
.select()
|
|
8344
|
+
.from(metadata$1)
|
|
8345
|
+
.where(and(...whereClauses));
|
|
8346
|
+
if (!metadataRows || metadataRows.length === 0) {
|
|
8347
|
+
return;
|
|
8348
|
+
}
|
|
8349
|
+
return metadataRows[0];
|
|
8350
|
+
};
|
|
8351
|
+
|
|
8352
|
+
const saveMetadata = async (metadataRecord, metadataValues) => {
|
|
8353
|
+
if (!metadataRecord.localId) {
|
|
8354
|
+
return;
|
|
8355
|
+
}
|
|
8356
|
+
const appDb = BaseDb.getAppDb();
|
|
8357
|
+
await appDb
|
|
8358
|
+
.update(metadata$1)
|
|
8359
|
+
.set({
|
|
8360
|
+
...metadataValues,
|
|
8361
|
+
updatedAt: Date.now(),
|
|
8362
|
+
})
|
|
8363
|
+
.where(eq(metadata$1.localId, metadataRecord.localId));
|
|
8364
|
+
};
|
|
8365
|
+
|
|
8366
|
+
const isNode = () => {
|
|
8367
|
+
return (typeof process !== 'undefined' &&
|
|
8368
|
+
process.versions != null &&
|
|
8369
|
+
process.versions.node != null);
|
|
8370
|
+
};
|
|
8371
|
+
const isBrowser = () => {
|
|
8372
|
+
return !isElectron() && typeof document !== 'undefined' && typeof window !== 'undefined';
|
|
8373
|
+
};
|
|
8374
|
+
const isElectron = () => {
|
|
8375
|
+
return typeof process !== 'undefined' && process.versions != null && process.versions.electron != null;
|
|
8376
|
+
};
|
|
8377
|
+
/**
|
|
8378
|
+
* Detects if code is running in an Electron renderer process.
|
|
8379
|
+
*
|
|
8380
|
+
* Uses multiple detection methods for robustness:
|
|
8381
|
+
* 1. Checks process.type === 'renderer' (most reliable)
|
|
8382
|
+
* 2. Falls back to checking if Electron is present and window/document exist
|
|
8383
|
+
*
|
|
8384
|
+
* @returns true if running in Electron renderer process, false otherwise
|
|
8385
|
+
*/
|
|
8386
|
+
const isElectronRenderer = () => {
|
|
8387
|
+
// Method 1: Check process.type (most reliable - official Electron API)
|
|
8388
|
+
if (typeof process !== 'undefined' &&
|
|
8389
|
+
process.type === 'renderer') {
|
|
8390
|
+
return true;
|
|
8391
|
+
}
|
|
8392
|
+
// Method 2: Fallback - Electron + browser-like environment
|
|
8393
|
+
// Renderer processes have window/document, main process doesn't (in modern Electron)
|
|
8394
|
+
if (isElectron() &&
|
|
8395
|
+
typeof window !== 'undefined' &&
|
|
8396
|
+
typeof document !== 'undefined') {
|
|
8397
|
+
return true;
|
|
8398
|
+
}
|
|
8399
|
+
return false;
|
|
8400
|
+
};
|
|
8401
|
+
/**
|
|
8402
|
+
* True where OPFS-backed Arweave file downloads should run: normal browsers and
|
|
8403
|
+
* Electron renderer. {@link isBrowser} is false for every Electron build (including renderer).
|
|
8404
|
+
*/
|
|
8405
|
+
const supportsOpfsFileDownloads = () => {
|
|
8406
|
+
return isBrowser() || isElectronRenderer();
|
|
8407
|
+
};
|
|
8408
|
+
|
|
8409
|
+
const logger$g = debug('seedSdk:files:download');
|
|
8410
|
+
const AUTO_BULK_DOWNLOAD_THROTTLE_MS = 10000;
|
|
8411
|
+
/** Avoid refetch-on-every-call: transient empty indexer responses were overwriting good cache (see trailing throttle ~10s after success). */
|
|
8412
|
+
const GET_FILES_METADATA_STALE_MS = 120000;
|
|
8413
|
+
let bulkDownloadInFlight = null;
|
|
8414
|
+
const lazyDownloadInFlightByTransactionId = new Map();
|
|
8415
|
+
// syncDbFiles helper - internal service removed, functionality moved here
|
|
8416
|
+
const syncDbFiles = async (endpoints) => {
|
|
8417
|
+
// TODO: Implement syncDbFiles functionality if needed
|
|
8418
|
+
// This was previously in @/services/internal/helpers
|
|
8419
|
+
logger$g('[download] syncDbFiles called but not yet implemented');
|
|
8420
|
+
return Promise.resolve();
|
|
8421
|
+
};
|
|
8422
|
+
const getAppDbReady = async () => {
|
|
8423
|
+
if (!BaseDb.isAppDbReady()) {
|
|
8424
|
+
// Wait for ClientManager to be ready (DB_INIT state or later)
|
|
8425
|
+
const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
|
|
8426
|
+
const { getClient } = clientManagerMod;
|
|
8427
|
+
const clientManager = getClient();
|
|
8428
|
+
const clientService = clientManager.getService();
|
|
8429
|
+
await waitFor(clientService, (snapshot) => {
|
|
8430
|
+
const state = snapshot.value;
|
|
8431
|
+
return state === 'dbInit' ||
|
|
8432
|
+
state === 'saveConfig' ||
|
|
8433
|
+
state === 'processSchemaFiles' ||
|
|
8434
|
+
state === 'addModelsToStore' ||
|
|
8435
|
+
state === 'addModelsToDb' ||
|
|
8436
|
+
state === 'idle';
|
|
8437
|
+
}, { timeout: 30000 });
|
|
8438
|
+
}
|
|
8439
|
+
return BaseDb.getAppDb();
|
|
8440
|
+
};
|
|
8441
|
+
const getExcludedTransactions = async () => {
|
|
8442
|
+
const appDb = await getAppDbReady();
|
|
8443
|
+
if (!appDb) {
|
|
8444
|
+
return new Set();
|
|
8445
|
+
}
|
|
8446
|
+
const excludedTransactionsQuery = await appDb
|
|
8447
|
+
.select()
|
|
8448
|
+
.from(appState)
|
|
8449
|
+
.where(eq(appState.key, 'excludedTransactions'));
|
|
8450
|
+
const excludedTransactions = new Set();
|
|
8451
|
+
if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
|
|
8452
|
+
const valueString = excludedTransactionsQuery[0].value;
|
|
8453
|
+
if (valueString) {
|
|
8454
|
+
const excludedTransactionsArray = JSON.parse(valueString);
|
|
8455
|
+
for (const txId of excludedTransactionsArray) {
|
|
8456
|
+
excludedTransactions.add(txId);
|
|
8457
|
+
}
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
8460
|
+
return excludedTransactions;
|
|
8461
|
+
};
|
|
8462
|
+
/** Arweave transaction ids are 43 chars in the URL-safe base64 alphabet. */
|
|
8463
|
+
const ARWEAVE_TX_ID_RE = /^[a-z0-9_-]{43}$/i;
|
|
8464
|
+
const normalizeArweaveTxId = (raw) => {
|
|
8465
|
+
if (raw == null || raw === '')
|
|
8466
|
+
return undefined;
|
|
8467
|
+
const t = String(raw).trim();
|
|
8468
|
+
if (ARWEAVE_TX_ID_RE.test(t))
|
|
8469
|
+
return t;
|
|
8470
|
+
const m = t.match(/^([a-z0-9_-]{43})(?:\.[^/]+)?$/i);
|
|
8471
|
+
if (m)
|
|
8472
|
+
return m[1];
|
|
8473
|
+
// Values may be full gateway URLs or paths; scan for the embedded tx id.
|
|
8474
|
+
const embedded = t.match(/[a-z0-9_-]{43}/gi);
|
|
8475
|
+
if (embedded) {
|
|
8476
|
+
for (const candidate of embedded) {
|
|
8477
|
+
if (ARWEAVE_TX_ID_RE.test(candidate))
|
|
8478
|
+
return candidate;
|
|
8479
|
+
}
|
|
8480
|
+
}
|
|
8481
|
+
return undefined;
|
|
8482
|
+
};
|
|
8483
|
+
const mergeAddressLists = (a, b) => {
|
|
8484
|
+
const seen = new Set();
|
|
8485
|
+
const out = [];
|
|
8486
|
+
for (const addr of [...(a ?? []), ...(b ?? [])]) {
|
|
8487
|
+
if (!addr || !addr.trim())
|
|
8488
|
+
continue;
|
|
8489
|
+
const k = addr.toLowerCase();
|
|
8490
|
+
if (seen.has(k))
|
|
8491
|
+
continue;
|
|
8492
|
+
seen.add(k);
|
|
8493
|
+
out.push(addr);
|
|
8494
|
+
}
|
|
8495
|
+
return out;
|
|
8496
|
+
};
|
|
8497
|
+
const collectTransactionIdsFromLocalMetadata = async () => {
|
|
8498
|
+
const appDb = await getAppDbReady();
|
|
8499
|
+
if (!appDb) {
|
|
8500
|
+
return [];
|
|
8501
|
+
}
|
|
8502
|
+
const nameOr = or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'storage_transaction_id'), eq(metadata$1.propertyName, 'transactionId'));
|
|
8503
|
+
const propRows = await appDb
|
|
8504
|
+
.select({ propertyValue: metadata$1.propertyValue })
|
|
8505
|
+
.from(metadata$1)
|
|
8506
|
+
.where(and(nameOr, isNotNull(metadata$1.propertyValue)));
|
|
8507
|
+
const refRows = await appDb
|
|
8508
|
+
.select({ refResolvedValue: metadata$1.refResolvedValue })
|
|
8509
|
+
.from(metadata$1)
|
|
8510
|
+
.where(isNotNull(metadata$1.refResolvedValue));
|
|
8511
|
+
const ids = new Set();
|
|
8512
|
+
for (const row of propRows) {
|
|
8513
|
+
const id = normalizeArweaveTxId(row.propertyValue ?? undefined);
|
|
8514
|
+
if (id)
|
|
8515
|
+
ids.add(id);
|
|
8516
|
+
}
|
|
8517
|
+
for (const row of refRows) {
|
|
8518
|
+
const id = normalizeArweaveTxId(row.refResolvedValue ?? undefined);
|
|
8519
|
+
if (id)
|
|
8520
|
+
ids.add(id);
|
|
8521
|
+
}
|
|
8522
|
+
return Array.from(ids);
|
|
8523
|
+
};
|
|
8524
|
+
const parseTransactionIdsFromMetadata = (filesMetadata, excludedTransactions) => {
|
|
8525
|
+
const transactionIds = [];
|
|
8526
|
+
for (const fileMetadata of filesMetadata) {
|
|
8527
|
+
// Validate and parse decodedDataJson
|
|
8528
|
+
if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
|
|
8529
|
+
console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
|
|
8530
|
+
continue;
|
|
8531
|
+
}
|
|
8532
|
+
let json;
|
|
8533
|
+
try {
|
|
8534
|
+
json = JSON.parse(fileMetadata.decodedDataJson);
|
|
8535
|
+
}
|
|
8536
|
+
catch (error) {
|
|
8537
|
+
console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
|
|
8538
|
+
continue;
|
|
8539
|
+
}
|
|
8540
|
+
if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
|
|
8541
|
+
console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
|
|
8542
|
+
continue;
|
|
8543
|
+
}
|
|
8544
|
+
const rawTx = json[0].value.value;
|
|
8545
|
+
if (typeof rawTx !== 'string' || rawTx.trim().length === 0) {
|
|
8546
|
+
continue;
|
|
8547
|
+
}
|
|
8548
|
+
const transactionId = normalizeArweaveTxId(rawTx.trim());
|
|
8549
|
+
if (!transactionId) {
|
|
8550
|
+
continue;
|
|
8551
|
+
}
|
|
8552
|
+
if (excludedTransactions.has(transactionId) || excludedTransactions.has(rawTx.trim())) {
|
|
8553
|
+
continue;
|
|
8554
|
+
}
|
|
8555
|
+
transactionIds.push(transactionId);
|
|
8556
|
+
}
|
|
8557
|
+
return transactionIds;
|
|
8558
|
+
};
|
|
8559
|
+
const downloadTransactionIds = async (rawTransactionIds, options) => {
|
|
8560
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8561
|
+
return false;
|
|
8562
|
+
}
|
|
8563
|
+
const transactionIds = Array.from(new Set(rawTransactionIds.filter((tx) => !!tx && tx.trim().length > 0)));
|
|
8564
|
+
if (transactionIds.length === 0) {
|
|
8565
|
+
return false;
|
|
8566
|
+
}
|
|
8567
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
8568
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
8569
|
+
const transactionIdsToDownload = [];
|
|
8570
|
+
await ensureReadGatewaySelected();
|
|
8571
|
+
for (const transactionId of transactionIds) {
|
|
8572
|
+
if (excludedTransactions.has(transactionId)) {
|
|
8573
|
+
continue;
|
|
8574
|
+
}
|
|
8575
|
+
try {
|
|
8576
|
+
// Browser: do not call getTransactionStatus() — many gateways (e.g. g8way.io) redirect or omit
|
|
8577
|
+
// CORS headers, so fetch() fails and we would wrongly exclude txs. The OPFS worker fetch decides success.
|
|
8578
|
+
let tags = [];
|
|
8579
|
+
try {
|
|
8580
|
+
tags = await queryClient.fetchQuery({
|
|
8581
|
+
queryKey: ['getTransactionTags', transactionId],
|
|
8582
|
+
queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
|
|
8583
|
+
});
|
|
8584
|
+
}
|
|
8585
|
+
catch {
|
|
8586
|
+
tags = [];
|
|
8587
|
+
}
|
|
8588
|
+
if (tags && tags.length > 0) {
|
|
8589
|
+
for (const { name, value } of tags) {
|
|
8590
|
+
if (name !== 'Content-SHA-256')
|
|
8591
|
+
continue;
|
|
8592
|
+
const metadataRecord = await getMetadata({
|
|
8593
|
+
storageTransactionId: transactionId,
|
|
8594
|
+
});
|
|
8595
|
+
if (metadataRecord) {
|
|
8596
|
+
await saveMetadata(metadataRecord, {
|
|
8597
|
+
contentHash: value,
|
|
8598
|
+
});
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8601
|
+
}
|
|
8602
|
+
transactionIdsToDownload.push(transactionId);
|
|
8603
|
+
}
|
|
8604
|
+
catch (error) {
|
|
8605
|
+
logger$g(error);
|
|
8606
|
+
}
|
|
8607
|
+
}
|
|
8608
|
+
if (transactionIdsToDownload.length === 0) {
|
|
8609
|
+
return false;
|
|
8610
|
+
}
|
|
8611
|
+
if (transactionIdsToDownload.length === 1) {
|
|
8612
|
+
await BaseFileManager.downloadFileByTransactionId({
|
|
8613
|
+
transactionId: transactionIdsToDownload[0],
|
|
8614
|
+
arweaveHost: BaseArweaveClient.getHost(),
|
|
8615
|
+
excludedTransactions,
|
|
8616
|
+
});
|
|
8617
|
+
}
|
|
8618
|
+
else {
|
|
8619
|
+
await BaseFileManager.downloadAllFiles({
|
|
8620
|
+
transactionIds: transactionIdsToDownload,
|
|
8621
|
+
arweaveHost: BaseArweaveClient.getHost(),
|
|
8622
|
+
excludedTransactions,
|
|
8623
|
+
});
|
|
8624
|
+
}
|
|
8625
|
+
if (options?.resizeAllImages !== false) {
|
|
8626
|
+
await BaseFileManager.resizeAllImages({
|
|
8627
|
+
width: 480,
|
|
8628
|
+
height: 480,
|
|
8629
|
+
});
|
|
8630
|
+
}
|
|
8631
|
+
return true;
|
|
8632
|
+
};
|
|
8633
|
+
const runBulkDownloadWithDedupe = async (transactionIds) => {
|
|
8634
|
+
if (bulkDownloadInFlight) {
|
|
8635
|
+
return bulkDownloadInFlight;
|
|
8636
|
+
}
|
|
8637
|
+
bulkDownloadInFlight = (async () => {
|
|
8638
|
+
try {
|
|
8639
|
+
await downloadTransactionIds(transactionIds, { resizeAllImages: true });
|
|
8640
|
+
}
|
|
8641
|
+
finally {
|
|
8642
|
+
bulkDownloadInFlight = null;
|
|
8643
|
+
}
|
|
8644
|
+
})();
|
|
8645
|
+
return bulkDownloadInFlight;
|
|
8646
|
+
};
|
|
8647
|
+
const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
|
|
8648
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8649
|
+
return;
|
|
8650
|
+
}
|
|
8651
|
+
await syncDbFiles();
|
|
8652
|
+
eventEmitter.emit('fs.downloadAll.success', { eventId });
|
|
8653
|
+
eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
|
|
8654
|
+
};
|
|
8655
|
+
const downloadAllFilesBinaryRequestHandler = async (addressesHintOrPayload) => {
|
|
8656
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8657
|
+
return;
|
|
8658
|
+
}
|
|
8659
|
+
const addressesHint = Array.isArray(addressesHintOrPayload)
|
|
8660
|
+
? addressesHintOrPayload
|
|
8661
|
+
: undefined;
|
|
8662
|
+
let fromDb = [];
|
|
8663
|
+
if (BaseDb.isAppDbReady()) {
|
|
8664
|
+
fromDb = await getAllAddressesFromDb();
|
|
8665
|
+
}
|
|
8666
|
+
if (!BaseDb.isAppDbReady()) {
|
|
8667
|
+
await getAppDbReady();
|
|
8668
|
+
fromDb = await getAllAddressesFromDb();
|
|
8669
|
+
}
|
|
8670
|
+
const addresses = mergeAddressLists(addressesHint, fromDb);
|
|
8671
|
+
if (!addresses || addresses.length === 0) {
|
|
8672
|
+
return;
|
|
8673
|
+
}
|
|
8674
|
+
const queryClient = BaseQueryClient.getQueryClient();
|
|
8675
|
+
const easClient = BaseEasClient.getEasClient();
|
|
8676
|
+
const filesMetadataQueryKey = ['getFilesMetadata', ...addresses];
|
|
8677
|
+
const fetchFilesMetadata = () => easClient.request(GET_FILES_METADATA, {
|
|
8678
|
+
where: {
|
|
8679
|
+
attester: {
|
|
8680
|
+
in: addresses,
|
|
8681
|
+
},
|
|
8682
|
+
schema: {
|
|
8683
|
+
is: {
|
|
8684
|
+
id: {
|
|
8685
|
+
equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
|
|
8686
|
+
},
|
|
8687
|
+
},
|
|
8688
|
+
},
|
|
8689
|
+
},
|
|
8690
|
+
});
|
|
8691
|
+
let { filesMetadata } = await queryClient.fetchQuery({
|
|
8692
|
+
queryKey: filesMetadataQueryKey,
|
|
8693
|
+
queryFn: fetchFilesMetadata,
|
|
8694
|
+
staleTime: GET_FILES_METADATA_STALE_MS,
|
|
8695
|
+
});
|
|
8696
|
+
if ((!Array.isArray(filesMetadata) || filesMetadata.length === 0) && addresses.length > 0) {
|
|
8697
|
+
await queryClient.removeQueries({ queryKey: filesMetadataQueryKey });
|
|
8698
|
+
({ filesMetadata } = await queryClient.fetchQuery({
|
|
8699
|
+
queryKey: filesMetadataQueryKey,
|
|
8700
|
+
queryFn: fetchFilesMetadata,
|
|
8701
|
+
staleTime: GET_FILES_METADATA_STALE_MS,
|
|
8702
|
+
}));
|
|
8703
|
+
}
|
|
8704
|
+
const filesRoot = BaseFileManager.getWorkingDir();
|
|
8705
|
+
await BaseFileManager.createDirIfNotExists(filesRoot);
|
|
8706
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
|
|
8707
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
|
|
8708
|
+
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
|
|
8709
|
+
const excludedTransactions = await getExcludedTransactions();
|
|
8710
|
+
const fromEas = parseTransactionIdsFromMetadata(filesMetadata ?? [], excludedTransactions);
|
|
8711
|
+
const fromLocal = await collectTransactionIdsFromLocalMetadata();
|
|
8712
|
+
const transactionIds = Array.from(new Set([...fromEas, ...fromLocal]));
|
|
8713
|
+
await runBulkDownloadWithDedupe(transactionIds);
|
|
8714
|
+
};
|
|
8715
|
+
const downloadTransactionIdWithDedupe = async (transactionId) => {
|
|
8716
|
+
if (!supportsOpfsFileDownloads() || !transactionId || transactionId.trim().length === 0) {
|
|
8717
|
+
return false;
|
|
8718
|
+
}
|
|
8719
|
+
const normalizedTxId = normalizeArweaveTxId(transactionId) ?? transactionId.trim();
|
|
8720
|
+
const existing = lazyDownloadInFlightByTransactionId.get(normalizedTxId);
|
|
8721
|
+
if (existing) {
|
|
8722
|
+
return existing;
|
|
8723
|
+
}
|
|
8724
|
+
const inFlight = (async () => {
|
|
8725
|
+
try {
|
|
8726
|
+
const ok = await downloadTransactionIds([normalizedTxId], { resizeAllImages: false });
|
|
8727
|
+
return ok;
|
|
8728
|
+
}
|
|
8729
|
+
finally {
|
|
8730
|
+
lazyDownloadInFlightByTransactionId.delete(normalizedTxId);
|
|
8731
|
+
}
|
|
8732
|
+
})();
|
|
8733
|
+
lazyDownloadInFlightByTransactionId.set(normalizedTxId, inFlight);
|
|
8734
|
+
return inFlight;
|
|
8735
|
+
};
|
|
8736
|
+
const scheduleBulkFilesDownloadFromEasSyncThrottled = throttle((addressesHint) => {
|
|
8737
|
+
void downloadAllFilesBinaryRequestHandler(addressesHint).catch((error) => {
|
|
8738
|
+
logger$g('[scheduleBulkFilesDownloadFromEasSync] failed', error);
|
|
8739
|
+
});
|
|
8740
|
+
}, AUTO_BULK_DOWNLOAD_THROTTLE_MS, { leading: true, trailing: false });
|
|
8741
|
+
const scheduleBulkFilesDownloadFromEasSync = (addressesHint) => {
|
|
8742
|
+
if (!supportsOpfsFileDownloads()) {
|
|
8743
|
+
return;
|
|
8744
|
+
}
|
|
8745
|
+
scheduleBulkFilesDownloadFromEasSyncThrottled(addressesHint);
|
|
8746
|
+
};
|
|
8747
|
+
|
|
8748
|
+
var download = /*#__PURE__*/Object.freeze({
|
|
8749
|
+
__proto__: null,
|
|
8750
|
+
downloadAllFilesBinaryRequestHandler: downloadAllFilesBinaryRequestHandler,
|
|
8751
|
+
downloadAllFilesRequestHandler: downloadAllFilesRequestHandler,
|
|
8752
|
+
downloadTransactionIdWithDedupe: downloadTransactionIdWithDedupe,
|
|
8753
|
+
scheduleBulkFilesDownloadFromEasSync: scheduleBulkFilesDownloadFromEasSync
|
|
8754
|
+
});
|
|
8755
|
+
|
|
8756
|
+
/** Published storage seeds use `0x` + 64 hex; `saveHtml` still writes `html/{localId}.html`. */
|
|
8757
|
+
const SEED_UID_HEX_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
8758
|
+
/** Arweave L1 transaction ids are 43 URL-safe base64 characters. */
|
|
8759
|
+
const ARWEAVE_TX_ID_IN_STRING_RE = /[a-z0-9_-]{43}/i;
|
|
8760
|
+
function extractArweaveTransactionId(raw) {
|
|
8761
|
+
const t = raw.trim();
|
|
8762
|
+
const embedded = t.match(ARWEAVE_TX_ID_IN_STRING_RE);
|
|
8763
|
+
if (embedded && /^[a-z0-9_-]{43}$/i.test(embedded[0])) {
|
|
8764
|
+
return embedded[0];
|
|
8765
|
+
}
|
|
8766
|
+
return t;
|
|
8767
|
+
}
|
|
8768
|
+
/**
|
|
8769
|
+
* GET /raw/{txId} on each configured gateway. Avoids arweave.js /tx/.../offset which often 404s on
|
|
8770
|
+
* arweave.net while another gateway (e.g. ar.seedprotocol.io) still serves the data.
|
|
8771
|
+
*/
|
|
8772
|
+
async function fetchHtmlViaRawAcrossGateways(txId) {
|
|
8773
|
+
const id = extractArweaveTransactionId(txId);
|
|
8774
|
+
if (!id || SEED_UID_HEX_RE.test(id))
|
|
8775
|
+
return undefined;
|
|
8776
|
+
try {
|
|
8777
|
+
const { ensureReadGatewaySelected } = await Promise.resolve().then(function () { return selectReadGateway; });
|
|
8778
|
+
await ensureReadGatewaySelected().catch(() => { });
|
|
8779
|
+
}
|
|
8780
|
+
catch {
|
|
8781
|
+
/* optional */
|
|
8782
|
+
}
|
|
8783
|
+
const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
|
|
8784
|
+
const protocol = BaseArweaveClient.getProtocol();
|
|
8785
|
+
const hosts = mergePrimaryHostWithDefaults(BaseArweaveClient.getHost(), getDefaultArweaveReadGatewayHostsOrdered());
|
|
8786
|
+
for (const host of hosts) {
|
|
8787
|
+
const h = host.trim().replace(/\/$/, '');
|
|
8788
|
+
if (!h)
|
|
8789
|
+
continue;
|
|
8790
|
+
const url = `${protocol}://${h}/raw/${encodeURIComponent(id)}`;
|
|
8791
|
+
try {
|
|
8792
|
+
const res = await fetch(url, { method: 'GET', credentials: 'omit' });
|
|
8793
|
+
if (!res.ok)
|
|
8794
|
+
continue;
|
|
8795
|
+
const text = await res.text();
|
|
8796
|
+
if (typeof text === 'string' && text.length > 0) {
|
|
8797
|
+
return text;
|
|
8798
|
+
}
|
|
8799
|
+
}
|
|
8800
|
+
catch {
|
|
8801
|
+
/* next gateway */
|
|
8802
|
+
}
|
|
8803
|
+
}
|
|
8804
|
+
return undefined;
|
|
8805
|
+
}
|
|
8806
|
+
/**
|
|
8807
|
+
* Resolve the Html storage seed's `local_id` used for the `{localId}.html` file name.
|
|
8808
|
+
* `propertyValue` on the parent Html property is either that local id or the seed uid after publish.
|
|
8809
|
+
*/
|
|
8810
|
+
async function resolveHtmlStorageSeedLocalId(propertyValue) {
|
|
8811
|
+
const pv = String(propertyValue ?? '').trim();
|
|
8812
|
+
if (!pv)
|
|
8813
|
+
return undefined;
|
|
8814
|
+
if (SEED_UID_HEX_RE.test(pv)) {
|
|
8815
|
+
const { getSeedData } = await Promise.resolve().then(function () { return getSeedData$1; });
|
|
8816
|
+
return (await getSeedData({ seedUid: pv }))?.localId ?? undefined;
|
|
8817
|
+
}
|
|
8818
|
+
return pv;
|
|
8819
|
+
}
|
|
8820
|
+
/**
|
|
8821
|
+
* When the local draft file is gone (new device, OPFS cleared, etc.), load HTML from the
|
|
8822
|
+
* Html storage seed's published Arweave transaction id on that child seed.
|
|
8823
|
+
*/
|
|
8824
|
+
async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
|
|
8825
|
+
const { getPropertyData } = await Promise.resolve().then(function () { return getPropertyData$1; });
|
|
8826
|
+
const pickTx = async (name) => {
|
|
8827
|
+
const row = await getPropertyData({ propertyName: name, seedLocalId });
|
|
8828
|
+
const v = row?.propertyValue != null ? String(row.propertyValue).trim() : '';
|
|
8829
|
+
return v || undefined;
|
|
8830
|
+
};
|
|
8831
|
+
const txId = (await pickTx('storageTransactionId')) ??
|
|
8832
|
+
(await pickTx('transactionId')) ??
|
|
8833
|
+
(await pickTx('storage_transaction_id'));
|
|
8834
|
+
if (!txId || SEED_UID_HEX_RE.test(txId)) {
|
|
8835
|
+
return { txIdLen: 0, gatewayStringLen: 0 };
|
|
8836
|
+
}
|
|
8837
|
+
const rawHtml = await fetchHtmlViaRawAcrossGateways(txId);
|
|
8838
|
+
if (rawHtml && rawHtml.length > 0) {
|
|
8839
|
+
return { body: rawHtml, txIdLen: txId.length, gatewayStringLen: rawHtml.length };
|
|
8840
|
+
}
|
|
8841
|
+
try {
|
|
8842
|
+
const { BaseArweaveClient } = await Promise.resolve().then(function () { return BaseArweaveClient$1; });
|
|
8843
|
+
const data = await BaseArweaveClient.getTransactionData(extractArweaveTransactionId(txId), {
|
|
8844
|
+
string: true,
|
|
8845
|
+
});
|
|
8846
|
+
if (typeof data === 'string' && data.length > 0) {
|
|
8847
|
+
return { body: data, txIdLen: txId.length, gatewayStringLen: data.length };
|
|
8848
|
+
}
|
|
8849
|
+
}
|
|
8850
|
+
catch {
|
|
8851
|
+
/* offline / bad tx id */
|
|
8852
|
+
}
|
|
8853
|
+
try {
|
|
8854
|
+
const { downloadTransactionIdWithDedupe } = await Promise.resolve().then(function () { return download; });
|
|
8855
|
+
await downloadTransactionIdWithDedupe(txId);
|
|
8856
|
+
const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
|
|
8857
|
+
if (await BaseFileManager.pathExists(retryFp)) {
|
|
8858
|
+
const s = await BaseFileManager.readFileAsString(retryFp);
|
|
8859
|
+
return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8860
|
+
}
|
|
8861
|
+
const dirPath = BaseFileManager.getFilesPath('html');
|
|
8862
|
+
if (await BaseFileManager.pathExists(dirPath)) {
|
|
8863
|
+
const fs = await BaseFileManager.getFs();
|
|
8864
|
+
const pathMod = BaseFileManager.getPathModule();
|
|
8865
|
+
const files = await fs.promises.readdir(dirPath);
|
|
8866
|
+
const needle = txId.replace(/\.[^/.]+$/, '');
|
|
8867
|
+
const match = files.find((f) => f.includes(seedLocalId) || f.includes(needle) || (needle.length >= 20 && f.includes(needle.slice(0, 20))));
|
|
8868
|
+
if (match) {
|
|
8869
|
+
const s = await BaseFileManager.readFileAsString(pathMod.join(dirPath, match));
|
|
8870
|
+
return { body: s, txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8871
|
+
}
|
|
8872
|
+
}
|
|
8873
|
+
}
|
|
8874
|
+
catch {
|
|
8875
|
+
/* OPFS unsupported or download failed */
|
|
8876
|
+
}
|
|
8877
|
+
return { txIdLen: txId.length, gatewayStringLen: 0 };
|
|
8878
|
+
}
|
|
8879
|
+
/** Read saved HTML body for a parent Html property whose `propertyValue` points at the Html storage seed. */
|
|
8880
|
+
async function readHtmlBodyForStorageSeedPropertyValue(propertyValue) {
|
|
8881
|
+
const pv = String(propertyValue ?? '').trim();
|
|
8882
|
+
if (!pv)
|
|
8883
|
+
return undefined;
|
|
8884
|
+
const localId = await resolveHtmlStorageSeedLocalId(propertyValue);
|
|
8885
|
+
const fp = localId ? BaseFileManager.getFilesPath('html', `${localId}.html`) : '';
|
|
8886
|
+
let fileExists = fp ? await BaseFileManager.pathExists(fp) : false;
|
|
8887
|
+
// OPFS: file can appear shortly after create/download; avoid false "missing" before hitting Arweave.
|
|
8888
|
+
if (!fileExists && fp) {
|
|
8889
|
+
await BaseFileManager.waitForFileWithContent(fp, 100, 5000).catch(() => { });
|
|
8890
|
+
fileExists = await BaseFileManager.pathExists(fp);
|
|
8891
|
+
}
|
|
8892
|
+
let body = fileExists && fp ? await BaseFileManager.readFileAsString(fp) : undefined;
|
|
8893
|
+
if (!body && localId) {
|
|
8894
|
+
const ar = await readHtmlBodyFromChildStorageArweave(localId);
|
|
8895
|
+
body = ar.body;
|
|
8896
|
+
}
|
|
8897
|
+
return body;
|
|
8898
|
+
}
|
|
8899
|
+
|
|
8900
|
+
// Dynamic import to break circular dependency: schema/index -> ... -> hydrateFromDb -> schema/index
|
|
8901
|
+
// import { ModelPropertyDataTypes } from '@/schema'
|
|
8902
|
+
const logger$f = debug('seedSdk:property:actors:hydrateFromDb');
|
|
8903
|
+
const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
8904
|
+
const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyRecordSchema, modelName, } = context;
|
|
8905
|
+
if (!propertyNameRaw) {
|
|
8906
|
+
throw new Error('propertyName is required');
|
|
8907
|
+
}
|
|
8908
|
+
let propertyName = propertyNameRaw;
|
|
8909
|
+
// Note: isRelation, isImage, isFile checks moved inside async function
|
|
8910
|
+
// to use dynamically imported ModelPropertyDataTypes
|
|
8911
|
+
const _hydrateFromDb = async () => {
|
|
8912
|
+
// Use dynamic import to break circular dependency
|
|
8913
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
8914
|
+
const { ModelPropertyDataTypes } = schemaMod;
|
|
8915
|
+
const appDb = BaseDb.getAppDb();
|
|
8916
|
+
const whereClauses = [];
|
|
8917
|
+
// Re-check types with dynamically imported ModelPropertyDataTypes
|
|
8918
|
+
// Use normalizeDataType for case-insensitive comparison (schema may use "image" vs "Image")
|
|
8919
|
+
const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
|
|
8920
|
+
const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
|
|
8921
|
+
propertyRecordSchema &&
|
|
8922
|
+
propertyRecordSchema.ref &&
|
|
8923
|
+
normalizedDataType === ModelPropertyDataTypes.Relation;
|
|
8924
|
+
const isImageDynamic = propertyRecordSchema &&
|
|
8925
|
+
(normalizedDataType === ModelPropertyDataTypes.Image ||
|
|
8926
|
+
normalizedRefValueType === ModelPropertyDataTypes.Image);
|
|
8927
|
+
const isFileDynamic = propertyRecordSchema &&
|
|
8928
|
+
normalizedDataType === ModelPropertyDataTypes.File;
|
|
8929
|
+
const isHtmlDynamic = propertyRecordSchema &&
|
|
8930
|
+
normalizedDataType === ModelPropertyDataTypes.Html;
|
|
8931
|
+
// Html/Image/File/Relation store metadata with Id suffix (e.g. htmlId); query both variants
|
|
8932
|
+
const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
|
|
8933
|
+
whereClauses.push(propertyNames.length > 1
|
|
8934
|
+
? or(...propertyNames.map((n) => eq(metadata$1.propertyName, n)))
|
|
8935
|
+
: eq(metadata$1.propertyName, propertyNames[0]));
|
|
8936
|
+
// Draft rows often have only seed_local_id populated; on-chain rows may have uid.
|
|
8937
|
+
// Requiring both with AND misses valid metadata when only one column is set.
|
|
8938
|
+
if (seedUid && seedLocalId) {
|
|
8939
|
+
whereClauses.push(or(eq(metadata$1.seedLocalId, seedLocalId), eq(metadata$1.seedUid, seedUid)));
|
|
8940
|
+
}
|
|
8941
|
+
else if (seedUid) {
|
|
8942
|
+
whereClauses.push(eq(metadata$1.seedUid, seedUid));
|
|
8943
|
+
}
|
|
8944
|
+
else if (seedLocalId) {
|
|
8945
|
+
whereClauses.push(eq(metadata$1.seedLocalId, seedLocalId));
|
|
8946
|
+
}
|
|
8947
|
+
const rows = await appDb
|
|
8948
|
+
.select()
|
|
8949
|
+
.from(metadata$1)
|
|
8950
|
+
.where(and(...whereClauses))
|
|
8951
|
+
.orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC'));
|
|
8952
|
+
if (!rows || !rows.length) {
|
|
8953
|
+
return;
|
|
8954
|
+
}
|
|
8955
|
+
const firstRow = rows[0];
|
|
8956
|
+
const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, versionLocalId: versionLocalIdFromDb, versionUid: versionUidFromDb, refValueType, } = firstRow;
|
|
8957
|
+
let { refResolvedDisplayValue, refResolvedValue, localStorageDir } = firstRow;
|
|
8958
|
+
let propertyValueProcessed = propertyValueFromDb;
|
|
8959
|
+
let renderValue = refResolvedDisplayValue ?? undefined;
|
|
8960
|
+
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
8961
|
+
if (isImageDynamic) {
|
|
8962
|
+
let dir = localStorageDir;
|
|
8963
|
+
if (!dir && isImageDynamic) {
|
|
8964
|
+
dir = 'images';
|
|
8965
|
+
}
|
|
8966
|
+
dir = dir.replace(/^\//, '');
|
|
8967
|
+
if (propertyValueFromDb &&
|
|
8968
|
+
propertyValueFromDb.length === 66) {
|
|
8969
|
+
// Here the storageTransactionId is stored on a different record and
|
|
8970
|
+
// we want to add it as the refResolvedValue
|
|
8971
|
+
const storageTransactionQuery = await appDb
|
|
8972
|
+
.select({
|
|
8973
|
+
propertyValue: metadata$1.propertyValue,
|
|
8974
|
+
})
|
|
8975
|
+
.from(metadata$1)
|
|
8976
|
+
.where(and(eq(metadata$1.seedUid, propertyValueFromDb), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))));
|
|
8977
|
+
if (storageTransactionQuery && storageTransactionQuery.length > 0) {
|
|
8978
|
+
const row = storageTransactionQuery[0];
|
|
8979
|
+
refResolvedValue = row.propertyValue;
|
|
8980
|
+
await updateMetadata({
|
|
8981
|
+
localId,
|
|
8982
|
+
refResolvedValue,
|
|
8983
|
+
localStorageDir: '/images',
|
|
8984
|
+
});
|
|
8985
|
+
}
|
|
8986
|
+
}
|
|
8987
|
+
const resolveMatchingFilePath = async (dir, needle) => {
|
|
8988
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
8989
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
8990
|
+
if (!dirExists)
|
|
8991
|
+
return undefined;
|
|
8992
|
+
const fs = await BaseFileManager.getFs();
|
|
8993
|
+
const path = BaseFileManager.getPathModule();
|
|
8994
|
+
const files = await fs.promises.readdir(dirPath);
|
|
8995
|
+
const matchingFiles = files.filter((file) => {
|
|
8996
|
+
return path.basename(file).includes(needle);
|
|
8997
|
+
});
|
|
8998
|
+
if (!matchingFiles?.length)
|
|
8999
|
+
return undefined;
|
|
9000
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9001
|
+
};
|
|
9002
|
+
if (refResolvedValue) {
|
|
9003
|
+
try {
|
|
9004
|
+
let filePath = await resolveMatchingFilePath(dir, refResolvedValue);
|
|
9005
|
+
if (!filePath) {
|
|
9006
|
+
await downloadTransactionIdWithDedupe(refResolvedValue);
|
|
9007
|
+
filePath = await resolveMatchingFilePath(dir, refResolvedValue);
|
|
9008
|
+
}
|
|
9009
|
+
localStorageDir = `/${dir}`;
|
|
9010
|
+
if (filePath) {
|
|
9011
|
+
const file = await BaseFileManager.readFile(filePath);
|
|
9012
|
+
refResolvedDisplayValue = URL.createObjectURL(file);
|
|
9013
|
+
renderValue = refResolvedDisplayValue;
|
|
9014
|
+
// Do not persist blob URL - it is session-scoped
|
|
9015
|
+
}
|
|
9016
|
+
}
|
|
9017
|
+
catch (e) {
|
|
9018
|
+
logger$f('[hydrateFromDb] Image file resolution error', e);
|
|
9019
|
+
}
|
|
9020
|
+
}
|
|
9021
|
+
}
|
|
9022
|
+
if (isFileDynamic && refResolvedValue) {
|
|
9023
|
+
try {
|
|
9024
|
+
const dir = (localStorageDir ?? '/files').replace(/^\//, '');
|
|
9025
|
+
const resolveMatchingFilePath = async (needle) => {
|
|
9026
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9027
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9028
|
+
if (!dirExists)
|
|
9029
|
+
return undefined;
|
|
9030
|
+
const fs = await BaseFileManager.getFs();
|
|
9031
|
+
const path = BaseFileManager.getPathModule();
|
|
9032
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9033
|
+
const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
|
|
9034
|
+
if (!matchingFiles?.length)
|
|
9035
|
+
return undefined;
|
|
9036
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9037
|
+
};
|
|
9038
|
+
let filePath = await resolveMatchingFilePath(refResolvedValue);
|
|
9039
|
+
if (!filePath) {
|
|
9040
|
+
await downloadTransactionIdWithDedupe(refResolvedValue);
|
|
9041
|
+
filePath = await resolveMatchingFilePath(refResolvedValue);
|
|
9042
|
+
}
|
|
9043
|
+
if (filePath) {
|
|
9044
|
+
localStorageDir = `/${dir}`;
|
|
9045
|
+
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
9046
|
+
}
|
|
9047
|
+
}
|
|
9048
|
+
catch (e) {
|
|
9049
|
+
logger$f('[hydrateFromDb] File resolution error', e);
|
|
9050
|
+
}
|
|
9051
|
+
}
|
|
9052
|
+
if (propertyRecordSchema &&
|
|
9053
|
+
normalizedDataType === ModelPropertyDataTypes.List &&
|
|
9054
|
+
typeof propertyValueFromDb === 'string') {
|
|
9055
|
+
propertyValueProcessed = parseListPropertyValueFromStorage(propertyValueFromDb);
|
|
9056
|
+
}
|
|
9057
|
+
sendBack({
|
|
9058
|
+
type: 'updateContext',
|
|
9059
|
+
localId,
|
|
9060
|
+
uid,
|
|
9061
|
+
propertyValue: propertyValueProcessed,
|
|
9062
|
+
seedLocalId: seedLocalIdFromDb,
|
|
9063
|
+
seedUid: seedUidFromDb,
|
|
9064
|
+
versionLocalId: versionLocalIdFromDb,
|
|
9065
|
+
versionUid: versionUidFromDb,
|
|
9066
|
+
schemaUid: schemaUidFromDb,
|
|
9067
|
+
refValueType,
|
|
9068
|
+
localStorageDir,
|
|
9069
|
+
refResolvedValue,
|
|
9070
|
+
refResolvedDisplayValue,
|
|
9071
|
+
renderValue,
|
|
9072
|
+
populatedFromDb: true,
|
|
9073
|
+
});
|
|
9074
|
+
if (propertyRecordSchema &&
|
|
9075
|
+
propertyRecordSchema.storageType &&
|
|
9076
|
+
propertyRecordSchema.storageType === 'ItemStorage') {
|
|
9077
|
+
const itemMod = await Promise.resolve().then(function () { return Item$1; });
|
|
9078
|
+
const { Item } = itemMod;
|
|
9079
|
+
const item = await Item.find({
|
|
9080
|
+
seedLocalId: seedLocalId ?? undefined,
|
|
9081
|
+
modelName,
|
|
9082
|
+
});
|
|
8153
9083
|
if (item) {
|
|
8154
9084
|
const dir = localStorageDir?.replace(/^\//, '') || 'files';
|
|
8155
9085
|
const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
|
|
@@ -8165,15 +9095,34 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
8165
9095
|
return;
|
|
8166
9096
|
}
|
|
8167
9097
|
}
|
|
8168
|
-
// Html: read file content for renderValue (blob URLs from DB are invalid after reload)
|
|
8169
|
-
//
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
if (
|
|
8176
|
-
const
|
|
9098
|
+
// Html: read file content for renderValue (blob URLs from DB are invalid after reload).
|
|
9099
|
+
// When propertyValue is the Html storage seed uid, resolve localId and read `html/{localId}.html`.
|
|
9100
|
+
if (isHtmlDynamic) {
|
|
9101
|
+
const htmlLocalStorageDir = refResolvedValue && !localStorageDir ? '/html' : localStorageDir ?? '/html';
|
|
9102
|
+
let htmlContent;
|
|
9103
|
+
let outRef = refResolvedValue;
|
|
9104
|
+
let outDir = htmlLocalStorageDir;
|
|
9105
|
+
if (refResolvedValue && htmlLocalStorageDir) {
|
|
9106
|
+
const dir = htmlLocalStorageDir.replace(/^\//, '');
|
|
9107
|
+
const filePath = BaseFileManager.getFilesPath(dir, refResolvedValue);
|
|
9108
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
9109
|
+
if (!exists) {
|
|
9110
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
9111
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
9112
|
+
}
|
|
9113
|
+
if (exists) {
|
|
9114
|
+
htmlContent = await BaseFileManager.readFileAsString(filePath);
|
|
9115
|
+
}
|
|
9116
|
+
}
|
|
9117
|
+
if (!htmlContent && propertyValueFromDb) {
|
|
9118
|
+
htmlContent = await readHtmlBodyForStorageSeedPropertyValue(propertyValueFromDb);
|
|
9119
|
+
const lid = await resolveHtmlStorageSeedLocalId(String(propertyValueFromDb));
|
|
9120
|
+
if (lid) {
|
|
9121
|
+
outRef = `${lid}.html`;
|
|
9122
|
+
outDir = '/html';
|
|
9123
|
+
}
|
|
9124
|
+
}
|
|
9125
|
+
if (htmlContent) {
|
|
8177
9126
|
sendBack({
|
|
8178
9127
|
type: 'updateContext',
|
|
8179
9128
|
localId,
|
|
@@ -8185,8 +9134,8 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
8185
9134
|
versionUid: versionUidFromDb,
|
|
8186
9135
|
schemaUid: schemaUidFromDb,
|
|
8187
9136
|
refValueType,
|
|
8188
|
-
localStorageDir:
|
|
8189
|
-
refResolvedValue,
|
|
9137
|
+
localStorageDir: outDir,
|
|
9138
|
+
refResolvedValue: outRef ?? refResolvedValue,
|
|
8190
9139
|
refResolvedDisplayValue,
|
|
8191
9140
|
renderValue: htmlContent,
|
|
8192
9141
|
populatedFromDb: true,
|
|
@@ -8200,11 +9149,11 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
8200
9149
|
});
|
|
8201
9150
|
});
|
|
8202
9151
|
|
|
8203
|
-
const logger$
|
|
9152
|
+
const logger$e = debug('seedSdk:itemProperty:actors:loadOrCreateProperty');
|
|
8204
9153
|
const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) => {
|
|
8205
9154
|
const _loadOrCreateProperty = async () => {
|
|
8206
9155
|
const { seedLocalId, seedUid, propertyName, versionLocalId } = context;
|
|
8207
|
-
logger$
|
|
9156
|
+
logger$e(`loadOrCreateProperty called for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}, seedUid: ${seedUid}`);
|
|
8208
9157
|
if (!seedLocalId && !seedUid) {
|
|
8209
9158
|
throw new Error('seedLocalId or seedUid is required');
|
|
8210
9159
|
}
|
|
@@ -8250,15 +9199,15 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8250
9199
|
const schemas = modelPropertiesToObject(model$1.properties);
|
|
8251
9200
|
propertyRecordSchema = schemas[propertyName];
|
|
8252
9201
|
if (propertyRecordSchema) {
|
|
8253
|
-
logger$
|
|
9202
|
+
logger$e(`Metadata not found: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
|
|
8254
9203
|
}
|
|
8255
9204
|
}
|
|
8256
9205
|
}
|
|
8257
9206
|
catch (error) {
|
|
8258
|
-
logger$
|
|
9207
|
+
logger$e(`Metadata not found: Model fallback failed for propertyName "${propertyName}": ${error}`);
|
|
8259
9208
|
}
|
|
8260
9209
|
}
|
|
8261
|
-
logger$
|
|
9210
|
+
logger$e(`Metadata not found in database for propertyName: ${propertyName}, seedLocalId: ${seedLocalId}`);
|
|
8262
9211
|
sendBack({
|
|
8263
9212
|
type: 'loadOrCreatePropertySuccess',
|
|
8264
9213
|
property: {
|
|
@@ -8324,7 +9273,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8324
9273
|
};
|
|
8325
9274
|
// Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
|
|
8326
9275
|
try {
|
|
8327
|
-
const { getPropertySchema } = await import('./property-
|
|
9276
|
+
const { getPropertySchema } = await import('./property-BSNWvgei.js');
|
|
8328
9277
|
let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName);
|
|
8329
9278
|
if (!schemaFromFile?.validation) {
|
|
8330
9279
|
// Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
|
|
@@ -8362,7 +9311,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8362
9311
|
}
|
|
8363
9312
|
}
|
|
8364
9313
|
catch (error) {
|
|
8365
|
-
logger$
|
|
9314
|
+
logger$e(`Error loading propertyRecordSchema from database: ${error}`);
|
|
8366
9315
|
// Continue without propertyRecordSchema
|
|
8367
9316
|
}
|
|
8368
9317
|
}
|
|
@@ -8380,22 +9329,27 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8380
9329
|
const schemas = modelPropertiesToObject(model$1.properties);
|
|
8381
9330
|
propertyRecordSchema = schemas[propertyName];
|
|
8382
9331
|
if (propertyRecordSchema) {
|
|
8383
|
-
logger$
|
|
9332
|
+
logger$e(`Fallback: loaded propertyRecordSchema from Model for propertyName "${propertyName}"`);
|
|
8384
9333
|
}
|
|
8385
9334
|
}
|
|
8386
9335
|
}
|
|
8387
9336
|
catch (error) {
|
|
8388
|
-
logger$
|
|
9337
|
+
logger$e(`Fallback Model lookup failed for propertyName "${propertyName}": ${error}`);
|
|
8389
9338
|
}
|
|
8390
9339
|
}
|
|
8391
9340
|
// For Html: read file content for renderValue (propertyValue is seed ID; blob URLs in DB are invalid after reload)
|
|
8392
9341
|
let renderValue = metadataRecord.propertyValue || undefined;
|
|
8393
9342
|
const refSeedType = metadataRecord.refSeedType;
|
|
8394
|
-
const
|
|
8395
|
-
|
|
9343
|
+
const normalizedHtmlDt = normalizeDataType(propertyRecordSchema?.dataType);
|
|
9344
|
+
const isHtml = refSeedType === 'html' || normalizedHtmlDt === ModelPropertyDataTypes.Html;
|
|
9345
|
+
// Fallback: derive refResolvedValue/localStorageDir from propertyValue when missing (e.g. EAS sync, legacy data).
|
|
9346
|
+
// After publish, propertyValue may be the Html storage seed uid while files stay named `{localId}.html`.
|
|
8396
9347
|
if (isHtml && !metadataRecord.refResolvedValue && metadataRecord.propertyValue) {
|
|
8397
|
-
|
|
8398
|
-
|
|
9348
|
+
const lid = await resolveHtmlStorageSeedLocalId(metadataRecord.propertyValue);
|
|
9349
|
+
if (lid) {
|
|
9350
|
+
metadataRecord.refResolvedValue = `${lid}.html`;
|
|
9351
|
+
metadataRecord.localStorageDir = '/html';
|
|
9352
|
+
}
|
|
8399
9353
|
}
|
|
8400
9354
|
// Fallback: when Html has refResolvedValue but localStorageDir is null (e.g. EAS sync, legacy records)
|
|
8401
9355
|
if (isHtml && metadataRecord.refResolvedValue && !metadataRecord.localStorageDir) {
|
|
@@ -8405,13 +9359,34 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8405
9359
|
try {
|
|
8406
9360
|
const dir = metadataRecord.localStorageDir.replace(/^\//, '');
|
|
8407
9361
|
const filePath = BaseFileManager.getFilesPath(dir, metadataRecord.refResolvedValue);
|
|
8408
|
-
|
|
9362
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
9363
|
+
if (!exists) {
|
|
9364
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
9365
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
9366
|
+
}
|
|
8409
9367
|
if (exists) {
|
|
8410
9368
|
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
8411
9369
|
}
|
|
9370
|
+
else {
|
|
9371
|
+
const viaSeedPointer = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
|
|
9372
|
+
if (viaSeedPointer) {
|
|
9373
|
+
renderValue = viaSeedPointer;
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
8412
9376
|
}
|
|
8413
9377
|
catch (e) {
|
|
8414
|
-
logger$
|
|
9378
|
+
logger$e(`Failed to read Html file for ${propertyName}: ${e}`);
|
|
9379
|
+
}
|
|
9380
|
+
}
|
|
9381
|
+
// Covers missing ref row, wrong ref, or DB dataType casing "html" (handled by isHtml above).
|
|
9382
|
+
if (isHtml && metadataRecord.propertyValue) {
|
|
9383
|
+
const pv = String(metadataRecord.propertyValue).trim();
|
|
9384
|
+
const rv = typeof renderValue === 'string' ? renderValue.trim() : '';
|
|
9385
|
+
if (!rv || rv === pv) {
|
|
9386
|
+
const recovered = await readHtmlBodyForStorageSeedPropertyValue(metadataRecord.propertyValue);
|
|
9387
|
+
if (recovered) {
|
|
9388
|
+
renderValue = recovered;
|
|
9389
|
+
}
|
|
8415
9390
|
}
|
|
8416
9391
|
}
|
|
8417
9392
|
// Image: always resolve display value from file (blob URLs in DB are invalid after reload)
|
|
@@ -8421,28 +9396,83 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8421
9396
|
const isImage = refSeedType === 'image' ||
|
|
8422
9397
|
normalizedDataType === 'Image' ||
|
|
8423
9398
|
normalizedRefValueType === 'Image';
|
|
9399
|
+
const resolveMatchingFilePath = async (dir, needle) => {
|
|
9400
|
+
const dirPath = BaseFileManager.getFilesPath(dir);
|
|
9401
|
+
const dirExists = await BaseFileManager.pathExists(dirPath);
|
|
9402
|
+
if (!dirExists)
|
|
9403
|
+
return undefined;
|
|
9404
|
+
const fs = await BaseFileManager.getFs();
|
|
9405
|
+
const path = BaseFileManager.getPathModule();
|
|
9406
|
+
const files = await fs.promises.readdir(dirPath);
|
|
9407
|
+
const matchingFiles = files.filter((file) => path.basename(file).includes(needle));
|
|
9408
|
+
if (!matchingFiles?.length)
|
|
9409
|
+
return undefined;
|
|
9410
|
+
return BaseFileManager.getFilesPath(dir, matchingFiles[0]);
|
|
9411
|
+
};
|
|
9412
|
+
// EAS-synced rows: parent metadata stores the image seed uid in property_value; filename/Arweave id is on the image seed's metadata.
|
|
9413
|
+
// hydrateFromDb already repairs this; doing it here avoids a multi-second gap where UI shows a non-blob value until rehydrate runs.
|
|
9414
|
+
if (isImage &&
|
|
9415
|
+
!metadataRecord.refResolvedValue &&
|
|
9416
|
+
typeof metadataRecord.propertyValue === 'string' &&
|
|
9417
|
+
metadataRecord.propertyValue.length === 66) {
|
|
9418
|
+
const storageTxRows = await db
|
|
9419
|
+
.select({ propertyValue: metadata$1.propertyValue })
|
|
9420
|
+
.from(metadata$1)
|
|
9421
|
+
.where(and(eq(metadata$1.seedUid, metadataRecord.propertyValue), or(eq(metadata$1.propertyName, 'storageTransactionId'), eq(metadata$1.propertyName, 'transactionId'))))
|
|
9422
|
+
.limit(1);
|
|
9423
|
+
const derivedTxId = storageTxRows[0]?.propertyValue;
|
|
9424
|
+
if (derivedTxId) {
|
|
9425
|
+
metadataRecord.refResolvedValue = derivedTxId;
|
|
9426
|
+
metadataRecord.localStorageDir = metadataRecord.localStorageDir ?? '/images';
|
|
9427
|
+
if (metadataRecord.localId) {
|
|
9428
|
+
try {
|
|
9429
|
+
await updateMetadata({
|
|
9430
|
+
localId: metadataRecord.localId,
|
|
9431
|
+
refResolvedValue: derivedTxId,
|
|
9432
|
+
localStorageDir: '/images',
|
|
9433
|
+
});
|
|
9434
|
+
}
|
|
9435
|
+
catch (e) {
|
|
9436
|
+
logger$e(`loadOrCreateProperty: updateMetadata refResolvedValue failed for ${propertyName}:`, e);
|
|
9437
|
+
}
|
|
9438
|
+
}
|
|
9439
|
+
}
|
|
9440
|
+
}
|
|
8424
9441
|
if (isImage && metadataRecord.refResolvedValue) {
|
|
8425
9442
|
try {
|
|
8426
9443
|
const dir = (metadataRecord.localStorageDir ?? '/images').replace(/^\//, '');
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
const
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
9444
|
+
let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9445
|
+
if (!filePath) {
|
|
9446
|
+
await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
|
|
9447
|
+
filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9448
|
+
}
|
|
9449
|
+
if (filePath) {
|
|
9450
|
+
const file = await BaseFileManager.readFile(filePath);
|
|
9451
|
+
const freshBlobUrl = URL.createObjectURL(file);
|
|
9452
|
+
renderValue = freshBlobUrl;
|
|
9453
|
+
refResolvedDisplayValue = freshBlobUrl;
|
|
9454
|
+
}
|
|
9455
|
+
}
|
|
9456
|
+
catch (e) {
|
|
9457
|
+
logger$e(`Failed to resolve Image file for ${propertyName}: ${e}`);
|
|
9458
|
+
}
|
|
9459
|
+
}
|
|
9460
|
+
const isFile = refSeedType === 'file' ||
|
|
9461
|
+
normalizedDataType === 'File';
|
|
9462
|
+
if (isFile && metadataRecord.refResolvedValue) {
|
|
9463
|
+
try {
|
|
9464
|
+
const dir = (metadataRecord.localStorageDir ?? '/files').replace(/^\//, '');
|
|
9465
|
+
let filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9466
|
+
if (!filePath) {
|
|
9467
|
+
await downloadTransactionIdWithDedupe(metadataRecord.refResolvedValue);
|
|
9468
|
+
filePath = await resolveMatchingFilePath(dir, metadataRecord.refResolvedValue);
|
|
9469
|
+
}
|
|
9470
|
+
if (filePath) {
|
|
9471
|
+
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
8442
9472
|
}
|
|
8443
9473
|
}
|
|
8444
9474
|
catch (e) {
|
|
8445
|
-
logger$
|
|
9475
|
+
logger$e(`Failed to resolve File for ${propertyName}: ${e}`);
|
|
8446
9476
|
}
|
|
8447
9477
|
}
|
|
8448
9478
|
let propertyValueOut = metadataRecord.propertyValue || undefined;
|
|
@@ -8474,7 +9504,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
|
|
|
8474
9504
|
});
|
|
8475
9505
|
};
|
|
8476
9506
|
_loadOrCreateProperty().catch((error) => {
|
|
8477
|
-
logger$
|
|
9507
|
+
logger$e(`Error in loadOrCreateProperty: ${error}`);
|
|
8478
9508
|
sendBack({
|
|
8479
9509
|
type: 'loadOrCreatePropertyError',
|
|
8480
9510
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -8504,10 +9534,10 @@ const getVersionData = async ({ localId, seedLocalId, uid, }) => {
|
|
|
8504
9534
|
return queryRows[0];
|
|
8505
9535
|
};
|
|
8506
9536
|
|
|
8507
|
-
const logger$
|
|
9537
|
+
const logger$d = debug('seedSdk:write:updateItemPropertyValue');
|
|
8508
9538
|
const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, localStorageDir, dataType, refValueType, }) => {
|
|
8509
9539
|
if (!localIdParam && !seedLocalId) {
|
|
8510
|
-
logger$
|
|
9540
|
+
logger$d(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
|
|
8511
9541
|
return;
|
|
8512
9542
|
}
|
|
8513
9543
|
let safeNewValue = newValue;
|
|
@@ -8535,7 +9565,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8535
9565
|
.select()
|
|
8536
9566
|
.from(metadata$1)
|
|
8537
9567
|
.where(and(propertyNameWhere, eq(metadata$1.seedLocalId, seedLocalId)))
|
|
8538
|
-
.orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
|
|
9568
|
+
.orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
|
|
8539
9569
|
}
|
|
8540
9570
|
}
|
|
8541
9571
|
else if (localIdParam) {
|
|
@@ -8555,7 +9585,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8555
9585
|
.select()
|
|
8556
9586
|
.from(metadata$1)
|
|
8557
9587
|
.where(and(propertyNameWhere, eq(metadata$1.seedLocalId, seedLocalId)))
|
|
8558
|
-
.orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC')));
|
|
9588
|
+
.orderBy(sql.raw('COALESCE(attestation_created_at, created_at) DESC, local_id DESC')));
|
|
8559
9589
|
}
|
|
8560
9590
|
// const mostRecentRecordStatement = `SELECT local_id,
|
|
8561
9591
|
// uid,
|
|
@@ -8571,7 +9601,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8571
9601
|
// FROM metadata
|
|
8572
9602
|
// WHERE property_name = '${propertyName}'
|
|
8573
9603
|
// AND seed_local_id = '${seedLocalId}'
|
|
8574
|
-
// ORDER BY COALESCE(attestation_created_at, created_at) DESC;`
|
|
9604
|
+
// ORDER BY COALESCE(attestation_created_at, created_at) DESC, local_id DESC;`
|
|
8575
9605
|
//
|
|
8576
9606
|
// const { rows } = await runQueryForStatement(mostRecentRecordStatement)
|
|
8577
9607
|
if (rows && rows.length > 0) {
|
|
@@ -8580,7 +9610,7 @@ const updateItemPropertyValue = async ({ localId: localIdParam, propertyName, ne
|
|
|
8580
9610
|
modelType === modelName?.toLowerCase() &&
|
|
8581
9611
|
refSeedTypeFromDb === refSeedType &&
|
|
8582
9612
|
refResolvedValueFromDb === refResolvedValue) {
|
|
8583
|
-
logger$
|
|
9613
|
+
logger$d(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
|
|
8584
9614
|
return;
|
|
8585
9615
|
}
|
|
8586
9616
|
// This means we already have a local-only record so we should just update that one
|
|
@@ -8708,9 +9738,9 @@ const analyzeInput = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
|
8708
9738
|
}
|
|
8709
9739
|
const _analyzeInput = async () => {
|
|
8710
9740
|
// Use dynamic import to break circular dependency
|
|
8711
|
-
const schemaMod = await import('./index-
|
|
9741
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
8712
9742
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
8713
|
-
const { SchemaValidationService } = await import('./SchemaValidationService-
|
|
9743
|
+
const { SchemaValidationService } = await import('./SchemaValidationService-C4DIwn8Z.js');
|
|
8714
9744
|
let propertyName = propertyNameRaw;
|
|
8715
9745
|
if (!propertyName) {
|
|
8716
9746
|
throw new Error('propertyName is required');
|
|
@@ -8908,7 +9938,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
|
|
|
8908
9938
|
propertyRecordSchema?.validation &&
|
|
8909
9939
|
metadataValues.propertyValue != null &&
|
|
8910
9940
|
metadataValues.propertyValue !== '') {
|
|
8911
|
-
const { SchemaValidationService } = await import('./SchemaValidationService-
|
|
9941
|
+
const { SchemaValidationService } = await import('./SchemaValidationService-C4DIwn8Z.js');
|
|
8912
9942
|
const validationService = new SchemaValidationService();
|
|
8913
9943
|
const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, propertyRecordSchema.dataType, propertyRecordSchema.validation, propertyRecordSchema.refValueType);
|
|
8914
9944
|
if (!validationResult.isValid && validationResult.errors.length > 0) {
|
|
@@ -8986,8 +10016,6 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
|
|
|
8986
10016
|
return inserted[0];
|
|
8987
10017
|
};
|
|
8988
10018
|
|
|
8989
|
-
const eventEmitter = new EventEmitter();
|
|
8990
|
-
|
|
8991
10019
|
const readFileAsArrayBuffer$1 = async (file) => {
|
|
8992
10020
|
return new Promise((resolve) => {
|
|
8993
10021
|
const reader = new FileReader();
|
|
@@ -9134,6 +10162,12 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
|
9134
10162
|
}
|
|
9135
10163
|
const refResolvedDisplayValue = await BaseFileManager.getContentUrlFromPath(filePath);
|
|
9136
10164
|
let newLocalId;
|
|
10165
|
+
const resolvedPropertySchemaUid = schemaUid && schemaUid !== imageSchemaUid
|
|
10166
|
+
? schemaUid
|
|
10167
|
+
: (await getEasSchemaForItemProperty({
|
|
10168
|
+
propertyName,
|
|
10169
|
+
easDataType: 'bytes32',
|
|
10170
|
+
}))?.id;
|
|
9137
10171
|
if (!localId) {
|
|
9138
10172
|
const result = await createMetadata({
|
|
9139
10173
|
propertyName,
|
|
@@ -9143,7 +10177,7 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
|
9143
10177
|
versionLocalId,
|
|
9144
10178
|
versionUid,
|
|
9145
10179
|
modelName,
|
|
9146
|
-
schemaUid:
|
|
10180
|
+
schemaUid: resolvedPropertySchemaUid,
|
|
9147
10181
|
refSeedType: 'image',
|
|
9148
10182
|
refModelUid: imageSchemaUid,
|
|
9149
10183
|
refResolvedValue: fileName,
|
|
@@ -9162,7 +10196,7 @@ const saveImage = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
|
9162
10196
|
seedLocalId,
|
|
9163
10197
|
versionLocalId,
|
|
9164
10198
|
modelName,
|
|
9165
|
-
schemaUid,
|
|
10199
|
+
schemaUid: resolvedPropertySchemaUid,
|
|
9166
10200
|
refSeedType: 'image',
|
|
9167
10201
|
refResolvedValue: fileName,
|
|
9168
10202
|
localStorageDir: '/images',
|
|
@@ -9495,7 +10529,7 @@ const saveRelation = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
|
9495
10529
|
}
|
|
9496
10530
|
const _saveRelation = async () => {
|
|
9497
10531
|
// Use dynamic import to break circular dependency
|
|
9498
|
-
const schemaMod = await import('./index-
|
|
10532
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
9499
10533
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
9500
10534
|
if (!propertyNameRaw) {
|
|
9501
10535
|
throw new Error('propertyName is required');
|
|
@@ -9704,6 +10738,10 @@ const propertyMachine = setup({
|
|
|
9704
10738
|
context: {},
|
|
9705
10739
|
input: {},
|
|
9706
10740
|
},
|
|
10741
|
+
guards: {
|
|
10742
|
+
// stateIn return type does not satisfy setup() inference; runtime guard is correct for root state `idle`.
|
|
10743
|
+
propertyMachineIsIdle: stateIn('idle'),
|
|
10744
|
+
},
|
|
9707
10745
|
// actions: {
|
|
9708
10746
|
// updateContext: updateMachineContext,
|
|
9709
10747
|
// },
|
|
@@ -9726,7 +10764,11 @@ const propertyMachine = setup({
|
|
|
9726
10764
|
initial: 'waitingForDb',
|
|
9727
10765
|
context: ({ input }) => input,
|
|
9728
10766
|
on: {
|
|
9729
|
-
|
|
10767
|
+
/** Re-run DB hydration (e.g. after EAS sync wrote new metadata for this version). */
|
|
10768
|
+
rehydrateFromDb: {
|
|
10769
|
+
guard: 'propertyMachineIsIdle',
|
|
10770
|
+
target: '.hydratingFromDb',
|
|
10771
|
+
},
|
|
9730
10772
|
save: {
|
|
9731
10773
|
actions: assign({
|
|
9732
10774
|
isSaving: true,
|
|
@@ -10325,6 +11367,8 @@ function createReactiveProxy(config) {
|
|
|
10325
11367
|
return proxy;
|
|
10326
11368
|
}
|
|
10327
11369
|
|
|
11370
|
+
/** Parent Html property `propertyValue` after publish (66-char seed uid). */
|
|
11371
|
+
const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
10328
11372
|
// Start loading Model at module load time (non-blocking)
|
|
10329
11373
|
Promise.resolve().then(function () { return Model$1; }).then(module => {
|
|
10330
11374
|
module.Model;
|
|
@@ -10424,7 +11468,7 @@ const resolvePropertyRecordSchemaFromModel = async (modelName, propertyName, mod
|
|
|
10424
11468
|
};
|
|
10425
11469
|
/** Convert modelType (snake_case from DB) to Model name (PascalCase). startCase adds spaces ("Test Post"); Model names are "TestPost". */
|
|
10426
11470
|
const modelTypeToModelName = (modelType) => modelType ? upperFirst(camelCase(modelType)) : '';
|
|
10427
|
-
const logger$
|
|
11471
|
+
const logger$c = debug('seedSdk:property:class');
|
|
10428
11472
|
// Define tracked properties for the Proxy
|
|
10429
11473
|
// These properties will be read from/written to the actor context
|
|
10430
11474
|
const TRACKED_PROPERTIES$2 = [
|
|
@@ -10506,7 +11550,7 @@ class ItemProperty {
|
|
|
10506
11550
|
serviceInput.propertyValue = JSON.parse(propertyValue);
|
|
10507
11551
|
}
|
|
10508
11552
|
catch (e) {
|
|
10509
|
-
logger$
|
|
11553
|
+
logger$c('List property value is not JSON', e);
|
|
10510
11554
|
}
|
|
10511
11555
|
}
|
|
10512
11556
|
}
|
|
@@ -10529,7 +11573,7 @@ class ItemProperty {
|
|
|
10529
11573
|
return;
|
|
10530
11574
|
}
|
|
10531
11575
|
// Use dynamic import to break circular dependency
|
|
10532
|
-
const schemaMod = await import('./index-
|
|
11576
|
+
const schemaMod = await import('./index-3Ekqb4QB.js');
|
|
10533
11577
|
const { ModelPropertyDataTypes } = schemaMod;
|
|
10534
11578
|
const { context } = snapshot;
|
|
10535
11579
|
const { propertyRecordSchema } = context;
|
|
@@ -10552,7 +11596,8 @@ class ItemProperty {
|
|
|
10552
11596
|
propertyRecordSchema.storageType === 'ItemStorage' &&
|
|
10553
11597
|
context.refResolvedValue &&
|
|
10554
11598
|
context.localStorageDir;
|
|
10555
|
-
const
|
|
11599
|
+
const normalizedSchemaDt = normalizeDataType(propertyRecordSchema?.dataType);
|
|
11600
|
+
const isHtml = (context.refSeedType === 'html' || normalizedSchemaDt === ModelPropertyDataTypes.Html) &&
|
|
10556
11601
|
context.refResolvedValue;
|
|
10557
11602
|
// Fix: When File/Image property has a File object before save completes, set refResolvedValue and renderValue
|
|
10558
11603
|
// so the UI can display the filename and preview immediately (these update again when save completes)
|
|
@@ -10588,7 +11633,11 @@ class ItemProperty {
|
|
|
10588
11633
|
const dir = context.localStorageDir?.replace(/^\//, '') || (isHtml ? 'html' : 'images');
|
|
10589
11634
|
const filePath = BaseFileManager.getFilesPath(dir, context.refResolvedValue);
|
|
10590
11635
|
try {
|
|
10591
|
-
|
|
11636
|
+
let exists = await BaseFileManager.pathExists(filePath);
|
|
11637
|
+
if (!exists && isHtml) {
|
|
11638
|
+
await BaseFileManager.waitForFileWithContent(filePath, 100, 5000).catch(() => { });
|
|
11639
|
+
exists = await BaseFileManager.pathExists(filePath);
|
|
11640
|
+
}
|
|
10592
11641
|
if (exists && (isItemStorage || isHtml)) {
|
|
10593
11642
|
renderValue = await BaseFileManager.readFileAsString(filePath);
|
|
10594
11643
|
}
|
|
@@ -10608,8 +11657,8 @@ class ItemProperty {
|
|
|
10608
11657
|
if (isFile && isFileValue) {
|
|
10609
11658
|
renderValue = pv.name;
|
|
10610
11659
|
}
|
|
10611
|
-
else if (isImage) {
|
|
10612
|
-
// FS race
|
|
11660
|
+
else if (isImage || isHtml) {
|
|
11661
|
+
// FS race, OPFS cleared, or HTML served from Arweave: do not clobber hydrated/rehydrated value
|
|
10613
11662
|
renderValue = undefined;
|
|
10614
11663
|
}
|
|
10615
11664
|
else {
|
|
@@ -10618,13 +11667,21 @@ class ItemProperty {
|
|
|
10618
11667
|
}
|
|
10619
11668
|
}
|
|
10620
11669
|
catch (e) {
|
|
10621
|
-
logger$
|
|
10622
|
-
renderValue = 'No file found';
|
|
11670
|
+
logger$c(`[ItemProperty] [${context.seedLocalId}] [${context.propertyName}] [storageType] error`, e);
|
|
11671
|
+
renderValue = isHtml ? undefined : 'No file found';
|
|
10623
11672
|
}
|
|
10624
11673
|
}
|
|
10625
11674
|
if (!renderValue) {
|
|
10626
11675
|
renderValue = context.renderValue || context.propertyValue;
|
|
10627
11676
|
}
|
|
11677
|
+
const pvStr = typeof context.propertyValue === 'string' ? context.propertyValue.trim() : '';
|
|
11678
|
+
if (normalizedSchemaDt === ModelPropertyDataTypes.Html &&
|
|
11679
|
+
HTML_PROP_SEED_UID_RE.test(pvStr) &&
|
|
11680
|
+
renderValue === pvStr &&
|
|
11681
|
+
typeof context.renderValue === 'string' &&
|
|
11682
|
+
context.renderValue.length > pvStr.length) {
|
|
11683
|
+
renderValue = context.renderValue;
|
|
11684
|
+
}
|
|
10628
11685
|
let transformedPropertyName = propertyName;
|
|
10629
11686
|
const skipTransform = INTERNAL_PROPERTY_NAMES.includes(propertyName) || !!this._alias;
|
|
10630
11687
|
if (!skipTransform && transformedPropertyName.endsWith('Id')) {
|
|
@@ -10687,7 +11744,7 @@ class ItemProperty {
|
|
|
10687
11744
|
const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
|
|
10688
11745
|
const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
|
|
10689
11746
|
const propertyNameVariant = propertyNames.length > 1 ? propertyNames[1] : undefined;
|
|
10690
|
-
const _mod_6 = await import('./index-
|
|
11747
|
+
const _mod_6 = await import('./index-BRo7D3s1.js');
|
|
10691
11748
|
const _ns_6 = _mod_6.s;
|
|
10692
11749
|
const seedSchemaMod = _ns_6;
|
|
10693
11750
|
const { metadata } = seedSchemaMod;
|
|
@@ -11039,6 +12096,35 @@ class ItemProperty {
|
|
|
11039
12096
|
instance._service.send({ type: 'updateContext', ...updates });
|
|
11040
12097
|
}
|
|
11041
12098
|
}
|
|
12099
|
+
// After wipe/reconnect, cached actors can stay idle with stale renderValue while DB + Arweave
|
|
12100
|
+
// paths would hydrate. Re-run DB hydration without clobbering propertyValue.
|
|
12101
|
+
const svc = instance._service;
|
|
12102
|
+
const snap = svc.getSnapshot();
|
|
12103
|
+
if (snap.status === 'active' && snap.value === 'idle') {
|
|
12104
|
+
const schema = props.propertyRecordSchema ?? ctx.propertyRecordSchema;
|
|
12105
|
+
const dt = normalizeDataType(schema?.dataType);
|
|
12106
|
+
const isHtmlProp = props.refSeedType === 'html' ||
|
|
12107
|
+
ctx.refSeedType === 'html' ||
|
|
12108
|
+
dt === ModelPropertyDataTypes.Html;
|
|
12109
|
+
const isListProp = dt === ModelPropertyDataTypes.List;
|
|
12110
|
+
const isRelationProp = dt === ModelPropertyDataTypes.Relation;
|
|
12111
|
+
const pv = ctx.propertyValue;
|
|
12112
|
+
const pvStr = typeof pv === 'string' ? pv.trim() : '';
|
|
12113
|
+
const renderVal = ctx.renderValue;
|
|
12114
|
+
const renderMissing = renderVal == null || (typeof renderVal === 'string' && renderVal.length === 0);
|
|
12115
|
+
const htmlStuckOnUid = isHtmlProp &&
|
|
12116
|
+
HTML_PROP_SEED_UID_RE.test(pvStr) &&
|
|
12117
|
+
(renderMissing || renderVal === pv);
|
|
12118
|
+
const pvPresent = pv != null &&
|
|
12119
|
+
(Array.isArray(pv) ? pv.length > 0 : String(pv).trim().length > 0);
|
|
12120
|
+
const listOrRelationNeedsResolve = (isListProp || isRelationProp) && renderMissing && pvPresent;
|
|
12121
|
+
const versionChanged = props.versionLocalId != null &&
|
|
12122
|
+
ctx.versionLocalId != null &&
|
|
12123
|
+
props.versionLocalId !== ctx.versionLocalId;
|
|
12124
|
+
if (htmlStuckOnUid || listOrRelationNeedsResolve || versionChanged) {
|
|
12125
|
+
svc.send({ type: 'rehydrateFromDb' });
|
|
12126
|
+
}
|
|
12127
|
+
}
|
|
11042
12128
|
// On cache hit, do not sync propertyValue: refetches can race with in-memory updates (e.g. save()).
|
|
11043
12129
|
if (!waitForReady)
|
|
11044
12130
|
return instance;
|
|
@@ -11388,7 +12474,7 @@ class ItemProperty {
|
|
|
11388
12474
|
}
|
|
11389
12475
|
async save() {
|
|
11390
12476
|
const ctx = this._getSnapshotContext();
|
|
11391
|
-
const { assertItemOwned } = await import('./ownership-
|
|
12477
|
+
const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
|
|
11392
12478
|
await assertItemOwned({
|
|
11393
12479
|
seedLocalId: ctx?.seedLocalId ?? undefined,
|
|
11394
12480
|
seedUid: ctx?.seedUid ?? undefined,
|
|
@@ -11481,7 +12567,7 @@ class ItemProperty {
|
|
|
11481
12567
|
if (!propertyName || (!seedLocalId && !seedUid))
|
|
11482
12568
|
return;
|
|
11483
12569
|
if (db) {
|
|
11484
|
-
const _mod_7 = await import('./index-
|
|
12570
|
+
const _mod_7 = await import('./index-BRo7D3s1.js');
|
|
11485
12571
|
const _ns_7 = _mod_7.s;
|
|
11486
12572
|
const seedSchemaMod = _ns_7;
|
|
11487
12573
|
const { metadata } = seedSchemaMod;
|
|
@@ -11729,7 +12815,7 @@ class Item {
|
|
|
11729
12815
|
});
|
|
11730
12816
|
};
|
|
11731
12817
|
this.unpublish = async () => {
|
|
11732
|
-
const { assertItemOwned } = await import('./ownership-
|
|
12818
|
+
const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
|
|
11733
12819
|
const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
|
|
11734
12820
|
await assertItemOwned(this);
|
|
11735
12821
|
const seedUid = this.seedUid;
|
|
@@ -11753,7 +12839,7 @@ class Item {
|
|
|
11753
12839
|
this._service.send({ type: 'updateContext', revokedAt });
|
|
11754
12840
|
};
|
|
11755
12841
|
this.publish = async () => {
|
|
11756
|
-
const { assertItemOwned } = await import('./ownership-
|
|
12842
|
+
const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
|
|
11757
12843
|
await assertItemOwned(this);
|
|
11758
12844
|
this._service.send({ type: 'startPublish' });
|
|
11759
12845
|
return new Promise((resolve, reject) => {
|
|
@@ -11789,12 +12875,12 @@ class Item {
|
|
|
11789
12875
|
};
|
|
11790
12876
|
this.getPublishUploads = async (options) => {
|
|
11791
12877
|
// Use dynamic import to break circular dependency
|
|
11792
|
-
const getPublishUploadsMod = await import('./getPublishUploads-
|
|
12878
|
+
const getPublishUploadsMod = await import('./getPublishUploads-Cf2J-5FR.js');
|
|
11793
12879
|
const { getPublishUploads } = getPublishUploadsMod;
|
|
11794
12880
|
return await getPublishUploads(this, [], undefined, options);
|
|
11795
12881
|
};
|
|
11796
12882
|
this.getPublishPayload = async (uploadedTransactions, options) => {
|
|
11797
|
-
const getPublishPayloadMod = await import('./getPublishPayload-
|
|
12883
|
+
const getPublishPayloadMod = await import('./getPublishPayload-Ddc_LGPs.js');
|
|
11798
12884
|
const { getPublishPayload } = getPublishPayloadMod;
|
|
11799
12885
|
return await getPublishPayload(this, uploadedTransactions, options);
|
|
11800
12886
|
};
|
|
@@ -11911,6 +12997,8 @@ class Item {
|
|
|
11911
12997
|
'schemaUid',
|
|
11912
12998
|
'latestVersionLocalId',
|
|
11913
12999
|
'latestVersionUid',
|
|
13000
|
+
'publishedVersionUid',
|
|
13001
|
+
'publishedVersionLocalId',
|
|
11914
13002
|
];
|
|
11915
13003
|
const keysFromInitial = Object.keys(initialValues).filter((key) => !metadataKeys.includes(key));
|
|
11916
13004
|
const schemaNameForModel = initialValues.schemaName;
|
|
@@ -11954,6 +13042,128 @@ class Item {
|
|
|
11954
13042
|
});
|
|
11955
13043
|
}
|
|
11956
13044
|
}
|
|
13045
|
+
/** Prefer local id so list rows (local + uid) resolve the same cache entry as early draft loads. */
|
|
13046
|
+
static findItemInstanceCacheEntryByProps(props) {
|
|
13047
|
+
const l = props.seedLocalId;
|
|
13048
|
+
const u = props.seedUid;
|
|
13049
|
+
if (typeof l === 'string' && l.length > 0) {
|
|
13050
|
+
const e = this.instanceCache.get(l);
|
|
13051
|
+
if (e)
|
|
13052
|
+
return e;
|
|
13053
|
+
}
|
|
13054
|
+
if (typeof u === 'string' && u.length > 0) {
|
|
13055
|
+
const e = this.instanceCache.get(u);
|
|
13056
|
+
if (e)
|
|
13057
|
+
return e;
|
|
13058
|
+
}
|
|
13059
|
+
return undefined;
|
|
13060
|
+
}
|
|
13061
|
+
static findItemInstanceCacheEntryById(id) {
|
|
13062
|
+
const direct = this.instanceCache.get(id);
|
|
13063
|
+
if (direct)
|
|
13064
|
+
return direct;
|
|
13065
|
+
for (const [, entry] of this.instanceCache) {
|
|
13066
|
+
const ctx = entry.instance._getSnapshotContext();
|
|
13067
|
+
if (ctx.seedLocalId === id || ctx.seedUid === id)
|
|
13068
|
+
return entry;
|
|
13069
|
+
}
|
|
13070
|
+
return undefined;
|
|
13071
|
+
}
|
|
13072
|
+
static collectInstanceCacheKeysForInstance(instance) {
|
|
13073
|
+
const keys = [];
|
|
13074
|
+
for (const [k, v] of this.instanceCache) {
|
|
13075
|
+
if (v.instance === instance)
|
|
13076
|
+
keys.push(k);
|
|
13077
|
+
}
|
|
13078
|
+
return keys;
|
|
13079
|
+
}
|
|
13080
|
+
static registerItemInInstanceCache(instance) {
|
|
13081
|
+
const ctx = instance._getSnapshotContext();
|
|
13082
|
+
const lid = typeof ctx.seedLocalId === 'string' && ctx.seedLocalId.length > 0
|
|
13083
|
+
? ctx.seedLocalId
|
|
13084
|
+
: undefined;
|
|
13085
|
+
const uid = typeof ctx.seedUid === 'string' && ctx.seedUid.length > 0 ? ctx.seedUid : undefined;
|
|
13086
|
+
const entry = { instance, refCount: 1 };
|
|
13087
|
+
if (lid)
|
|
13088
|
+
this.instanceCache.set(lid, entry);
|
|
13089
|
+
if (uid && uid !== lid)
|
|
13090
|
+
this.instanceCache.set(uid, entry);
|
|
13091
|
+
if (!lid && !uid) {
|
|
13092
|
+
throw new Error('Item.registerItemInInstanceCache: missing seedLocalId and seedUid');
|
|
13093
|
+
}
|
|
13094
|
+
}
|
|
13095
|
+
static releaseItemInstanceCacheHold(instance) {
|
|
13096
|
+
const keys = this.collectInstanceCacheKeysForInstance(instance);
|
|
13097
|
+
if (keys.length === 0)
|
|
13098
|
+
return;
|
|
13099
|
+
const entry = this.instanceCache.get(keys[0]);
|
|
13100
|
+
entry.refCount -= 1;
|
|
13101
|
+
if (entry.refCount <= 0) {
|
|
13102
|
+
for (const k of keys) {
|
|
13103
|
+
this.instanceCache.delete(k);
|
|
13104
|
+
}
|
|
13105
|
+
}
|
|
13106
|
+
}
|
|
13107
|
+
/**
|
|
13108
|
+
* Item machine can reach `idle` before `propertyInstances` is merged (race) or while
|
|
13109
|
+
* child ItemProperty actors are still hydrating. useItems / Item.all must not return that shell.
|
|
13110
|
+
*/
|
|
13111
|
+
static async waitForItemInstanceReadyForRead(item, readyTimeout) {
|
|
13112
|
+
await waitForEntityIdle(item, { timeout: readyTimeout });
|
|
13113
|
+
const svc = item.getService();
|
|
13114
|
+
try {
|
|
13115
|
+
await waitFor(svc, (snap) => {
|
|
13116
|
+
if ('value' in snap && snap.value === 'error') {
|
|
13117
|
+
throw new Error('Entity failed to load');
|
|
13118
|
+
}
|
|
13119
|
+
if (!('value' in snap) || snap.value !== 'idle') {
|
|
13120
|
+
return false;
|
|
13121
|
+
}
|
|
13122
|
+
const ctx = snap.context || {};
|
|
13123
|
+
const versionsCount = ctx.versionsCount ?? 0;
|
|
13124
|
+
const hasHeadVersion = !!ctx.latestVersionLocalId;
|
|
13125
|
+
if (versionsCount === 0 && !hasHeadVersion) {
|
|
13126
|
+
return true;
|
|
13127
|
+
}
|
|
13128
|
+
return (ctx.propertyInstances?.size ?? 0) > 0;
|
|
13129
|
+
}, { timeout: readyTimeout });
|
|
13130
|
+
}
|
|
13131
|
+
catch (e) {
|
|
13132
|
+
if (e?.message === 'Entity failed to load') {
|
|
13133
|
+
throw e;
|
|
13134
|
+
}
|
|
13135
|
+
const msg = typeof e?.message === 'string' ? e.message : '';
|
|
13136
|
+
const isWaitForTimeout = msg.includes('Timeout') || msg.toLowerCase().includes('timed out');
|
|
13137
|
+
if (!isWaitForTimeout) {
|
|
13138
|
+
throw e;
|
|
13139
|
+
}
|
|
13140
|
+
}
|
|
13141
|
+
const snap = svc.getSnapshot();
|
|
13142
|
+
const pis = snap.context?.propertyInstances;
|
|
13143
|
+
if (!pis || pis.size === 0) {
|
|
13144
|
+
return;
|
|
13145
|
+
}
|
|
13146
|
+
await Promise.all([...pis.values()].map((prop) => waitForEntityIdle(prop, {
|
|
13147
|
+
timeout: readyTimeout,
|
|
13148
|
+
throwOnError: false,
|
|
13149
|
+
})));
|
|
13150
|
+
}
|
|
13151
|
+
static itemCacheEntryLooksUnhydratedAfterIdle(instance, props) {
|
|
13152
|
+
const snap = instance.getService().getSnapshot();
|
|
13153
|
+
if (snap.value !== 'idle')
|
|
13154
|
+
return false;
|
|
13155
|
+
const mapSize = snap.context.propertyInstances?.size ?? 0;
|
|
13156
|
+
if (mapSize > 0)
|
|
13157
|
+
return false;
|
|
13158
|
+
const ctx = snap.context;
|
|
13159
|
+
const versionsCount = props.versionsCount ?? ctx.versionsCount ?? 0;
|
|
13160
|
+
const hasVersionHead = versionsCount > 0 ||
|
|
13161
|
+
!!props.latestVersionLocalId ||
|
|
13162
|
+
!!ctx.latestVersionLocalId ||
|
|
13163
|
+
!!props.latestVersionUid ||
|
|
13164
|
+
!!ctx.latestVersionUid;
|
|
13165
|
+
return hasVersionHead;
|
|
13166
|
+
}
|
|
11957
13167
|
static async create(props, options) {
|
|
11958
13168
|
const waitForReady = options?.waitForReady !== false;
|
|
11959
13169
|
const readyTimeout = options?.readyTimeout ?? 5000;
|
|
@@ -11961,45 +13171,66 @@ class Item {
|
|
|
11961
13171
|
props.modelName = startCase(props.type);
|
|
11962
13172
|
}
|
|
11963
13173
|
if (props.seedUid || props.seedLocalId) {
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
|
|
11979
|
-
|
|
13174
|
+
cacheReuse: {
|
|
13175
|
+
const cachedEntry = this.findItemInstanceCacheEntryByProps(props);
|
|
13176
|
+
if (cachedEntry) {
|
|
13177
|
+
const instance = cachedEntry.instance;
|
|
13178
|
+
cachedEntry.refCount += 1;
|
|
13179
|
+
for (const [propertyName, propertyValue] of Object.entries(props)) {
|
|
13180
|
+
const snapshot = instance.getService().getSnapshot();
|
|
13181
|
+
const propertyInstances = snapshot.context.propertyInstances;
|
|
13182
|
+
if (!propertyInstances || !propertyInstances.has(propertyName)) {
|
|
13183
|
+
continue;
|
|
13184
|
+
}
|
|
13185
|
+
const propertyInstance = propertyInstances.get(propertyName);
|
|
13186
|
+
if (!propertyInstance) {
|
|
13187
|
+
continue;
|
|
13188
|
+
}
|
|
13189
|
+
propertyInstance.getService().send({
|
|
13190
|
+
type: 'updateContext',
|
|
13191
|
+
propertyValue,
|
|
13192
|
+
});
|
|
11980
13193
|
}
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
propertyValue,
|
|
11984
|
-
});
|
|
11985
|
-
}
|
|
11986
|
-
if (!waitForReady)
|
|
11987
|
-
return instance;
|
|
11988
|
-
try {
|
|
11989
|
-
await waitForEntityIdle(instance, { timeout: readyTimeout });
|
|
11990
|
-
}
|
|
11991
|
-
catch (err) {
|
|
13194
|
+
if (!waitForReady)
|
|
13195
|
+
return instance;
|
|
11992
13196
|
try {
|
|
11993
|
-
|
|
13197
|
+
await this.waitForItemInstanceReadyForRead(instance, readyTimeout);
|
|
11994
13198
|
}
|
|
11995
|
-
catch {
|
|
11996
|
-
|
|
13199
|
+
catch (err) {
|
|
13200
|
+
try {
|
|
13201
|
+
instance.unload();
|
|
13202
|
+
}
|
|
13203
|
+
catch {
|
|
13204
|
+
/* best-effort cache cleanup */
|
|
13205
|
+
}
|
|
13206
|
+
throw err;
|
|
11997
13207
|
}
|
|
11998
|
-
|
|
13208
|
+
if (waitForReady &&
|
|
13209
|
+
this.itemCacheEntryLooksUnhydratedAfterIdle(instance, props)) {
|
|
13210
|
+
forceRemoveFromCaches(instance, {
|
|
13211
|
+
getCacheKeys: () => this.collectInstanceCacheKeysForInstance(instance),
|
|
13212
|
+
caches: [Item.instanceCache],
|
|
13213
|
+
});
|
|
13214
|
+
try {
|
|
13215
|
+
unloadEntity(instance, {
|
|
13216
|
+
getCacheKeys: () => [],
|
|
13217
|
+
caches: [],
|
|
13218
|
+
instanceState: itemInstanceState,
|
|
13219
|
+
getService: (inst) => inst._service,
|
|
13220
|
+
onUnload: (inst) => {
|
|
13221
|
+
inst._subscription?.unsubscribe();
|
|
13222
|
+
},
|
|
13223
|
+
});
|
|
13224
|
+
}
|
|
13225
|
+
catch {
|
|
13226
|
+
/* best-effort teardown for stale cached shell */
|
|
13227
|
+
}
|
|
13228
|
+
break cacheReuse;
|
|
13229
|
+
}
|
|
13230
|
+
return instance;
|
|
11999
13231
|
}
|
|
12000
|
-
return instance;
|
|
12001
13232
|
}
|
|
12002
|
-
if (!this.
|
|
13233
|
+
if (!this.findItemInstanceCacheEntryByProps(props)) {
|
|
12003
13234
|
// Item no longer needs modelInstance - it loads properties from database independently
|
|
12004
13235
|
// Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
|
|
12005
13236
|
const { latestVersionUid, ...propsWithoutVersionUid } = props;
|
|
@@ -12088,14 +13319,11 @@ class Item {
|
|
|
12088
13319
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
12089
13320
|
},
|
|
12090
13321
|
});
|
|
12091
|
-
this.
|
|
12092
|
-
instance: proxiedInstance,
|
|
12093
|
-
refCount: 1,
|
|
12094
|
-
});
|
|
13322
|
+
this.registerItemInInstanceCache(proxiedInstance);
|
|
12095
13323
|
if (!waitForReady)
|
|
12096
13324
|
return proxiedInstance;
|
|
12097
13325
|
try {
|
|
12098
|
-
await
|
|
13326
|
+
await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
|
|
12099
13327
|
}
|
|
12100
13328
|
catch (err) {
|
|
12101
13329
|
try {
|
|
@@ -12271,14 +13499,11 @@ class Item {
|
|
|
12271
13499
|
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
12272
13500
|
},
|
|
12273
13501
|
});
|
|
12274
|
-
this.
|
|
12275
|
-
instance: proxiedInstance,
|
|
12276
|
-
refCount: 1,
|
|
12277
|
-
});
|
|
13502
|
+
this.registerItemInInstanceCache(proxiedInstance);
|
|
12278
13503
|
if (!waitForReady)
|
|
12279
13504
|
return proxiedInstance;
|
|
12280
13505
|
try {
|
|
12281
|
-
await
|
|
13506
|
+
await this.waitForItemInstanceReadyForRead(proxiedInstance, readyTimeout);
|
|
12282
13507
|
}
|
|
12283
13508
|
catch (err) {
|
|
12284
13509
|
try {
|
|
@@ -12301,14 +13526,10 @@ class Item {
|
|
|
12301
13526
|
if (!id) {
|
|
12302
13527
|
return null;
|
|
12303
13528
|
}
|
|
12304
|
-
|
|
12305
|
-
if (
|
|
12306
|
-
|
|
12307
|
-
|
|
12308
|
-
instance,
|
|
12309
|
-
refCount: refCount + 1,
|
|
12310
|
-
});
|
|
12311
|
-
return instance;
|
|
13529
|
+
const entry = this.findItemInstanceCacheEntryById(id);
|
|
13530
|
+
if (entry) {
|
|
13531
|
+
entry.refCount += 1;
|
|
13532
|
+
return entry.instance;
|
|
12312
13533
|
}
|
|
12313
13534
|
return null;
|
|
12314
13535
|
}
|
|
@@ -12354,8 +13575,8 @@ class Item {
|
|
|
12354
13575
|
if (!seedLocalId && !seedUid) {
|
|
12355
13576
|
return undefined;
|
|
12356
13577
|
}
|
|
12357
|
-
//
|
|
12358
|
-
const id =
|
|
13578
|
+
// Prefer local id so cache + findEntity align with Item.instanceCache (local-first, uid alias).
|
|
13579
|
+
const id = seedLocalId || seedUid;
|
|
12359
13580
|
if (!id) {
|
|
12360
13581
|
return undefined;
|
|
12361
13582
|
}
|
|
@@ -12386,10 +13607,129 @@ class Item {
|
|
|
12386
13607
|
}));
|
|
12387
13608
|
}
|
|
12388
13609
|
if (waitForReady && itemInstances.length > 0) {
|
|
12389
|
-
await Promise.all(itemInstances.map((item) =>
|
|
13610
|
+
await Promise.all(itemInstances.map((item) => this.waitForItemInstanceReadyForRead(item, readyTimeout)));
|
|
12390
13611
|
}
|
|
12391
13612
|
return orderBy(itemInstances, ['createdAt'], ['desc']);
|
|
12392
13613
|
}
|
|
13614
|
+
/**
|
|
13615
|
+
* After EAS sync writes metadata for the latest version, merge new property instances and
|
|
13616
|
+
* re-run DB hydration on cached Items. Item liveQuery watches seeds/versions, not metadata,
|
|
13617
|
+
* and useItems may not invalidate when the seed set is unchanged.
|
|
13618
|
+
*/
|
|
13619
|
+
static async rehydrateCachedItemsFromDbAfterEasSync() {
|
|
13620
|
+
const appDb = BaseDb.getAppDb();
|
|
13621
|
+
if (!appDb || Item.instanceCache.size === 0) {
|
|
13622
|
+
return;
|
|
13623
|
+
}
|
|
13624
|
+
const _mod_8 = await import('./index-BRo7D3s1.js');
|
|
13625
|
+
const _ns_8 = _mod_8.s;
|
|
13626
|
+
const { metadata } = _ns_8;
|
|
13627
|
+
const { eq, and } = await import('drizzle-orm');
|
|
13628
|
+
const dedupedInstances = new Map();
|
|
13629
|
+
for (const entry of Item.instanceCache.values()) {
|
|
13630
|
+
dedupedInstances.set(entry.instance, entry);
|
|
13631
|
+
}
|
|
13632
|
+
const entries = [...dedupedInstances.values()];
|
|
13633
|
+
await Promise.all(entries.map(async ({ instance }) => {
|
|
13634
|
+
try {
|
|
13635
|
+
const svc = instance.getService();
|
|
13636
|
+
if (svc.getSnapshot().status !== 'active') {
|
|
13637
|
+
return;
|
|
13638
|
+
}
|
|
13639
|
+
const ctx = svc.getSnapshot().context;
|
|
13640
|
+
const seedLocalId = ctx.seedLocalId;
|
|
13641
|
+
const seedUid = ctx.seedUid;
|
|
13642
|
+
const versionLocalId = ctx.latestVersionLocalId;
|
|
13643
|
+
const itemModelName = ctx.modelName;
|
|
13644
|
+
const schemaNameForModel = ctx.schemaName;
|
|
13645
|
+
if (!seedLocalId || !versionLocalId || !itemModelName) {
|
|
13646
|
+
return;
|
|
13647
|
+
}
|
|
13648
|
+
const metadataRows = await appDb
|
|
13649
|
+
.select()
|
|
13650
|
+
.from(metadata)
|
|
13651
|
+
.where(and(eq(metadata.seedLocalId, seedLocalId), eq(metadata.versionLocalId, versionLocalId)));
|
|
13652
|
+
let propertySchemas = {};
|
|
13653
|
+
try {
|
|
13654
|
+
const M = getModel();
|
|
13655
|
+
const model = schemaNameForModel !== undefined
|
|
13656
|
+
? M?.getByName(itemModelName, schemaNameForModel)
|
|
13657
|
+
: M?.getByName(itemModelName);
|
|
13658
|
+
if (model?.properties?.length) {
|
|
13659
|
+
propertySchemas = modelPropertiesToObject(model.properties);
|
|
13660
|
+
}
|
|
13661
|
+
}
|
|
13662
|
+
catch {
|
|
13663
|
+
/* Model optional */
|
|
13664
|
+
}
|
|
13665
|
+
const sendToItemMachine = (event) => {
|
|
13666
|
+
if (svc.getSnapshot().status !== 'active') {
|
|
13667
|
+
return;
|
|
13668
|
+
}
|
|
13669
|
+
svc.send(event);
|
|
13670
|
+
};
|
|
13671
|
+
for (const metaRow of metadataRows) {
|
|
13672
|
+
try {
|
|
13673
|
+
let propertyName = metaRow.propertyName;
|
|
13674
|
+
const listSchemaKey = propertyName &&
|
|
13675
|
+
Object.keys(propertySchemas).length > 0 &&
|
|
13676
|
+
resolveStorageNameToSchemaName(propertySchemas, propertyName);
|
|
13677
|
+
if (listSchemaKey) {
|
|
13678
|
+
propertyName = listSchemaKey;
|
|
13679
|
+
}
|
|
13680
|
+
else {
|
|
13681
|
+
const baseName = propertyName?.endsWith('Id') ? propertyName.slice(0, -2) : undefined;
|
|
13682
|
+
const refSeedType = metaRow.refSeedType;
|
|
13683
|
+
const isRefTypeFromMeta = refSeedType === 'file' ||
|
|
13684
|
+
refSeedType === 'image' ||
|
|
13685
|
+
refSeedType === 'relation' ||
|
|
13686
|
+
refSeedType === 'html';
|
|
13687
|
+
if (baseName && (propertySchemas[baseName] || isRefTypeFromMeta)) {
|
|
13688
|
+
propertyName = baseName;
|
|
13689
|
+
}
|
|
13690
|
+
}
|
|
13691
|
+
if (!propertyName) {
|
|
13692
|
+
continue;
|
|
13693
|
+
}
|
|
13694
|
+
const property = await ItemProperty.find({
|
|
13695
|
+
propertyName,
|
|
13696
|
+
seedLocalId,
|
|
13697
|
+
seedUid,
|
|
13698
|
+
modelName: itemModelName,
|
|
13699
|
+
});
|
|
13700
|
+
if (property) {
|
|
13701
|
+
sendToItemMachine({
|
|
13702
|
+
type: 'addPropertyInstance',
|
|
13703
|
+
propertyName,
|
|
13704
|
+
propertyInstance: property,
|
|
13705
|
+
});
|
|
13706
|
+
}
|
|
13707
|
+
}
|
|
13708
|
+
catch {
|
|
13709
|
+
/* row skipped */
|
|
13710
|
+
}
|
|
13711
|
+
}
|
|
13712
|
+
const instances = svc.getSnapshot().context.propertyInstances;
|
|
13713
|
+
if (!instances) {
|
|
13714
|
+
return;
|
|
13715
|
+
}
|
|
13716
|
+
for (const propertyInstance of instances.values()) {
|
|
13717
|
+
try {
|
|
13718
|
+
const propertySnap = propertyInstance.getService().getSnapshot();
|
|
13719
|
+
if (isMachineSnapshot(propertySnap) && propertySnap.matches('idle')) {
|
|
13720
|
+
propertyInstance.getService().send({ type: 'rehydrateFromDb' });
|
|
13721
|
+
}
|
|
13722
|
+
}
|
|
13723
|
+
catch {
|
|
13724
|
+
/* best-effort */
|
|
13725
|
+
}
|
|
13726
|
+
}
|
|
13727
|
+
}
|
|
13728
|
+
catch (e) {
|
|
13729
|
+
itemLogger('rehydrateCachedItemsFromDbAfterEasSync item failed:', e);
|
|
13730
|
+
}
|
|
13731
|
+
}));
|
|
13732
|
+
}
|
|
12393
13733
|
_createPropertyInstance(props) {
|
|
12394
13734
|
if (this._storageTransactionId) {
|
|
12395
13735
|
props.storageTransactionId = this._storageTransactionId;
|
|
@@ -12732,9 +14072,9 @@ class Item {
|
|
|
12732
14072
|
itemActor.send(event);
|
|
12733
14073
|
};
|
|
12734
14074
|
try {
|
|
12735
|
-
const
|
|
12736
|
-
const
|
|
12737
|
-
const seedSchemaMod =
|
|
14075
|
+
const _mod_9 = await import('./index-BRo7D3s1.js');
|
|
14076
|
+
const _ns_9 = _mod_9.s;
|
|
14077
|
+
const seedSchemaMod = _ns_9;
|
|
12738
14078
|
const { seeds, versions, metadata } = seedSchemaMod;
|
|
12739
14079
|
const drizzleMod = await import('drizzle-orm');
|
|
12740
14080
|
const { eq, and } = drizzleMod;
|
|
@@ -13006,15 +14346,10 @@ class Item {
|
|
|
13006
14346
|
}
|
|
13007
14347
|
unload() {
|
|
13008
14348
|
try {
|
|
13009
|
-
|
|
13010
|
-
const cacheKey = context.seedUid || context.seedLocalId;
|
|
13011
|
-
const cacheKeys = [];
|
|
13012
|
-
if (cacheKey) {
|
|
13013
|
-
cacheKeys.push(cacheKey);
|
|
13014
|
-
}
|
|
14349
|
+
Item.releaseItemInstanceCacheHold(this);
|
|
13015
14350
|
unloadEntity(this, {
|
|
13016
|
-
getCacheKeys: () =>
|
|
13017
|
-
caches: [
|
|
14351
|
+
getCacheKeys: () => [],
|
|
14352
|
+
caches: [],
|
|
13018
14353
|
instanceState: itemInstanceState,
|
|
13019
14354
|
getService: (instance) => instance._service,
|
|
13020
14355
|
onUnload: (instance) => {
|
|
@@ -13043,11 +14378,10 @@ class Item {
|
|
|
13043
14378
|
* Destroy the item: soft delete in DB, remove from caches, clean up subscriptions, stop service.
|
|
13044
14379
|
*/
|
|
13045
14380
|
async destroy() {
|
|
13046
|
-
const { assertItemOwned } = await import('./ownership-
|
|
14381
|
+
const { assertItemOwned } = await import('./ownership-TR-mIjJh.js');
|
|
13047
14382
|
await assertItemOwned(this);
|
|
13048
14383
|
const context = this._getSnapshotContext();
|
|
13049
|
-
const
|
|
13050
|
-
const cacheKeys = cacheKey ? [cacheKey] : [];
|
|
14384
|
+
const cacheKeys = Item.collectInstanceCacheKeysForInstance(this);
|
|
13051
14385
|
clearDestroySubscriptions(this, {
|
|
13052
14386
|
instanceState: itemInstanceState,
|
|
13053
14387
|
onUnload: (instance) => instance._subscription?.unsubscribe(),
|
|
@@ -13104,600 +14438,331 @@ function normalizeAddressConfig(addresses) {
|
|
|
13104
14438
|
};
|
|
13105
14439
|
}
|
|
13106
14440
|
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
const
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
const
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
|
|
14441
|
+
let writeTail = Promise.resolve();
|
|
14442
|
+
function enqueueEasSyncDbWrite(fn) {
|
|
14443
|
+
const next = writeTail.then(fn);
|
|
14444
|
+
writeTail = next.catch(() => { });
|
|
14445
|
+
return next;
|
|
14446
|
+
}
|
|
14447
|
+
const MAX_ERROR_MESSAGE_LENGTH = 500;
|
|
14448
|
+
const MAX_ERROR_DETAILS_LENGTH = 2000;
|
|
14449
|
+
async function insertEasSyncProcessRow(params) {
|
|
14450
|
+
return enqueueEasSyncDbWrite(async () => {
|
|
14451
|
+
const db = BaseDb.getAppDb();
|
|
14452
|
+
if (!db) {
|
|
14453
|
+
throw new Error('[easSyncProcess] App DB not available');
|
|
14454
|
+
}
|
|
14455
|
+
const now = Date.now();
|
|
14456
|
+
const [row] = await db
|
|
14457
|
+
.insert(easSyncProcesses)
|
|
14458
|
+
.values({
|
|
14459
|
+
status: 'in_progress',
|
|
14460
|
+
startedAt: now,
|
|
14461
|
+
requestPayload: JSON.stringify(params.requestPayload),
|
|
14462
|
+
persistedSnapshot: JSON.stringify(params.persistedSnapshot),
|
|
14463
|
+
createdAt: now,
|
|
14464
|
+
updatedAt: now,
|
|
13126
14465
|
})
|
|
13127
|
-
.
|
|
13128
|
-
|
|
13129
|
-
|
|
13130
|
-
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
id: foundModelQuery[0].id,
|
|
13137
|
-
name: foundModelQuery[0].name,
|
|
13138
|
-
uid: foundModelQuery[0].uid,
|
|
13139
|
-
tableName: pluralize(foundModelQuery[0].name).toLowerCase(),
|
|
13140
|
-
};
|
|
13141
|
-
modelRecords.push(foundModel);
|
|
13142
|
-
if (modelName === 'Seed') {
|
|
13143
|
-
continue;
|
|
13144
|
-
}
|
|
13145
|
-
const schemaString = `bytes32 ${toSnakeCase(modelName)}`;
|
|
13146
|
-
schemaStringToModelRecord.set(schemaString, foundModel);
|
|
13147
|
-
}
|
|
13148
|
-
return {
|
|
13149
|
-
schemaStringToModelRecord,
|
|
13150
|
-
modelRecords,
|
|
13151
|
-
};
|
|
13152
|
-
};
|
|
13153
|
-
|
|
13154
|
-
const createSeeds = async (newSeeds) => {
|
|
13155
|
-
const appDb = BaseDb.getAppDb();
|
|
13156
|
-
const results = await appDb
|
|
13157
|
-
.insert(seeds)
|
|
13158
|
-
.values(newSeeds)
|
|
13159
|
-
.returning({ uid: seeds.uid });
|
|
13160
|
-
const newUids = results.reduce((acc, result) => {
|
|
13161
|
-
if (result.uid) {
|
|
13162
|
-
acc.push(result.uid);
|
|
14466
|
+
.returning({ id: easSyncProcesses.id });
|
|
14467
|
+
return row.id;
|
|
14468
|
+
});
|
|
14469
|
+
}
|
|
14470
|
+
async function finalizeEasSyncProcessRow(id, params) {
|
|
14471
|
+
return enqueueEasSyncDbWrite(async () => {
|
|
14472
|
+
const db = BaseDb.getAppDb();
|
|
14473
|
+
if (!db) {
|
|
14474
|
+
return;
|
|
13163
14475
|
}
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
14476
|
+
const now = Date.now();
|
|
14477
|
+
await db
|
|
14478
|
+
.update(easSyncProcesses)
|
|
14479
|
+
.set({
|
|
14480
|
+
status: params.status,
|
|
14481
|
+
completedAt: now,
|
|
14482
|
+
updatedAt: now,
|
|
14483
|
+
errorMessage: params.errorMessage?.slice(0, MAX_ERROR_MESSAGE_LENGTH) ?? null,
|
|
14484
|
+
errorDetails: params.errorDetails?.slice(0, MAX_ERROR_DETAILS_LENGTH) ?? null,
|
|
14485
|
+
persistedSnapshot: JSON.stringify(params.persistedSnapshot),
|
|
14486
|
+
})
|
|
14487
|
+
.where(eq(easSyncProcesses.id, id));
|
|
14488
|
+
});
|
|
14489
|
+
}
|
|
13168
14490
|
|
|
13169
14491
|
/**
|
|
13170
|
-
*
|
|
14492
|
+
* Merge multiple EAS sync intents: full sync (no concrete address list) wins;
|
|
14493
|
+
* otherwise union addresses (first-seen casing).
|
|
13171
14494
|
*/
|
|
13172
|
-
|
|
13173
|
-
|
|
13174
|
-
|
|
14495
|
+
function mergeEasSyncRequestIntents(parts) {
|
|
14496
|
+
const norm = parts.filter((p) => p != null);
|
|
14497
|
+
if (norm.length === 0) {
|
|
14498
|
+
return {};
|
|
13175
14499
|
}
|
|
13176
|
-
|
|
13177
|
-
|
|
13178
|
-
|
|
13179
|
-
.
|
|
13180
|
-
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13187
|
-
'0x0000000000000000000000000000000000000000000000000000000000000020',
|
|
13188
|
-
];
|
|
13189
|
-
const seedUidToLocalId = new Map();
|
|
13190
|
-
const seedUidToModelType = new Map();
|
|
13191
|
-
const relatedSeedUids = new Set();
|
|
13192
|
-
const versionUidToLocalId = new Map();
|
|
13193
|
-
const versionUidToSeedUid = new Map();
|
|
13194
|
-
const propertyUidToLocalId = new Map();
|
|
13195
|
-
const saveEasSeedsToDb = async ({ itemSeeds }) => {
|
|
13196
|
-
const appDb = BaseDb.getAppDb();
|
|
13197
|
-
const seedUids = itemSeeds.map((seed) => seed.id);
|
|
13198
|
-
const existingSeedRecordsRows = await appDb
|
|
13199
|
-
.select()
|
|
13200
|
-
.from(seeds)
|
|
13201
|
-
.where(inArray(seeds.uid, seedUids));
|
|
13202
|
-
const existingSeedUids = new Set();
|
|
13203
|
-
if (existingSeedRecordsRows && existingSeedRecordsRows.length > 0) {
|
|
13204
|
-
for (const row of existingSeedRecordsRows) {
|
|
13205
|
-
if (row.uid) {
|
|
13206
|
-
existingSeedUids.add(row.uid);
|
|
13207
|
-
if (row.localId) {
|
|
13208
|
-
seedUidToLocalId.set(row.uid, row.localId);
|
|
13209
|
-
}
|
|
13210
|
-
if (row.type) {
|
|
13211
|
-
seedUidToModelType.set(row.uid, row.type);
|
|
13212
|
-
}
|
|
14500
|
+
let full = false;
|
|
14501
|
+
const addressMap = new Map();
|
|
14502
|
+
for (const p of norm) {
|
|
14503
|
+
if (!('addresses' in p) || p.addresses === undefined) {
|
|
14504
|
+
full = true;
|
|
14505
|
+
break;
|
|
14506
|
+
}
|
|
14507
|
+
for (const addr of p.addresses) {
|
|
14508
|
+
const k = addr.toLowerCase();
|
|
14509
|
+
if (!addressMap.has(k)) {
|
|
14510
|
+
addressMap.set(k, addr);
|
|
13213
14511
|
}
|
|
13214
14512
|
}
|
|
13215
14513
|
}
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
const seedByUid = new Map(itemSeeds.map((s) => [s.id, s]));
|
|
13219
|
-
for (const row of existingSeedRecordsRows) {
|
|
13220
|
-
if (!row.uid || !row.localId)
|
|
13221
|
-
continue;
|
|
13222
|
-
const attestation = seedByUid.get(row.uid);
|
|
13223
|
-
if (!attestation?.revoked)
|
|
13224
|
-
continue;
|
|
13225
|
-
if (row.revokedAt != null)
|
|
13226
|
-
continue;
|
|
13227
|
-
const revokedAt = attestation.revocationTime > 0
|
|
13228
|
-
? attestation.revocationTime
|
|
13229
|
-
: Math.floor(Date.now() / 1000);
|
|
13230
|
-
await updateSeedRevokedAt({ seedLocalId: row.localId, revokedAt });
|
|
13231
|
-
}
|
|
13232
|
-
if (newSeeds.length === 0) {
|
|
13233
|
-
return { seedUidToLocalId, seedUids };
|
|
13234
|
-
}
|
|
13235
|
-
const newSeedsData = [];
|
|
13236
|
-
for (let i = 0; i < newSeeds.length; i++) {
|
|
13237
|
-
const seed = newSeeds[i];
|
|
13238
|
-
seedUidToModelType.set(seed.id, seed.schema.schemaNames[0].name);
|
|
13239
|
-
const seedLocalId = generateId();
|
|
13240
|
-
seedUidToLocalId.set(seed.id, seedLocalId);
|
|
13241
|
-
const attestationRaw = escapeSqliteString(JSON.stringify(seed));
|
|
13242
|
-
const revokedAt = seed.revoked && seed.revocationTime != null && seed.revocationTime > 0
|
|
13243
|
-
? seed.revocationTime
|
|
13244
|
-
: seed.revoked
|
|
13245
|
-
? Math.floor(Date.now() / 1000)
|
|
13246
|
-
: undefined;
|
|
13247
|
-
newSeedsData.push({
|
|
13248
|
-
localId: seedLocalId,
|
|
13249
|
-
uid: seed.id,
|
|
13250
|
-
schemaUid: seed.schemaId,
|
|
13251
|
-
type: seed.schema.schemaNames[0].name,
|
|
13252
|
-
publisher: seed.attester,
|
|
13253
|
-
createdAt: Date.now(),
|
|
13254
|
-
attestationCreatedAt: seed.timeCreated * 1000,
|
|
13255
|
-
attestationRaw,
|
|
13256
|
-
...(revokedAt !== undefined && { revokedAt }),
|
|
13257
|
-
});
|
|
13258
|
-
seedUidToLocalId.set(seed.id, seedLocalId);
|
|
14514
|
+
if (full) {
|
|
14515
|
+
return {};
|
|
13259
14516
|
}
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
};
|
|
13263
|
-
const saveEasVersionsToDb = async ({ itemVersions }) => {
|
|
13264
|
-
const versionUids = itemVersions.map((version) => version.id);
|
|
13265
|
-
const appDb = BaseDb.getAppDb();
|
|
13266
|
-
const existingVersionRecordsRows = await appDb
|
|
13267
|
-
.select()
|
|
13268
|
-
.from(versions)
|
|
13269
|
-
.where(inArray(versions.uid, versionUids));
|
|
13270
|
-
const existingVersionUids = new Set();
|
|
13271
|
-
if (existingVersionRecordsRows && existingVersionRecordsRows.length > 0) {
|
|
13272
|
-
for (const row of existingVersionRecordsRows) {
|
|
13273
|
-
if (row.uid) {
|
|
13274
|
-
existingVersionUids.add(row.uid);
|
|
13275
|
-
if (row.localId) {
|
|
13276
|
-
versionUidToLocalId.set(row.uid, row.localId);
|
|
13277
|
-
}
|
|
13278
|
-
if (row.seedUid) {
|
|
13279
|
-
versionUidToSeedUid.set(row.uid, row.seedUid);
|
|
13280
|
-
}
|
|
13281
|
-
}
|
|
13282
|
-
}
|
|
13283
|
-
}
|
|
13284
|
-
const newVersions = itemVersions.filter((version) => !existingVersionUids.has(version.id));
|
|
13285
|
-
if (newVersions.length === 0) {
|
|
13286
|
-
return { versionUidToLocalId, versionUids };
|
|
13287
|
-
}
|
|
13288
|
-
let insertVersionsQuery = `INSERT INTO versions (local_id, uid, seed_uid, seed_local_id, seed_type, created_at,
|
|
13289
|
-
attestation_created_at,
|
|
13290
|
-
attestation_raw, publisher)
|
|
13291
|
-
VALUES `;
|
|
13292
|
-
for (let i = 0; i < newVersions.length; i++) {
|
|
13293
|
-
const version = newVersions[i];
|
|
13294
|
-
versionUidToSeedUid.set(version.id, version.refUID);
|
|
13295
|
-
const versionLocalId = generateId();
|
|
13296
|
-
versionUidToLocalId.set(version.id, versionLocalId);
|
|
13297
|
-
const seedUid = versionUidToSeedUid.get(version.id);
|
|
13298
|
-
const seedLocalId = seedUidToLocalId.get(seedUid);
|
|
13299
|
-
const seedType = seedUidToModelType.get(seedUid);
|
|
13300
|
-
const attestationRaw = escapeSqliteString(JSON.stringify(version));
|
|
13301
|
-
const publisher = escapeSqliteString(version.attester ?? '');
|
|
13302
|
-
const valuesString = `('${versionLocalId}', '${version.id}', '${seedUid}', '${seedLocalId}', '${seedType}', ${Date.now()}, ${version.timeCreated * 1000}, '${attestationRaw}', '${publisher}')`;
|
|
13303
|
-
if (i < newVersions.length - 1) {
|
|
13304
|
-
insertVersionsQuery += valuesString + ', ';
|
|
13305
|
-
}
|
|
13306
|
-
if (i === newVersions.length - 1) {
|
|
13307
|
-
insertVersionsQuery += valuesString + ';';
|
|
13308
|
-
}
|
|
13309
|
-
versionUidToLocalId.set(version.id, versionLocalId);
|
|
13310
|
-
}
|
|
13311
|
-
await appDb.run(sql.raw(insertVersionsQuery));
|
|
13312
|
-
return { versionUids };
|
|
13313
|
-
};
|
|
13314
|
-
const createMetadataRecordsForStorageTransactionId = async (storageTransactionIdProperty, modelSchema) => {
|
|
13315
|
-
// Early return if modelSchema is not provided
|
|
13316
|
-
if (!modelSchema) {
|
|
13317
|
-
console.warn('[item/events] [syncDbWithEas] modelSchema is undefined for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
|
|
13318
|
-
return;
|
|
14517
|
+
if (addressMap.size === 0) {
|
|
14518
|
+
return { addresses: [] };
|
|
13319
14519
|
}
|
|
13320
|
-
|
|
13321
|
-
|
|
13322
|
-
|
|
13323
|
-
|
|
14520
|
+
return { addresses: [...addressMap.values()] };
|
|
14521
|
+
}
|
|
14522
|
+
|
|
14523
|
+
const log = debug('seedSdk:events:easSyncManager');
|
|
14524
|
+
function toRunSyncArg(options) {
|
|
14525
|
+
if (options &&
|
|
14526
|
+
'addresses' in options &&
|
|
14527
|
+
options.addresses !== undefined) {
|
|
14528
|
+
return options;
|
|
13324
14529
|
}
|
|
13325
|
-
|
|
14530
|
+
return undefined;
|
|
14531
|
+
}
|
|
14532
|
+
const runEasSync = fromPromise(async ({ input, }) => {
|
|
14533
|
+
const rowId = await insertEasSyncProcessRow({
|
|
14534
|
+
requestPayload: input.requestPayload,
|
|
14535
|
+
persistedSnapshot: input.runningSnapshot,
|
|
14536
|
+
});
|
|
14537
|
+
const { runSyncFromEas } = await import('./syncDbWithEas-CaytdS8D.js');
|
|
13326
14538
|
try {
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for storageTransactionIdProperty: ', storageTransactionIdProperty.id);
|
|
13335
|
-
return;
|
|
13336
|
-
}
|
|
13337
|
-
const attestationData = parsedData[0].value;
|
|
13338
|
-
camelCase(attestationData.name);
|
|
13339
|
-
const propertyValue = attestationData.value;
|
|
13340
|
-
const itemStorageProperties = new Map();
|
|
13341
|
-
for (const [_propertyName, propertyDef] of Object.entries(modelSchema)) {
|
|
13342
|
-
if (propertyDef?.storageType && propertyDef.storageType === 'ItemStorage') {
|
|
13343
|
-
itemStorageProperties.set(_propertyName, propertyDef);
|
|
13344
|
-
}
|
|
13345
|
-
}
|
|
13346
|
-
if (itemStorageProperties.size === 0) {
|
|
13347
|
-
return;
|
|
13348
|
-
}
|
|
13349
|
-
const appDb = BaseDb.getAppDb();
|
|
13350
|
-
for (const [_propertyName, propertyDef] of itemStorageProperties.entries()) {
|
|
13351
|
-
const existingMetadataRecordRows = await appDb
|
|
13352
|
-
.select()
|
|
13353
|
-
.from(metadata$1)
|
|
13354
|
-
.where(and(eq(metadata$1.propertyName, _propertyName), eq(metadata$1.propertyValue, propertyValue), eq(metadata$1.versionUid, storageTransactionIdProperty.refUID)));
|
|
13355
|
-
if (existingMetadataRecordRows && existingMetadataRecordRows.length > 0) {
|
|
13356
|
-
continue;
|
|
13357
|
-
}
|
|
13358
|
-
const seedUid = versionUidToSeedUid.get(storageTransactionIdProperty.refUID);
|
|
13359
|
-
const seedLocalId = seedUidToLocalId.get(seedUid);
|
|
13360
|
-
const versionUid = storageTransactionIdProperty.refUID;
|
|
13361
|
-
const versionLocalId = versionUidToLocalId.get(versionUid);
|
|
13362
|
-
const modelType = seedUidToModelType.get(seedUid);
|
|
13363
|
-
const propertyId = modelType != null
|
|
13364
|
-
? await getPropertyIdForModelAndName(modelType, _propertyName)
|
|
13365
|
-
: null;
|
|
13366
|
-
const propertyLocalId = generateId();
|
|
13367
|
-
await appDb.insert(metadata$1).values({
|
|
13368
|
-
localId: propertyLocalId,
|
|
13369
|
-
propertyId: propertyId ?? undefined,
|
|
13370
|
-
propertyName: _propertyName,
|
|
13371
|
-
propertyValue,
|
|
13372
|
-
localStorageDir: propertyDef.localStorageDir,
|
|
13373
|
-
seedLocalId,
|
|
13374
|
-
seedUid,
|
|
13375
|
-
versionLocalId,
|
|
13376
|
-
versionUid,
|
|
13377
|
-
refValueType: 'file',
|
|
13378
|
-
refResolvedValue: `${propertyValue}${propertyDef.filenameSuffix}`,
|
|
13379
|
-
modelType: seedUidToModelType.get(seedUid),
|
|
13380
|
-
createdAt: Date.now(),
|
|
13381
|
-
updatedAt: Date.now(),
|
|
14539
|
+
await runSyncFromEas(toRunSyncArg(input.options));
|
|
14540
|
+
await finalizeEasSyncProcessRow(rowId, {
|
|
14541
|
+
status: 'completed',
|
|
14542
|
+
persistedSnapshot: {
|
|
14543
|
+
phase: 'completed',
|
|
14544
|
+
correlationIds: input.requestPayload.correlationIds,
|
|
14545
|
+
},
|
|
13382
14546
|
});
|
|
13383
14547
|
}
|
|
13384
|
-
|
|
13385
|
-
|
|
13386
|
-
const
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
const appDb = BaseDb.getAppDb();
|
|
13398
|
-
const existingMetadataRecordsRows = await appDb
|
|
13399
|
-
.select()
|
|
13400
|
-
.from(metadata$1)
|
|
13401
|
-
.where(inArray(metadata$1.uid, propertyUids));
|
|
13402
|
-
const existingPropertyRecordsUids = new Set();
|
|
13403
|
-
if (existingMetadataRecordsRows && existingMetadataRecordsRows.length > 0) {
|
|
13404
|
-
for (const row of existingMetadataRecordsRows) {
|
|
13405
|
-
if (row.uid) {
|
|
13406
|
-
existingPropertyRecordsUids.add(row.uid);
|
|
13407
|
-
if (row.localId) {
|
|
13408
|
-
propertyUidToLocalId.set(row.uid, row.localId);
|
|
13409
|
-
}
|
|
13410
|
-
}
|
|
13411
|
-
}
|
|
13412
|
-
}
|
|
13413
|
-
const newProperties = itemProperties.filter((property) => !existingPropertyRecordsUids.has(property.id));
|
|
13414
|
-
if (newProperties.length === 0) {
|
|
13415
|
-
return { propertyUidToLocalId, propertyUids };
|
|
13416
|
-
}
|
|
13417
|
-
let insertPropertiesQuery = `INSERT INTO metadata (local_id, uid, schema_uid, property_id, property_name, property_value,
|
|
13418
|
-
eas_data_type, version_uid, version_local_id, seed_uid,
|
|
13419
|
-
seed_local_id, model_type, ref_value_type, ref_seed_type,
|
|
13420
|
-
ref_schema_uid,
|
|
13421
|
-
created_at, attestation_created_at, attestation_raw,
|
|
13422
|
-
local_storage_dir, ref_resolved_value, publisher)
|
|
13423
|
-
VALUES `;
|
|
13424
|
-
for (let i = 0; i < newProperties.length; i++) {
|
|
13425
|
-
const property = newProperties[i];
|
|
13426
|
-
const propertyLocalId = generateId();
|
|
13427
|
-
// Validate and parse decodedDataJson
|
|
13428
|
-
if (!property.decodedDataJson || property.decodedDataJson.trim() === '') {
|
|
13429
|
-
console.warn('[item/events] [syncDbWithEas] empty decodedDataJson for property: ', property.id);
|
|
13430
|
-
continue;
|
|
13431
|
-
}
|
|
13432
|
-
let parsedData;
|
|
13433
|
-
try {
|
|
13434
|
-
parsedData = JSON.parse(property.decodedDataJson);
|
|
13435
|
-
}
|
|
13436
|
-
catch (error) {
|
|
13437
|
-
console.warn('[item/events] [syncDbWithEas] failed to parse decodedDataJson for property: ', property.id, error);
|
|
13438
|
-
continue;
|
|
13439
|
-
}
|
|
13440
|
-
if (!Array.isArray(parsedData) || parsedData.length === 0 || !parsedData[0]?.value) {
|
|
13441
|
-
console.warn('[item/events] [syncDbWithEas] invalid decodedDataJson structure for property: ', property.id);
|
|
13442
|
-
continue;
|
|
13443
|
-
}
|
|
13444
|
-
const metadata = parsedData[0].value;
|
|
13445
|
-
let propertyNameSnake = metadata.name;
|
|
13446
|
-
if (!propertyNameSnake) {
|
|
13447
|
-
console.warn('[item/events] [syncDbWithEas] no propertyName found for property: ', property);
|
|
13448
|
-
continue;
|
|
13449
|
-
}
|
|
13450
|
-
let isRelation = false;
|
|
13451
|
-
let refValueType;
|
|
13452
|
-
let refSeedType;
|
|
13453
|
-
let refSchemaUid;
|
|
13454
|
-
let isList = false;
|
|
13455
|
-
const schemaUid = property.schemaId;
|
|
13456
|
-
setSchemaUidForSchemaDefinition({
|
|
13457
|
-
text: propertyNameSnake,
|
|
13458
|
-
schemaUid,
|
|
14548
|
+
catch (err) {
|
|
14549
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14550
|
+
const details = err instanceof Error && err.stack
|
|
14551
|
+
? err.stack.slice(0, 2000)
|
|
14552
|
+
: undefined;
|
|
14553
|
+
await finalizeEasSyncProcessRow(rowId, {
|
|
14554
|
+
status: 'failed',
|
|
14555
|
+
errorMessage: message,
|
|
14556
|
+
errorDetails: details,
|
|
14557
|
+
persistedSnapshot: {
|
|
14558
|
+
phase: 'failed',
|
|
14559
|
+
correlationIds: input.requestPayload.correlationIds,
|
|
14560
|
+
},
|
|
13459
14561
|
});
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
metadata.value.forEach((value) => {
|
|
13474
|
-
relatedSeedUids.add(value);
|
|
13475
|
-
});
|
|
13476
|
-
}
|
|
13477
|
-
if (!isList) {
|
|
13478
|
-
if (relationValuesToExclude.includes(metadata.value)) {
|
|
13479
|
-
continue;
|
|
13480
|
-
}
|
|
13481
|
-
relatedSeedUids.add(metadata.value);
|
|
13482
|
-
}
|
|
13483
|
-
}
|
|
13484
|
-
let propertyValue = metadata.value;
|
|
13485
|
-
if (typeof propertyValue !== 'string') {
|
|
13486
|
-
propertyValue = JSON.stringify(propertyValue);
|
|
13487
|
-
}
|
|
13488
|
-
if (isRelation && !isList) {
|
|
13489
|
-
const relatedSeed = itemSeeds.find((seed) => seed.id === metadata.value);
|
|
13490
|
-
if (relatedSeed && relatedSeed.schema && relatedSeed.schema.schemaNames) {
|
|
13491
|
-
refSeedType = relatedSeed.schema.schemaNames[0].name;
|
|
13492
|
-
refSchemaUid = relatedSeed.schemaId;
|
|
13493
|
-
}
|
|
13494
|
-
}
|
|
13495
|
-
if (isRelation && isList) {
|
|
13496
|
-
const relatedSeeds = itemSeeds.filter((seed) => metadata.value.includes(seed.id));
|
|
13497
|
-
if (relatedSeeds && relatedSeeds.length > 0) {
|
|
13498
|
-
refSeedType = relatedSeeds[0].schema.schemaNames[0].name;
|
|
13499
|
-
refSchemaUid = relatedSeeds[0].schemaId;
|
|
13500
|
-
}
|
|
13501
|
-
}
|
|
13502
|
-
const propertyName = camelCase(propertyNameSnake);
|
|
13503
|
-
propertyValue = escapeSqliteString(propertyValue);
|
|
13504
|
-
const easDataType = metadata.type;
|
|
13505
|
-
const versionUid = property.refUID;
|
|
13506
|
-
const versionLocalId = versionUidToLocalId.get(versionUid);
|
|
13507
|
-
const attestationCreatedAt = property.timeCreated * 1000;
|
|
13508
|
-
const attestationRaw = escapeSqliteString(JSON.stringify(property));
|
|
13509
|
-
const seedUid = versionUidToSeedUid.get(versionUid);
|
|
13510
|
-
const seedLocalId = seedUidToLocalId.get(seedUid);
|
|
13511
|
-
const modelType = seedUidToModelType.get(seedUid);
|
|
13512
|
-
const modelName = startCase(modelType);
|
|
13513
|
-
const model = models[modelName];
|
|
13514
|
-
const modelSchema = model?.properties ? modelPropertiesToObject(model.properties) : undefined;
|
|
13515
|
-
if (propertyNameSnake === 'storage_transaction_id') {
|
|
13516
|
-
await createMetadataRecordsForStorageTransactionId(property, modelSchema);
|
|
13517
|
-
}
|
|
13518
|
-
const propertyId = modelType != null
|
|
13519
|
-
? await getPropertyIdForModelAndName(modelType, propertyName)
|
|
13520
|
-
: null;
|
|
13521
|
-
const propertyIdSql = propertyId != null ? String(propertyId) : 'NULL';
|
|
13522
|
-
const publisher = escapeSqliteString(property.attester ?? '');
|
|
13523
|
-
const valuesString = `('${propertyLocalId}', '${property.id}',
|
|
13524
|
-
'${property.schemaId}', ${propertyIdSql}, '${propertyName}',
|
|
13525
|
-
'${propertyValue}', '${easDataType}', '${versionUid}',
|
|
13526
|
-
'${versionLocalId}', '${seedUid}', '${seedLocalId}',
|
|
13527
|
-
'${modelType}', ${refValueType ? `'${refValueType}'` : 'NULL'},
|
|
13528
|
-
${refSeedType ? `'${refSeedType}'` : 'NULL'},
|
|
13529
|
-
${refSchemaUid ? `'${refSchemaUid}'` : 'NULL'},
|
|
13530
|
-
${Date.now()}, ${attestationCreatedAt}, '${attestationRaw}',
|
|
13531
|
-
${'NULL'},
|
|
13532
|
-
${'NULL'},
|
|
13533
|
-
'${publisher}')`;
|
|
13534
|
-
if (i < newProperties.length - 1) {
|
|
13535
|
-
insertPropertiesQuery += valuesString + ', ';
|
|
13536
|
-
}
|
|
13537
|
-
if (i === newProperties.length - 1) {
|
|
13538
|
-
insertPropertiesQuery += valuesString + ';';
|
|
13539
|
-
}
|
|
13540
|
-
propertyUidToLocalId.set(property.id, propertyLocalId);
|
|
13541
|
-
}
|
|
13542
|
-
if (insertPropertiesQuery.endsWith('VALUES ')) {
|
|
13543
|
-
return { propertyUids };
|
|
13544
|
-
}
|
|
13545
|
-
if (insertPropertiesQuery.endsWith(', ')) {
|
|
13546
|
-
insertPropertiesQuery = insertPropertiesQuery.slice(0, -2) + ';';
|
|
13547
|
-
}
|
|
13548
|
-
await appDb.run(sql.raw(insertPropertiesQuery));
|
|
13549
|
-
isSavingToDb = false;
|
|
13550
|
-
return { propertyUids };
|
|
14562
|
+
throw err;
|
|
14563
|
+
}
|
|
14564
|
+
});
|
|
14565
|
+
const initialContext = {
|
|
14566
|
+
runOptions: {},
|
|
14567
|
+
activeCorrelationIds: [],
|
|
14568
|
+
activePrimarySource: 'event_bus',
|
|
14569
|
+
pendingMergedOptions: undefined,
|
|
14570
|
+
pendingCorrelationIds: [],
|
|
14571
|
+
pendingPrimarySource: null,
|
|
14572
|
+
lastFinishedCorrelationIds: null,
|
|
14573
|
+
lastFinishedStatus: null,
|
|
14574
|
+
lastFinishedError: null,
|
|
13551
14575
|
};
|
|
13552
|
-
const
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
14576
|
+
const easSyncMachine = setup({
|
|
14577
|
+
types: {
|
|
14578
|
+
context: {},
|
|
14579
|
+
events: {},
|
|
14580
|
+
},
|
|
14581
|
+
actors: {
|
|
14582
|
+
runEasSync,
|
|
14583
|
+
},
|
|
14584
|
+
}).createMachine({
|
|
14585
|
+
id: MachineIds.EAS_SYNC_MANAGER,
|
|
14586
|
+
initial: 'idle',
|
|
14587
|
+
context: initialContext,
|
|
14588
|
+
states: {
|
|
14589
|
+
idle: {
|
|
14590
|
+
on: {
|
|
14591
|
+
REQUEST: {
|
|
14592
|
+
target: 'running',
|
|
14593
|
+
actions: assign({
|
|
14594
|
+
runOptions: ({ event }) => event.options === undefined
|
|
14595
|
+
? {}
|
|
14596
|
+
: mergeEasSyncRequestIntents([event.options]),
|
|
14597
|
+
activeCorrelationIds: ({ event }) => [event.correlationId],
|
|
14598
|
+
activePrimarySource: ({ event }) => event.source,
|
|
14599
|
+
}),
|
|
14600
|
+
},
|
|
14601
|
+
},
|
|
14602
|
+
},
|
|
14603
|
+
running: {
|
|
14604
|
+
on: {
|
|
14605
|
+
REQUEST: {
|
|
14606
|
+
actions: assign({
|
|
14607
|
+
pendingMergedOptions: ({ context, event }) => mergeEasSyncRequestIntents([
|
|
14608
|
+
context.runOptions,
|
|
14609
|
+
context.pendingMergedOptions,
|
|
14610
|
+
event.options === undefined ? {} : event.options,
|
|
14611
|
+
].filter((x) => x != null)),
|
|
14612
|
+
pendingCorrelationIds: ({ context, event }) => [
|
|
14613
|
+
...context.pendingCorrelationIds,
|
|
14614
|
+
event.correlationId,
|
|
14615
|
+
],
|
|
14616
|
+
pendingPrimarySource: ({ context, event }) => context.pendingPrimarySource ?? event.source,
|
|
14617
|
+
}),
|
|
14618
|
+
},
|
|
13559
14619
|
},
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
14620
|
+
invoke: {
|
|
14621
|
+
src: 'runEasSync',
|
|
14622
|
+
input: ({ context }) => ({
|
|
14623
|
+
options: context.runOptions,
|
|
14624
|
+
requestPayload: {
|
|
14625
|
+
source: context.activePrimarySource,
|
|
14626
|
+
correlationIds: context.activeCorrelationIds,
|
|
14627
|
+
options: context.runOptions,
|
|
14628
|
+
},
|
|
14629
|
+
runningSnapshot: {
|
|
14630
|
+
phase: 'running',
|
|
14631
|
+
correlationIds: context.activeCorrelationIds,
|
|
14632
|
+
},
|
|
14633
|
+
}),
|
|
14634
|
+
onDone: {
|
|
14635
|
+
target: 'afterRun',
|
|
14636
|
+
actions: assign({
|
|
14637
|
+
lastFinishedCorrelationIds: ({ context }) => [
|
|
14638
|
+
...context.activeCorrelationIds,
|
|
14639
|
+
],
|
|
14640
|
+
lastFinishedStatus: () => 'success',
|
|
14641
|
+
lastFinishedError: () => null,
|
|
14642
|
+
activeCorrelationIds: () => [],
|
|
14643
|
+
runOptions: () => ({}),
|
|
14644
|
+
}),
|
|
14645
|
+
},
|
|
14646
|
+
onError: {
|
|
14647
|
+
target: 'afterRun',
|
|
14648
|
+
actions: [
|
|
14649
|
+
assign({
|
|
14650
|
+
lastFinishedCorrelationIds: ({ context }) => [
|
|
14651
|
+
...context.activeCorrelationIds,
|
|
14652
|
+
],
|
|
14653
|
+
lastFinishedStatus: () => 'failed',
|
|
14654
|
+
lastFinishedError: ({ event }) => {
|
|
14655
|
+
const e = event.error;
|
|
14656
|
+
if (e instanceof Error) {
|
|
14657
|
+
return e.message;
|
|
14658
|
+
}
|
|
14659
|
+
return e != null ? String(e) : 'EAS sync failed';
|
|
14660
|
+
},
|
|
14661
|
+
activeCorrelationIds: () => [],
|
|
14662
|
+
runOptions: () => ({}),
|
|
14663
|
+
}),
|
|
14664
|
+
({ event }) => {
|
|
14665
|
+
log('runEasSync error', event.error);
|
|
14666
|
+
},
|
|
14667
|
+
],
|
|
14668
|
+
},
|
|
13567
14669
|
},
|
|
13568
14670
|
},
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
14671
|
+
afterRun: {
|
|
14672
|
+
always: [
|
|
14673
|
+
{
|
|
14674
|
+
guard: ({ context }) => context.pendingCorrelationIds.length > 0,
|
|
14675
|
+
target: 'running',
|
|
14676
|
+
actions: assign({
|
|
14677
|
+
runOptions: ({ context }) => mergeEasSyncRequestIntents([context.pendingMergedOptions]),
|
|
14678
|
+
activeCorrelationIds: ({ context }) => [
|
|
14679
|
+
...context.pendingCorrelationIds,
|
|
14680
|
+
],
|
|
14681
|
+
activePrimarySource: ({ context }) => context.pendingPrimarySource ?? 'event_bus',
|
|
14682
|
+
pendingMergedOptions: () => undefined,
|
|
14683
|
+
pendingCorrelationIds: () => [],
|
|
14684
|
+
pendingPrimarySource: () => null,
|
|
14685
|
+
}),
|
|
14686
|
+
},
|
|
14687
|
+
{ target: 'idle' },
|
|
14688
|
+
],
|
|
13577
14689
|
},
|
|
13578
|
-
}
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
/**
|
|
13585
|
-
* Core sync logic: fetches item attestations from EAS for configured models and given addresses,
|
|
13586
|
-
* then saves seeds, versions, and properties to the local DB.
|
|
13587
|
-
* Uses owned + watched addresses from DB when addresses are not provided.
|
|
13588
|
-
*/
|
|
13589
|
-
const runSyncFromEas = async (options) => {
|
|
13590
|
-
let addresses = options?.addresses ?? (await getAllAddressesFromDb());
|
|
13591
|
-
const additionalGetter = getGetAdditionalSyncAddresses();
|
|
13592
|
-
if (additionalGetter) {
|
|
13593
|
-
const additional = await additionalGetter();
|
|
13594
|
-
if (additional?.length) {
|
|
13595
|
-
const seen = new Set(addresses.map((a) => a.toLowerCase()));
|
|
13596
|
-
for (const addr of additional) {
|
|
13597
|
-
if (addr && !seen.has(addr.toLowerCase())) {
|
|
13598
|
-
seen.add(addr.toLowerCase());
|
|
13599
|
-
addresses = [...addresses, addr];
|
|
13600
|
-
}
|
|
13601
|
-
}
|
|
13602
|
-
}
|
|
13603
|
-
}
|
|
13604
|
-
if (!addresses || addresses.length === 0) {
|
|
14690
|
+
},
|
|
14691
|
+
});
|
|
14692
|
+
const easSyncActor = createActor(easSyncMachine);
|
|
14693
|
+
let easSyncActorStarted = false;
|
|
14694
|
+
function startEasSyncActor() {
|
|
14695
|
+
if (easSyncActorStarted) {
|
|
13605
14696
|
return;
|
|
13606
14697
|
}
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
// Skip schemas that don't have a corresponding model in the user's config
|
|
13615
|
-
// This can happen with "bytes32 image" if there's no Image model defined
|
|
13616
|
-
console.warn(`[item/events] [syncDbWithEas] Model not found for schema ${modelSchema.schema}, skipping`);
|
|
13617
|
-
continue;
|
|
13618
|
-
}
|
|
13619
|
-
try {
|
|
13620
|
-
await appDb
|
|
13621
|
-
.insert(modelUids)
|
|
13622
|
-
.values({
|
|
13623
|
-
modelId: foundModel.id,
|
|
13624
|
-
uid: modelSchema.id,
|
|
13625
|
-
})
|
|
13626
|
-
.onConflictDoNothing();
|
|
13627
|
-
}
|
|
13628
|
-
catch (err) {
|
|
13629
|
-
// Model may have been deleted by test teardown or another process; skip to avoid unhandled rejection
|
|
13630
|
-
const e = err;
|
|
13631
|
-
const code = e?.code ?? e?.rawCode ?? e?.cause?.code ?? e?.cause?.rawCode;
|
|
13632
|
-
if (code === 'SQLITE_CONSTRAINT_FOREIGNKEY' || code === 787) {
|
|
13633
|
-
continue;
|
|
13634
|
-
}
|
|
13635
|
-
throw err;
|
|
13636
|
-
}
|
|
13637
|
-
schemaUids.push(modelSchema.id);
|
|
13638
|
-
}
|
|
13639
|
-
// If no schemas were found, skip the rest of the sync process
|
|
13640
|
-
// This can happen when models exist but don't have schemas registered in EAS yet
|
|
13641
|
-
if (schemaUids.length === 0) {
|
|
13642
|
-
return;
|
|
14698
|
+
easSyncActorStarted = true;
|
|
14699
|
+
easSyncActor.start();
|
|
14700
|
+
}
|
|
14701
|
+
function newCorrelationId() {
|
|
14702
|
+
const c = globalThis.crypto;
|
|
14703
|
+
if (c?.randomUUID) {
|
|
14704
|
+
return c.randomUUID();
|
|
13643
14705
|
}
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
const itemVersions = await getItemVersionsFromEas({
|
|
13653
|
-
seedUids,
|
|
13654
|
-
excludeRevoked: false,
|
|
14706
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
14707
|
+
}
|
|
14708
|
+
function requestEasSyncFromEventBus() {
|
|
14709
|
+
startEasSyncActor();
|
|
14710
|
+
easSyncActor.send({
|
|
14711
|
+
type: 'REQUEST',
|
|
14712
|
+
correlationId: newCorrelationId(),
|
|
14713
|
+
source: 'event_bus',
|
|
13655
14714
|
});
|
|
13656
|
-
|
|
13657
|
-
|
|
14715
|
+
}
|
|
14716
|
+
function requestEasSyncFromAddressChange(addresses) {
|
|
14717
|
+
startEasSyncActor();
|
|
14718
|
+
easSyncActor.send({
|
|
14719
|
+
type: 'REQUEST',
|
|
14720
|
+
correlationId: newCorrelationId(),
|
|
14721
|
+
options: { addresses },
|
|
14722
|
+
source: 'address_change',
|
|
13658
14723
|
});
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
14724
|
+
}
|
|
14725
|
+
function requestEasSyncFromModelsInit() {
|
|
14726
|
+
startEasSyncActor();
|
|
14727
|
+
easSyncActor.send({
|
|
14728
|
+
type: 'REQUEST',
|
|
14729
|
+
correlationId: newCorrelationId(),
|
|
14730
|
+
source: 'models_init',
|
|
13662
14731
|
});
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
14732
|
+
}
|
|
14733
|
+
function sendEasSyncClientRequest(correlationId, options) {
|
|
14734
|
+
startEasSyncActor();
|
|
14735
|
+
easSyncActor.send({
|
|
14736
|
+
type: 'REQUEST',
|
|
14737
|
+
correlationId,
|
|
14738
|
+
options,
|
|
14739
|
+
source: 'client_api',
|
|
13667
14740
|
});
|
|
13668
|
-
|
|
13669
|
-
};
|
|
13670
|
-
const syncDbWithEasHandler = throttle(async (_) => {
|
|
13671
|
-
await runSyncFromEas();
|
|
13672
|
-
}, 30000, {
|
|
13673
|
-
leading: true,
|
|
13674
|
-
trailing: false,
|
|
13675
|
-
});
|
|
14741
|
+
}
|
|
13676
14742
|
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
};
|
|
14743
|
+
var easSyncManager = /*#__PURE__*/Object.freeze({
|
|
14744
|
+
__proto__: null,
|
|
14745
|
+
easSyncActor: easSyncActor,
|
|
14746
|
+
easSyncMachine: easSyncMachine,
|
|
14747
|
+
requestEasSyncFromAddressChange: requestEasSyncFromAddressChange,
|
|
14748
|
+
requestEasSyncFromEventBus: requestEasSyncFromEventBus,
|
|
14749
|
+
requestEasSyncFromModelsInit: requestEasSyncFromModelsInit,
|
|
14750
|
+
sendEasSyncClientRequest: sendEasSyncClientRequest,
|
|
14751
|
+
startEasSyncActor: startEasSyncActor
|
|
14752
|
+
});
|
|
13688
14753
|
|
|
13689
14754
|
/**
|
|
13690
14755
|
* @deprecated Use BaseArweaveClient.setHost() instead.
|
|
13691
14756
|
* This function is kept for backward compatibility but will be removed in a future version.
|
|
13692
14757
|
*/
|
|
13693
14758
|
const setArweaveDomain = (newDomain) => {
|
|
13694
|
-
BaseArweaveClient.
|
|
14759
|
+
BaseArweaveClient.setPreferredReadGateway(newDomain);
|
|
13695
14760
|
};
|
|
13696
14761
|
|
|
13697
|
-
const logger$
|
|
14762
|
+
const logger$b = debug('seedSdk:services:events');
|
|
13698
14763
|
const handleServiceSaveState = (event) => {
|
|
13699
14764
|
const { state, serviceId } = event;
|
|
13700
|
-
logger$
|
|
14765
|
+
logger$b(`[browser] [service.saveState.request] serviceId: ${serviceId}`);
|
|
13701
14766
|
// TODO: This is called from Node as well. Do we need it? If so, need to generalize this to all platforms.
|
|
13702
14767
|
// localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
|
|
13703
14768
|
};
|
|
@@ -13706,7 +14771,8 @@ const setupServicesEventHandlers = () => {
|
|
|
13706
14771
|
};
|
|
13707
14772
|
|
|
13708
14773
|
const setupAllItemsEventHandlers = () => {
|
|
13709
|
-
|
|
14774
|
+
startEasSyncActor();
|
|
14775
|
+
eventEmitter.addListener('syncDbWithEas', requestEasSyncFromEventBus);
|
|
13710
14776
|
};
|
|
13711
14777
|
// Note: getAreItemEventHandlersReady removed - was only used by useItemIsReady hook which has been removed
|
|
13712
14778
|
|
|
@@ -13740,9 +14806,9 @@ class BasePathResolver {
|
|
|
13740
14806
|
}
|
|
13741
14807
|
}
|
|
13742
14808
|
|
|
13743
|
-
const logger$
|
|
14809
|
+
const logger$a = debug('seedSdk:ClientManager:initialize');
|
|
13744
14810
|
const platformClassesInit = fromCallback(({ sendBack, input: { context, event } }) => {
|
|
13745
|
-
logger$
|
|
14811
|
+
logger$a('initialize from ClientManager');
|
|
13746
14812
|
const { isInitialized } = context;
|
|
13747
14813
|
if (!event || !('options' in event)) {
|
|
13748
14814
|
throw new Error('Initialize event must include options');
|
|
@@ -13778,20 +14844,20 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
13778
14844
|
let PathResolver;
|
|
13779
14845
|
let EasClient;
|
|
13780
14846
|
if (isBrowser()) {
|
|
13781
|
-
FileManager = (await import('./FileManager-
|
|
13782
|
-
Db = (await import('./Db-
|
|
13783
|
-
QueryClient = (await import('./QueryClient-
|
|
13784
|
-
ArweaveClient = (await import('./ArweaveClient-
|
|
13785
|
-
PathResolver = (await import('./PathResolver-
|
|
13786
|
-
EasClient = (await import('./EasClient-
|
|
14847
|
+
FileManager = (await import('./FileManager-C2uXql_C.js')).FileManager;
|
|
14848
|
+
Db = (await import('./Db-B7whB3oJ.js')).Db;
|
|
14849
|
+
QueryClient = (await import('./QueryClient-PqOg8mcw.js')).QueryClient;
|
|
14850
|
+
ArweaveClient = (await import('./ArweaveClient-C-eLH0zU.js')).ArweaveClient;
|
|
14851
|
+
PathResolver = (await import('./PathResolver-DnrG1hUX.js')).PathResolver;
|
|
14852
|
+
EasClient = (await import('./EasClient-CFguAKBp.js')).EasClient;
|
|
13787
14853
|
}
|
|
13788
14854
|
else if (isNode()) {
|
|
13789
|
-
FileManager = (await import('./FileManager-
|
|
13790
|
-
Db = (await import('./Db-
|
|
13791
|
-
QueryClient = (await import('./QueryClient-
|
|
13792
|
-
ArweaveClient = (await import('./ArweaveClient-
|
|
13793
|
-
PathResolver = (await import('./PathResolver-
|
|
13794
|
-
EasClient = (await import('./EasClient-
|
|
14855
|
+
FileManager = (await import('./FileManager-BR3jtuSl.js')).FileManager;
|
|
14856
|
+
Db = (await import('./Db-nir1xVHg.js')).Db;
|
|
14857
|
+
QueryClient = (await import('./QueryClient-DJOrJZRR.js')).QueryClient;
|
|
14858
|
+
ArweaveClient = (await import('./ArweaveClient-B-vm2Xae.js')).ArweaveClient;
|
|
14859
|
+
PathResolver = (await import('./PathResolver-CZoSnHBU.js')).PathResolver;
|
|
14860
|
+
EasClient = (await import('./EasClient-BH_feMaX.js')).EasClient;
|
|
13795
14861
|
}
|
|
13796
14862
|
else {
|
|
13797
14863
|
throw new Error(`Unable to determine environment. isBrowser()=${isBrowser()}, isNode()=${isNode()}. Platform-specific implementations could not be loaded.`);
|
|
@@ -13865,11 +14931,14 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
13865
14931
|
dbConfig,
|
|
13866
14932
|
schemaFile,
|
|
13867
14933
|
schema,
|
|
13868
|
-
syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ??
|
|
14934
|
+
syncFromEasOnAddressChange: options.syncFromEasOnAddressChange ?? true,
|
|
13869
14935
|
} });
|
|
13870
14936
|
if (arweaveDomain) {
|
|
13871
14937
|
setArweaveDomain(arweaveDomain);
|
|
13872
14938
|
}
|
|
14939
|
+
void ensureReadGatewaySelected().catch(() => {
|
|
14940
|
+
/* non-blocking warm-up for read gateway probe */
|
|
14941
|
+
});
|
|
13873
14942
|
// Models are now Model instances, no registration needed
|
|
13874
14943
|
// They should be created via Model.create() and are accessible via Model static methods
|
|
13875
14944
|
setupAllItemsEventHandlers();
|
|
@@ -13905,15 +14974,15 @@ const platformClassesInit = fromCallback(({ sendBack, input: { context, event }
|
|
|
13905
14974
|
};
|
|
13906
14975
|
});
|
|
13907
14976
|
|
|
13908
|
-
const logger$
|
|
13909
|
-
const saveAppState
|
|
14977
|
+
const logger$9 = debug('seedSdk:client:writeToDb');
|
|
14978
|
+
const saveAppState = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
13910
14979
|
const _saveAppState = async () => {
|
|
13911
14980
|
try {
|
|
13912
14981
|
const appDb = BaseDb.getAppDb();
|
|
13913
14982
|
if (!appDb) {
|
|
13914
14983
|
// In test environments, continue anyway
|
|
13915
14984
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13916
|
-
logger$
|
|
14985
|
+
logger$9('[client/actors] [saveAppState] App DB not found, but continuing in test environment');
|
|
13917
14986
|
return;
|
|
13918
14987
|
}
|
|
13919
14988
|
throw new Error('App DB not found');
|
|
@@ -13929,13 +14998,13 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
13929
14998
|
value: JSON.stringify(value),
|
|
13930
14999
|
},
|
|
13931
15000
|
});
|
|
13932
|
-
logger$
|
|
15001
|
+
logger$9('result', result);
|
|
13933
15002
|
}
|
|
13934
15003
|
catch (error) {
|
|
13935
|
-
logger$
|
|
15004
|
+
logger$9('[client/actors] [saveAppState] Error saving app state:', error);
|
|
13936
15005
|
// In test environments, continue anyway
|
|
13937
15006
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13938
|
-
logger$
|
|
15007
|
+
logger$9('[client/actors] [saveAppState] Continuing despite error in test environment');
|
|
13939
15008
|
return;
|
|
13940
15009
|
}
|
|
13941
15010
|
throw error;
|
|
@@ -13950,10 +15019,10 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
13950
15019
|
});
|
|
13951
15020
|
})
|
|
13952
15021
|
.catch((error) => {
|
|
13953
|
-
logger$
|
|
15022
|
+
logger$9('[client/actors] [saveAppState] Error in promise chain:', error);
|
|
13954
15023
|
// In test environments, still send success to allow state machine to progress
|
|
13955
15024
|
if (process.env.NODE_ENV === 'test' || process.env.IS_SEED_DEV) {
|
|
13956
|
-
logger$
|
|
15025
|
+
logger$9('[client/actors] [saveAppState] Sending success despite error in test environment');
|
|
13957
15026
|
sendBack({
|
|
13958
15027
|
type: 'saveAppStateSuccess',
|
|
13959
15028
|
key,
|
|
@@ -13966,222 +15035,6 @@ const saveAppState$1 = fromCallback(({ sendBack, input: { key, value } }) => {
|
|
|
13966
15035
|
});
|
|
13967
15036
|
});
|
|
13968
15037
|
|
|
13969
|
-
const GET_FILES_METADATA = graphql(/* GraphQL */ `
|
|
13970
|
-
query GetFilesMetadata($where: AttestationWhereInput!) {
|
|
13971
|
-
filesMetadata: attestations(
|
|
13972
|
-
where: $where
|
|
13973
|
-
orderBy: [{ timeCreated: desc }]
|
|
13974
|
-
) {
|
|
13975
|
-
...attestationFields
|
|
13976
|
-
}
|
|
13977
|
-
}
|
|
13978
|
-
`);
|
|
13979
|
-
|
|
13980
|
-
const getMetadata = async (props) => {
|
|
13981
|
-
const appDb = BaseDb.getAppDb();
|
|
13982
|
-
let storageTransactionId;
|
|
13983
|
-
if (props) {
|
|
13984
|
-
storageTransactionId = props.storageTransactionId;
|
|
13985
|
-
}
|
|
13986
|
-
const whereClauses = [];
|
|
13987
|
-
if (storageTransactionId) {
|
|
13988
|
-
whereClauses.push(eq(metadata$1.propertyName, 'storageTransactionId'));
|
|
13989
|
-
whereClauses.push(eq(metadata$1.propertyValue, storageTransactionId));
|
|
13990
|
-
}
|
|
13991
|
-
const metadataRows = await appDb
|
|
13992
|
-
.select()
|
|
13993
|
-
.from(metadata$1)
|
|
13994
|
-
.where(and(...whereClauses));
|
|
13995
|
-
if (!metadataRows || metadataRows.length === 0) {
|
|
13996
|
-
return;
|
|
13997
|
-
}
|
|
13998
|
-
return metadataRows[0];
|
|
13999
|
-
};
|
|
14000
|
-
|
|
14001
|
-
const saveMetadata = async (metadataRecord, metadataValues) => {
|
|
14002
|
-
if (!metadataRecord.localId) {
|
|
14003
|
-
return;
|
|
14004
|
-
}
|
|
14005
|
-
const appDb = BaseDb.getAppDb();
|
|
14006
|
-
await appDb
|
|
14007
|
-
.update(metadata$1)
|
|
14008
|
-
.set({
|
|
14009
|
-
...metadataValues,
|
|
14010
|
-
updatedAt: Date.now(),
|
|
14011
|
-
})
|
|
14012
|
-
.where(eq(metadata$1.localId, metadataRecord.localId));
|
|
14013
|
-
};
|
|
14014
|
-
|
|
14015
|
-
const saveAppState = async (key, value) => {
|
|
14016
|
-
const appDb = BaseDb.getAppDb();
|
|
14017
|
-
await appDb
|
|
14018
|
-
.insert(appState)
|
|
14019
|
-
.values({
|
|
14020
|
-
key,
|
|
14021
|
-
value,
|
|
14022
|
-
})
|
|
14023
|
-
.onConflictDoUpdate({
|
|
14024
|
-
target: appState.key,
|
|
14025
|
-
set: {
|
|
14026
|
-
value,
|
|
14027
|
-
},
|
|
14028
|
-
});
|
|
14029
|
-
};
|
|
14030
|
-
|
|
14031
|
-
const logger$9 = debug('seedSdk:files:download');
|
|
14032
|
-
// syncDbFiles helper - internal service removed, functionality moved here
|
|
14033
|
-
const syncDbFiles = async (endpoints) => {
|
|
14034
|
-
// TODO: Implement syncDbFiles functionality if needed
|
|
14035
|
-
// This was previously in @/services/internal/helpers
|
|
14036
|
-
logger$9('[download] syncDbFiles called but not yet implemented');
|
|
14037
|
-
return Promise.resolve();
|
|
14038
|
-
};
|
|
14039
|
-
const downloadAllFilesRequestHandler = async ({ endpoints, eventId, }) => {
|
|
14040
|
-
if (!isBrowser()) {
|
|
14041
|
-
return;
|
|
14042
|
-
}
|
|
14043
|
-
await syncDbFiles();
|
|
14044
|
-
eventEmitter.emit('fs.downloadAll.success', { eventId });
|
|
14045
|
-
eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
|
|
14046
|
-
};
|
|
14047
|
-
const downloadAllFilesBinaryRequestHandler = async () => {
|
|
14048
|
-
let addresses;
|
|
14049
|
-
if (BaseDb.isAppDbReady()) {
|
|
14050
|
-
addresses = await getAllAddressesFromDb();
|
|
14051
|
-
}
|
|
14052
|
-
if (!BaseDb.isAppDbReady()) {
|
|
14053
|
-
// Wait for ClientManager to be ready (DB_INIT state or later)
|
|
14054
|
-
const clientManagerMod = await Promise.resolve().then(function () { return ClientManager$1; });
|
|
14055
|
-
const { getClient } = clientManagerMod;
|
|
14056
|
-
const clientManager = getClient();
|
|
14057
|
-
const clientService = clientManager.getService();
|
|
14058
|
-
await waitFor(clientService, (snapshot) => {
|
|
14059
|
-
const state = snapshot.value;
|
|
14060
|
-
return state === 'dbInit' ||
|
|
14061
|
-
state === 'saveConfig' ||
|
|
14062
|
-
state === 'processSchemaFiles' ||
|
|
14063
|
-
state === 'addModelsToStore' ||
|
|
14064
|
-
state === 'addModelsToDb' ||
|
|
14065
|
-
state === 'idle';
|
|
14066
|
-
}, { timeout: 30000 });
|
|
14067
|
-
addresses = await getAllAddressesFromDb();
|
|
14068
|
-
}
|
|
14069
|
-
if (!addresses || addresses.length === 0) {
|
|
14070
|
-
return;
|
|
14071
|
-
}
|
|
14072
|
-
const queryClient = BaseQueryClient.getQueryClient();
|
|
14073
|
-
const easClient = BaseEasClient.getEasClient();
|
|
14074
|
-
const { filesMetadata } = await queryClient.fetchQuery({
|
|
14075
|
-
queryKey: ['getFilesMetadata', ...addresses],
|
|
14076
|
-
queryFn: async () => easClient.request(GET_FILES_METADATA, {
|
|
14077
|
-
where: {
|
|
14078
|
-
attester: {
|
|
14079
|
-
in: addresses,
|
|
14080
|
-
},
|
|
14081
|
-
schema: {
|
|
14082
|
-
is: {
|
|
14083
|
-
id: {
|
|
14084
|
-
equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
|
|
14085
|
-
},
|
|
14086
|
-
},
|
|
14087
|
-
},
|
|
14088
|
-
},
|
|
14089
|
-
}),
|
|
14090
|
-
});
|
|
14091
|
-
const filesRoot = BaseFileManager.getWorkingDir();
|
|
14092
|
-
await BaseFileManager.createDirIfNotExists(filesRoot);
|
|
14093
|
-
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('html'));
|
|
14094
|
-
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('json'));
|
|
14095
|
-
await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath('images'));
|
|
14096
|
-
const appDb = BaseDb.getAppDb();
|
|
14097
|
-
if (!appDb) {
|
|
14098
|
-
console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available');
|
|
14099
|
-
return [];
|
|
14100
|
-
}
|
|
14101
|
-
const excludedTransactionsQuery = await appDb
|
|
14102
|
-
.select()
|
|
14103
|
-
.from(appState)
|
|
14104
|
-
.where(eq(appState.key, 'excludedTransactions'));
|
|
14105
|
-
let excludedTransactions = new Set();
|
|
14106
|
-
if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
|
|
14107
|
-
const valueString = excludedTransactionsQuery[0].value;
|
|
14108
|
-
if (valueString) {
|
|
14109
|
-
const excludedTransactionsArray = JSON.parse(valueString);
|
|
14110
|
-
excludedTransactions = new Set(excludedTransactionsArray);
|
|
14111
|
-
}
|
|
14112
|
-
}
|
|
14113
|
-
const transactionIds = [];
|
|
14114
|
-
for (const fileMetadata of filesMetadata) {
|
|
14115
|
-
// Validate and parse decodedDataJson
|
|
14116
|
-
if (!fileMetadata.decodedDataJson || fileMetadata.decodedDataJson.trim() === '') {
|
|
14117
|
-
console.warn('[events/files] [download] empty decodedDataJson for fileMetadata: ', fileMetadata.id);
|
|
14118
|
-
continue;
|
|
14119
|
-
}
|
|
14120
|
-
let json;
|
|
14121
|
-
try {
|
|
14122
|
-
json = JSON.parse(fileMetadata.decodedDataJson);
|
|
14123
|
-
}
|
|
14124
|
-
catch (error) {
|
|
14125
|
-
console.warn('[events/files] [download] failed to parse decodedDataJson for fileMetadata: ', fileMetadata.id, error);
|
|
14126
|
-
continue;
|
|
14127
|
-
}
|
|
14128
|
-
if (!Array.isArray(json) || json.length === 0 || !json[0]?.value?.value) {
|
|
14129
|
-
console.warn('[events/files] [download] invalid decodedDataJson structure for fileMetadata: ', fileMetadata.id);
|
|
14130
|
-
continue;
|
|
14131
|
-
}
|
|
14132
|
-
const transactionId = json[0].value.value;
|
|
14133
|
-
if (excludedTransactions.has(transactionId)) {
|
|
14134
|
-
continue;
|
|
14135
|
-
}
|
|
14136
|
-
transactionIds.push(transactionId);
|
|
14137
|
-
}
|
|
14138
|
-
const transactionIdsToDownload = [];
|
|
14139
|
-
for (const transactionId of transactionIds) {
|
|
14140
|
-
try {
|
|
14141
|
-
// Use BaseArweaveClient for transaction status check
|
|
14142
|
-
const status = await BaseArweaveClient.getTransactionStatus(transactionId);
|
|
14143
|
-
if (status.status !== 200) {
|
|
14144
|
-
logger$9(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`);
|
|
14145
|
-
excludedTransactions.add(transactionId);
|
|
14146
|
-
await saveAppState('excludedTransactions', JSON.stringify(Array.from(excludedTransactions)));
|
|
14147
|
-
continue;
|
|
14148
|
-
}
|
|
14149
|
-
// Use BaseArweaveClient for getting transaction tags
|
|
14150
|
-
const tags = await queryClient.fetchQuery({
|
|
14151
|
-
queryKey: ['getTransactionTags', transactionId],
|
|
14152
|
-
queryFn: async () => BaseArweaveClient.getTransactionTags(transactionId),
|
|
14153
|
-
});
|
|
14154
|
-
if (tags && tags.length > 0) {
|
|
14155
|
-
for (const { name, value } of tags) {
|
|
14156
|
-
if (name === 'Content-SHA-256') {
|
|
14157
|
-
const metadataRecord = await getMetadata({
|
|
14158
|
-
storageTransactionId: transactionId,
|
|
14159
|
-
});
|
|
14160
|
-
if (metadataRecord) {
|
|
14161
|
-
await saveMetadata(metadataRecord, {
|
|
14162
|
-
contentHash: value,
|
|
14163
|
-
});
|
|
14164
|
-
}
|
|
14165
|
-
}
|
|
14166
|
-
}
|
|
14167
|
-
}
|
|
14168
|
-
transactionIdsToDownload.push(transactionId);
|
|
14169
|
-
}
|
|
14170
|
-
catch (error) {
|
|
14171
|
-
logger$9(error);
|
|
14172
|
-
}
|
|
14173
|
-
}
|
|
14174
|
-
await BaseFileManager.downloadAllFiles({
|
|
14175
|
-
transactionIds: transactionIdsToDownload,
|
|
14176
|
-
arweaveHost: BaseArweaveClient.getHost(),
|
|
14177
|
-
excludedTransactions,
|
|
14178
|
-
});
|
|
14179
|
-
await BaseFileManager.resizeAllImages({
|
|
14180
|
-
width: 480,
|
|
14181
|
-
height: 480,
|
|
14182
|
-
});
|
|
14183
|
-
};
|
|
14184
|
-
|
|
14185
15038
|
let isInitialized = false;
|
|
14186
15039
|
const fsInitHandler = async () => {
|
|
14187
15040
|
if (isInitialized) {
|
|
@@ -14347,7 +15200,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
14347
15200
|
}
|
|
14348
15201
|
const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
|
|
14349
15202
|
// Fetch schemas from EAS in background - do not block init. EAS can be slow (10s+);
|
|
14350
|
-
// modelUids will be populated async and
|
|
15203
|
+
// modelUids will be populated async and EAS sync orchestrator runs when done.
|
|
14351
15204
|
const fetchEasAndPopulateModelUids = async () => {
|
|
14352
15205
|
try {
|
|
14353
15206
|
const queryClient = BaseQueryClient.getQueryClient();
|
|
@@ -14380,7 +15233,8 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
|
|
|
14380
15233
|
}
|
|
14381
15234
|
}
|
|
14382
15235
|
}
|
|
14383
|
-
|
|
15236
|
+
const { requestEasSyncFromModelsInit } = await Promise.resolve().then(function () { return easSyncManager; });
|
|
15237
|
+
requestEasSyncFromModelsInit();
|
|
14384
15238
|
}
|
|
14385
15239
|
else {
|
|
14386
15240
|
logger$6('[client/actors] [addModelsToDb] No schemas found from EAS, but continuing');
|
|
@@ -16830,16 +17684,19 @@ function addressesFromPersistedAddressValue(value) {
|
|
|
16830
17684
|
return out;
|
|
16831
17685
|
}
|
|
16832
17686
|
function maybeRunSyncFromEasAfterAddressSave({ context, event, }) {
|
|
17687
|
+
const merged = addressesFromPersistedAddressValue(event.value);
|
|
16833
17688
|
if (!context.syncFromEasOnAddressChange)
|
|
16834
17689
|
return;
|
|
16835
17690
|
if (event.key !== "addresses")
|
|
16836
17691
|
return;
|
|
16837
|
-
const merged = addressesFromPersistedAddressValue(event.value);
|
|
16838
17692
|
if (merged.length === 0)
|
|
16839
17693
|
return;
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
}
|
|
17694
|
+
try {
|
|
17695
|
+
requestEasSyncFromAddressChange(merged);
|
|
17696
|
+
}
|
|
17697
|
+
catch (err) {
|
|
17698
|
+
logSyncAfterAddressSave("requestEasSyncFromAddressChange after address save failed", err);
|
|
17699
|
+
}
|
|
16843
17700
|
}
|
|
16844
17701
|
function emitAddressesPersistedIfAddressesKey(event) {
|
|
16845
17702
|
if (event.key !== "addresses")
|
|
@@ -16857,7 +17714,7 @@ const clientManagerMachine = setup({
|
|
|
16857
17714
|
fileSystemInit,
|
|
16858
17715
|
dbInit,
|
|
16859
17716
|
saveConfig,
|
|
16860
|
-
saveAppState
|
|
17717
|
+
saveAppState,
|
|
16861
17718
|
addModelsToStore,
|
|
16862
17719
|
addModelsToDb,
|
|
16863
17720
|
processSchemaFiles,
|
|
@@ -17181,7 +18038,16 @@ const clientInstance = {
|
|
|
17181
18038
|
*/
|
|
17182
18039
|
syncFromEas: async (options) => {
|
|
17183
18040
|
ensureInitialized();
|
|
17184
|
-
|
|
18041
|
+
startEasSyncActor();
|
|
18042
|
+
const correlationId = typeof globalThis.crypto?.randomUUID === 'function'
|
|
18043
|
+
? globalThis.crypto.randomUUID()
|
|
18044
|
+
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
18045
|
+
sendEasSyncClientRequest(correlationId, options);
|
|
18046
|
+
await waitFor(easSyncActor, (snapshot) => snapshot.context.lastFinishedCorrelationIds?.includes(correlationId) ?? false);
|
|
18047
|
+
const snap = easSyncActor.getSnapshot();
|
|
18048
|
+
if (snap.context.lastFinishedStatus === 'failed') {
|
|
18049
|
+
throw new Error(snap.context.lastFinishedError ?? 'EAS sync failed');
|
|
18050
|
+
}
|
|
17185
18051
|
},
|
|
17186
18052
|
addModel: async (modelDef) => {
|
|
17187
18053
|
const db = await BaseDb.getAppDb();
|
|
@@ -17391,7 +18257,7 @@ const saveDraftLogger = debug('seedSdk:model:saveDraftToDb');
|
|
|
17391
18257
|
// Lazy import cache for ModelProperty to avoid circular dependency
|
|
17392
18258
|
// Eagerly start loading to minimize delay on first access
|
|
17393
18259
|
let ModelPropertyClass = null;
|
|
17394
|
-
const modelPropertyImportPromise = import('./ModelProperty-
|
|
18260
|
+
const modelPropertyImportPromise = import('./ModelProperty-CIeLasI4.js')
|
|
17395
18261
|
.then(module => {
|
|
17396
18262
|
ModelPropertyClass = module.ModelProperty;
|
|
17397
18263
|
return ModelPropertyClass;
|
|
@@ -17408,7 +18274,7 @@ function getModelProperty() {
|
|
|
17408
18274
|
}
|
|
17409
18275
|
// Lazy import cache for Schema to avoid circular dependency
|
|
17410
18276
|
let SchemaClass = null;
|
|
17411
|
-
const schemaImportPromise = (async () => { const
|
|
18277
|
+
const schemaImportPromise = (async () => { const _mod_10 = await import('./Schema-B3YQHTtu.js'); return _mod_10.b; })()
|
|
17412
18278
|
.then(module => {
|
|
17413
18279
|
SchemaClass = module.Schema;
|
|
17414
18280
|
return SchemaClass;
|
|
@@ -19148,5 +20014,5 @@ var Model$1 = /*#__PURE__*/Object.freeze({
|
|
|
19148
20014
|
const TModelValues = Type.Record(Type.String(), Type.Any());
|
|
19149
20015
|
const TModelSchema = Type.Record(Type.String(), TProperty);
|
|
19150
20016
|
|
|
19151
|
-
export { getItemData as $, models$1 as A, Boolean$1 as B, properties as C, Date$1 as D, isValidEasAttestationUid as E, File$1 as F, getLatestPublishedVersionRow as G, Html as H, Image as I, Json as J, modelPropertiesToObject as K, List as L, Model as M, Number$1 as N, parseListPropertyValueFromStorage as O, Property as P, getCorrectId as Q, Relation as R, INTERNAL_PROPERTY_NAMES as S, TModelValues as T, defaultAttestationData as U, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as V, INTERNAL_DATA_TYPES as W, toSnakeCase as X, getEasSchemaUidForSchemaDefinition as Y, ZERO_BYTES32 as Z, getEasSchemaForItemProperty as _, TModelSchema as a,
|
|
19152
|
-
//# sourceMappingURL=index-
|
|
20017
|
+
export { getItemData as $, models$1 as A, Boolean$1 as B, properties as C, Date$1 as D, isValidEasAttestationUid as E, File$1 as F, getLatestPublishedVersionRow as G, Html as H, Image as I, Json as J, modelPropertiesToObject as K, List as L, Model as M, Number$1 as N, parseListPropertyValueFromStorage as O, Property as P, getCorrectId as Q, Relation as R, INTERNAL_PROPERTY_NAMES as S, TModelValues as T, defaultAttestationData as U, VERSION_SCHEMA_UID_OPTIMISM_SEPOLIA as V, INTERNAL_DATA_TYPES as W, toSnakeCase as X, getEasSchemaUidForSchemaDefinition as Y, ZERO_BYTES32 as Z, getEasSchemaForItemProperty as _, TModelSchema as a, compareMetadataRowsLatestFirst as a$, resolveStorageNameToSchemaName as a0, appState as a1, BasePathResolver as a2, SEED_CONFIG_FILE as a3, SEED_CONFIG_FALLBACKS as a4, BaseEasClient as a5, EAS_ENDPOINT as a6, BaseQueryClient as a7, arweaveL1FinalizeJobs as a8, config as a9, GET_SEEDS as aA, GET_VERSIONS as aB, GET_PROPERTIES as aC, setSchemaUidForSchemaDefinition as aD, parseEasRelationPropertyName as aE, addModelsToDb$1 as aF, SCHEMA_NJK as aG, ItemProperty as aH, ClientManager as aI, INIT_SCRIPT_SUCCESS_MESSAGE as aJ, SCHEMA_TS as aK, getRefValueType as aL, importJsonSchema as aM, loadSchemaFromFile as aN, readJsonImportFile as aO, syncSchemaFromSource as aP, transformImportToSchemaFile as aQ, writeProcessMachine as aR, getModelIdByFileId as aS, waitForEntityIdle as aT, createReactiveProxy as aU, findEntity as aV, forceRemoveFromCaches as aW, runDestroyLifecycle as aX, getModelId as aY, isPlaceholderUid as aZ, normalizeBytes32Hex as a_, easSyncProcesses as aa, metadata$1 as ab, modelRelations as ac, modelSchemas as ad, modelUids as ae, modelsRelations as af, propertiesRelations as ag, propertyUidRelations as ah, propertyUids as ai, publishProcesses as aj, schemas as ak, uploadProcesses as al, versions as am, graphql as an, getPropertyIdForModelAndName as ao, getAllAddressesFromDb as ap, getModelSchemasFromEas as aq, getSeedsFromSchemaUids as ar, getItemVersionsFromEas as as, getItemPropertiesFromEas as at, pickLatestPropertyAttestationsByRefAndSchema as au, scheduleBulkFilesDownloadFromEasSync as av, eventEmitter as aw, EAS_SEED_DATA_SYNCED_TO_DB_EVENT as ax, generateId as ay, escapeSqliteString as az, ModelPropertyDataTypes as b, isInternalSchema as b$, getArweaveUrlForTransaction as b0, ADDRESSES_PERSISTED_EVENT as b1, parseAddressesPersistedPayload as b2, getClient as b3, ClientManagerState as b4, MachineIds as b5, createNewItem as b6, getVersionData$1 as b7, getMetadataLatest as b8, loadAllSchemasFromDb as b9, queryArweaveGatewayTransaction as bA, queryArweaveGatewayTransactionWithFallback as bB, ensureReadGatewaySelected as bC, invalidateReadGatewayCache as bD, resetArweaveReadGatewayForTests as bE, setUploadExecutor as bF, getUploadExecutor as bG, setGetPublisherForNewSeeds as bH, getGetPublisherForNewSeeds as bI, setRevokeExecutor as bJ, getRevokeExecutor as bK, setAdditionalSyncAddresses as bL, createSchema as bM, readSchema as bN, listCompleteSchemaFiles as bO, getSchemaNameFromId as bP, easSyncActor as bQ, startEasSyncActor as bR, sendEasSyncClientRequest as bS, requestEasSyncFromAddressChange as bT, requestEasSyncFromEventBus as bU, requestEasSyncFromModelsInit as bV, mergeEasSyncRequestIntents as bW, addSchemaToDb as bX, createModelsFromJson as bY, loadModelsFromDbForSchema as bZ, getLatestSchemaVersion as b_, propertyMachine as ba, SEED_PROTOCOL_SCHEMA_NAME as bb, ImageSize as bc, setSchemaUidForModel as bd, getCanonicalItemPropertiesFromEas as be, getEasSchemaUidBySchemaName as bf, getSeedsBySchemaName as bg, withExcludeRevokedFilter as bh, classifyMediaRef as bi, resolveMediaRef as bj, normalizeFeedItemFields as bk, getFeedItemStringField as bl, SeedModels as bm, DEFAULT_ARWEAVE_HOST as bn, DEFAULT_ARWEAVE_GATEWAYS as bo, DEFAULT_ARWEAVE_GRAPHQL_URL as bp, getDefaultArweaveReadGatewayHostsOrdered as bq, mergePrimaryHostWithDefaults as br, isKnownArweaveGatewayHostname as bs, getAddressesForItemsFilter as bt, normalizeUploadApiBaseUrl as bu, getUploadApiArweaveDataUrl as bv, getUploadPipelineTransactionStatus as bw, getUploadApiArweaveStatusUrl as bx, getArweaveUploadStatus as by, isArweaveL1AnchoringComplete as bz, TPropertyDataType as c, createModelFromJson as c0, ConflictError as c1, unloadEntity as c2, clearDestroySubscriptions as c3, setupEntityLiveQuery as c4, ModelSchema as c5, BaseFileManager$1 as c6, db as c7, eas as c8, getPropertyData$1 as c9, Item$1 as ca, schema as cb, SEEDPROTOCOL_Seed_Protocol_v1 as cc, Model$1 as cd, TStorageType as d, THtmlEmbeddedDataUriPolicy as e, TProperty as f, TPropertyConstructor as g, TPropertyDefs as h, PropertyMetadataKey as i, PropertyConstructor as j, Text as k, DEFAULT_TEXT_MAX_LENGTH as l, TValidationRules as m, normalizeDataType as n, getOwnedAddressesFromDb as o, BaseDb as p, getGetAdditionalSyncAddresses as q, resolveSeedIdsFromRefString as r, seeds as s, normalizeRelationPropertyValue as t, Item as u, BaseFileManager as v, getContentHash as w, htmlEmbeddedImageCoPublish as x, BaseArweaveClient as y, getEasSchemaUidForModel as z };
|
|
20018
|
+
//# sourceMappingURL=index-DUMXLKJr.js.map
|