@seedprotocol/sdk 0.7.9 → 0.7.10-next.1344.g3828e8a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +1 -1
  2. package/dist/{BaseFileManager-BAlySv8w.js → BaseFileManager-DLou1TZS.js} +5 -1
  3. package/dist/BaseFileManager-DLou1TZS.js.map +1 -0
  4. package/dist/{Item-Bf4kWKpH.js → Item-CXLcIHsi.js} +559 -346
  5. package/dist/Item-CXLcIHsi.js.map +1 -0
  6. package/dist/{ModelProperty-BlaEgb_U.js → ModelProperty-B3mfR6u4.js} +35 -35
  7. package/dist/{ModelProperty-BlaEgb_U.js.map → ModelProperty-B3mfR6u4.js.map} +1 -1
  8. package/dist/{Schema-J_1f6p0c.js → Schema-BeUyEmte.js} +18 -18
  9. package/dist/{Schema-J_1f6p0c.js.map → Schema-BeUyEmte.js.map} +1 -1
  10. package/dist/{SchemaValidationService-CnmKyzR-.js → SchemaValidationService-C1xqJFxI.js} +5 -5
  11. package/dist/{SchemaValidationService-CnmKyzR-.js.map → SchemaValidationService-C1xqJFxI.js.map} +1 -1
  12. package/dist/{errors-C1qUEZ7A.js → browserSupport-C64rX-2I.js} +38 -2
  13. package/dist/browserSupport-C64rX-2I.js.map +1 -0
  14. package/dist/{configurePlatform-CiOJ1R3q.js → configurePlatform-WkmvqeTO.js} +2 -2
  15. package/dist/{configurePlatform-CiOJ1R3q.js.map → configurePlatform-WkmvqeTO.js.map} +1 -1
  16. package/dist/{detachRowsBeforeDelete-sEaUwlOU.js → detachRowsBeforeDelete-BZr_0iZU.js} +2 -2
  17. package/dist/{detachRowsBeforeDelete-sEaUwlOU.js.map → detachRowsBeforeDelete-BZr_0iZU.js.map} +1 -1
  18. package/dist/dist/{BaseFileManager-BAlySv8w.d.ts → BaseFileManager-DLou1TZS.d.ts} +3 -1
  19. package/dist/dist/BaseFileManager-DLou1TZS.d.ts.map +1 -0
  20. package/dist/dist/{configurePlatform-CiOJ1R3q.d.ts → configurePlatform-WkmvqeTO.d.ts} +1 -1
  21. package/dist/dist/configurePlatform-WkmvqeTO.d.ts.map +1 -0
  22. package/dist/dist/{index-D0V-mjCV.d.ts → index-BjWk0x4-.d.ts} +1 -1
  23. package/dist/dist/{index-D0V-mjCV.d.ts.map → index-BjWk0x4-.d.ts.map} +1 -1
  24. package/dist/dist/{index.node-CYPemH-t.d.ts → index.node-BfiBriEq.d.ts} +7 -1
  25. package/dist/dist/{index.node-CYPemH-t.d.ts.map → index.node-BfiBriEq.d.ts.map} +1 -1
  26. package/dist/dist/platform.node.d.ts +2 -2
  27. package/dist/{eas-wB_fQ8Tc.js → eas-DpHg66jR.js} +5 -5
  28. package/dist/{eas-wB_fQ8Tc.js.map → eas-DpHg66jR.js.map} +1 -1
  29. package/dist/{errors-DLSoqSHG.js → errors-DpC9W4i3.js} +84 -45
  30. package/dist/{errors-DLSoqSHG.js.map → errors-DpC9W4i3.js.map} +1 -1
  31. package/dist/{getPublishPayload-BnIwpwz1.js → getPublishPayload-yidQCgY_.js} +8 -8
  32. package/dist/{getPublishPayload-BnIwpwz1.js.map → getPublishPayload-yidQCgY_.js.map} +1 -1
  33. package/dist/{getPublishPendingDiff-D6_-A5ns.js → getPublishPendingDiff-D__9bh6d.js} +7 -7
  34. package/dist/{getPublishPendingDiff-D6_-A5ns.js.map → getPublishPendingDiff-D__9bh6d.js.map} +1 -1
  35. package/dist/{getPublishUploads-sS6JfPgz.js → getPublishUploads-BdZmYCo2.js} +7 -7
  36. package/dist/{getPublishUploads-sS6JfPgz.js.map → getPublishUploads-BdZmYCo2.js.map} +1 -1
  37. package/dist/{index-CYGWPoOx.js → index-BMHqJ4kN.js} +7 -7
  38. package/dist/index-BMHqJ4kN.js.map +1 -0
  39. package/dist/{index-D0V-mjCV.js → index-BjWk0x4-.js} +2 -2
  40. package/dist/index-BjWk0x4-.js.map +1 -0
  41. package/dist/{index-DmTtj1nk.js → index-CVYB2g7a.js} +402 -20
  42. package/dist/index-CVYB2g7a.js.map +1 -0
  43. package/dist/{index-BVBmz_cc.js → index-uDLe9y9H.js} +7 -7
  44. package/dist/index-uDLe9y9H.js.map +1 -0
  45. package/dist/{index.browser-CUmBVYen.js → index.browser-OACFlpMH.js} +46 -10
  46. package/dist/index.browser-OACFlpMH.js.map +1 -0
  47. package/dist/{index.node-CYPemH-t.js → index.node-BfiBriEq.js} +31 -4
  48. package/dist/index.node-BfiBriEq.js.map +1 -0
  49. package/dist/main.js +17 -16
  50. package/dist/main.js.map +1 -1
  51. package/dist/{modelPropertyRecordSchemas-C7UgA5TH.js → modelPropertyRecordSchemas-BGvtTyaG.js} +5 -5
  52. package/dist/{modelPropertyRecordSchemas-C7UgA5TH.js.map → modelPropertyRecordSchemas-BGvtTyaG.js.map} +1 -1
  53. package/dist/node.js +8 -8
  54. package/dist/platform.browser.js +6 -6
  55. package/dist/platform.node.js +4 -4
  56. package/dist/{property-BxUYznH0.js → property-QjljUeb9.js} +8 -8
  57. package/dist/{property-BxUYznH0.js.map → property-QjljUeb9.js.map} +1 -1
  58. package/dist/{publishGraph-EcB40Uii.js → publishGraph-CP8IROkb.js} +5 -5
  59. package/dist/{publishGraph-EcB40Uii.js.map → publishGraph-CP8IROkb.js.map} +1 -1
  60. package/dist/{readHtmlBodyForStorageSeed-D6KPtWoR.js → readHtmlBodyForStorageSeed-D3OPk2iU.js} +10 -10
  61. package/dist/{readHtmlBodyForStorageSeed-D6KPtWoR.js.map → readHtmlBodyForStorageSeed-D3OPk2iU.js.map} +1 -1
  62. package/dist/src/Item/Item.d.ts +26 -5
  63. package/dist/src/Item/Item.d.ts.map +1 -1
  64. package/dist/src/ItemProperty/ItemProperty.d.ts +20 -5
  65. package/dist/src/ItemProperty/ItemProperty.d.ts.map +1 -1
  66. package/dist/src/ItemProperty/loadProperty.d.ts.map +1 -1
  67. package/dist/src/ItemProperty/propertyWrite.d.ts.map +1 -1
  68. package/dist/src/ItemProperty/service/actors/hydrateFromDb.d.ts.map +1 -1
  69. package/dist/src/archive/exportArchive.d.ts +57 -0
  70. package/dist/src/archive/exportArchive.d.ts.map +1 -0
  71. package/dist/src/browser/db/Db.d.ts +5 -0
  72. package/dist/src/browser/db/Db.d.ts.map +1 -1
  73. package/dist/src/browser/helpers/FileManager.d.ts.map +1 -1
  74. package/dist/src/browser/helpers/tolerantWebAccess.d.ts +12 -1
  75. package/dist/src/browser/helpers/tolerantWebAccess.d.ts.map +1 -1
  76. package/dist/src/client/ClientManager.d.ts +14 -4
  77. package/dist/src/client/ClientManager.d.ts.map +1 -1
  78. package/dist/src/db/Db/BaseDb.d.ts +2 -0
  79. package/dist/src/db/Db/BaseDb.d.ts.map +1 -1
  80. package/dist/src/helpers/FileManager/errors.d.ts +11 -0
  81. package/dist/src/helpers/FileManager/errors.d.ts.map +1 -1
  82. package/dist/src/helpers/browserSupport.d.ts +23 -0
  83. package/dist/src/helpers/browserSupport.d.ts.map +1 -0
  84. package/dist/src/helpers/cachedPropertyRefresh.d.ts +6 -6
  85. package/dist/src/helpers/cachedPropertyRefresh.d.ts.map +1 -1
  86. package/dist/src/helpers/entity/entityCache.d.ts +34 -3
  87. package/dist/src/helpers/entity/entityCache.d.ts.map +1 -1
  88. package/dist/src/helpers/entity/entityLifecycle.d.ts +21 -3
  89. package/dist/src/helpers/entity/entityLifecycle.d.ts.map +1 -1
  90. package/dist/src/helpers/propertyDefinition.d.ts +2 -0
  91. package/dist/src/helpers/propertyDefinition.d.ts.map +1 -1
  92. package/dist/src/helpers/tabCoordinator.d.ts +9 -2
  93. package/dist/src/helpers/tabCoordinator.d.ts.map +1 -1
  94. package/dist/src/index.d.ts +4 -1
  95. package/dist/src/index.d.ts.map +1 -1
  96. package/dist/src/interfaces/IDb.d.ts +6 -0
  97. package/dist/src/interfaces/IDb.d.ts.map +1 -1
  98. package/dist/src/node/db/Db.d.ts +6 -0
  99. package/dist/src/node/db/Db.d.ts.map +1 -1
  100. package/dist/src/outbox/conflicts.d.ts.map +1 -1
  101. package/dist/src/outbox/outbox.d.ts +6 -0
  102. package/dist/src/outbox/outbox.d.ts.map +1 -1
  103. package/dist/src/types/index.d.ts +16 -0
  104. package/dist/src/types/index.d.ts.map +1 -1
  105. package/dist/{syncDbWithEas-CA7PvBgu.js → syncDbWithEas-CDjSNrVR.js} +14 -14
  106. package/dist/{syncDbWithEas-CA7PvBgu.js.map → syncDbWithEas-CDjSNrVR.js.map} +1 -1
  107. package/dist/{tabEvents-CaVmngqr.js → tabEvents-BHPY5I08.js} +38 -12
  108. package/dist/tabEvents-BHPY5I08.js.map +1 -0
  109. package/dist/{tolerantWebAccess-BJqViq08.js → tolerantWebAccess-hDq9ZGXH.js} +53 -13
  110. package/dist/tolerantWebAccess-hDq9ZGXH.js.map +1 -0
  111. package/dist/{updateSeedRevokedAt-BL9Bg-G7.js → updateSeedRevokedAt-BMwBnlnC.js} +3 -3
  112. package/dist/{updateSeedRevokedAt-BL9Bg-G7.js.map → updateSeedRevokedAt-BMwBnlnC.js.map} +1 -1
  113. package/package.json +10 -12
  114. package/dist/BaseFileManager-BAlySv8w.js.map +0 -1
  115. package/dist/Item-Bf4kWKpH.js.map +0 -1
  116. package/dist/dist/BaseFileManager-BAlySv8w.d.ts.map +0 -1
  117. package/dist/dist/configurePlatform-CiOJ1R3q.d.ts.map +0 -1
  118. package/dist/errors-C1qUEZ7A.js.map +0 -1
  119. package/dist/index-BVBmz_cc.js.map +0 -1
  120. package/dist/index-CYGWPoOx.js.map +0 -1
  121. package/dist/index-D0V-mjCV.js.map +0 -1
  122. package/dist/index-DmTtj1nk.js.map +0 -1
  123. package/dist/index.browser-CUmBVYen.js.map +0 -1
  124. package/dist/index.node-CYPemH-t.js.map +0 -1
  125. package/dist/tabEvents-CaVmngqr.js.map +0 -1
  126. package/dist/tolerantWebAccess-BJqViq08.js.map +0 -1
@@ -1,10 +1,10 @@
1
- import { a_ as PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP, n as normalizeDataType, v as INTERNAL_DATA_TYPES, af as MachineIds, O as resolveItemModelFileId, l as resolveModelRecordByNameOrType, A as AmbiguousModelError, m as generateId, a$ as TAB_ID, aM as onTabMessage, ax as whenLeaderTab, ap as isLeaderTab, aL as postTabMessage, j as findSeedRow, b0 as getModelSchemaName, K as selectInBatches, aX as getOwnedAddressesFromDb, Z as ZERO_BYTES32, ar as normalizeAddressList, J as normalizeHexAddress, am as getAddressesForItemsFilter, a0 as INTERNAL_PROPERTY_NAMES, a7 as convertTxIdToImage, i as isDataType, R as getExtensionForMimeType, b1 as normalizeMimeType, aA as sniffMimeType, Y as getItemStorageSubdir, ad as ImageSize, b2 as findFileInDir, b3 as getStorageSubdirForDataType, g as normalizePropertyRecordSchema, h as eventEmitter, b4 as timingMarks, a4 as getPropertyDefinition, aT as tryWithTabLock, b5 as withTabLock, M as ModelPropertyDataTypes, aC as createSessionObjectUrl, U as INTERNAL_STORAGE_MODEL_FILE_IDS, b6 as revokeSessionObjectUrl, aw as whenDbReady, b7 as timed, av as watchEntityRows, a5 as propertyDefinitionFromRow, b8 as isSessionObjectUrl, x as normalizePublisher, _ as getItemStorageLocalFileName, b9 as timingNow, ba as timingSince, bb as timingLogger, bc as timedDb } from './tabEvents-CaVmngqr.js';
1
+ import { b0 as PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP, n as normalizeDataType, v as INTERNAL_DATA_TYPES, af as MachineIds, O as resolveItemModelFileId, l as resolveModelRecordByNameOrType, A as AmbiguousModelError, m as generateId, b1 as TAB_ID, aN as onTabMessage, ax as whenLeaderTab, ap as isLeaderTab, aM as postTabMessage, j as findSeedRow, b2 as getModelSchemaName, K as selectInBatches, aY as getOwnedAddressesFromDb, Z as ZERO_BYTES32, ar as normalizeAddressList, J as normalizeHexAddress, am as getAddressesForItemsFilter, a0 as INTERNAL_PROPERTY_NAMES, a7 as convertTxIdToImage, i as isDataType, R as getExtensionForMimeType, b3 as normalizeMimeType, aA as sniffMimeType, Y as getItemStorageSubdir, ad as ImageSize, b4 as findFileInDir, b5 as getStorageSubdirForDataType, g as normalizePropertyRecordSchema, h as eventEmitter, b6 as timingMarks, a4 as getPropertyDefinition, aU as tryWithTabLock, b7 as withTabLock, M as ModelPropertyDataTypes, aC as createSessionObjectUrl, U as INTERNAL_STORAGE_MODEL_FILE_IDS, b8 as revokeSessionObjectUrl, b9 as getPropertyDefinitionsByFileId, aw as whenDbReady, ba as timed, av as watchEntityRows, a5 as propertyDefinitionFromRow, bb as isSessionObjectUrl, a6 as addCachedPropertyRefresher, x as normalizePublisher, _ as getItemStorageLocalFileName, bc as timingNow, bd as timingSince, be as timingLogger, bf as timedDb } from './tabEvents-BHPY5I08.js';
2
2
  import { fromCallback, setup, assign, and as and$1, stateIn, createActor, waitFor, isMachineSnapshot } from 'xstate';
3
3
  import debug from 'debug';
4
4
  import pluralize from 'pluralize';
5
5
  import { easName, isValidEasAttestationUid, isPlaceholderUid, getEasSchemaUidForSchemaDefinition, getSchemaUidForModelFromCache, setSchemaUidForModel, cachedSchemaLookup, getEasModelSchemasForNames, getEasSchemaUidForExactDefinition } from '@seedprotocol/eas';
6
6
  import { sql, inArray, or, eq, and, isNull, getTableColumns, asc, lt, isNotNull, max, count, gt, desc, ne } from 'drizzle-orm';
7
- import { m as metadata, l as properties, B as BaseDb, d as models, p as pendingWrites, x as isSqliteBusyError, v as versions, s as seeds, w as BaseFileManager, b as modelUids, r as publishProcesses, e as arweaveL1FinalizeJobs, h as htmlEmbeddedImageCoPublish } from './BaseFileManager-BAlySv8w.js';
7
+ import { m as metadata, l as properties, B as BaseDb, d as models, p as pendingWrites, x as isSqliteBusyError, v as versions, s as seeds, w as BaseFileManager, b as modelUids, r as publishProcesses, e as arweaveL1FinalizeJobs, h as htmlEmbeddedImageCoPublish } from './BaseFileManager-DLou1TZS.js';
8
8
  import { BehaviorSubject } from 'rxjs';
9
9
  import { orderBy } from 'lodash-es';
10
10
  import { normalizeRelationPropertyValue, resolveSeedIdsFromRefString, BaseArweaveClient } from '@seedprotocol/arweave';
@@ -496,7 +496,7 @@ const runPublish = fromCallback(({ sendBack, input: { context, item: itemFromEve
496
496
  // item.publish() sends its own instance; look it up only if startPublish came without one.
497
497
  const loaded = itemFromEvent
498
498
  ? undefined
499
- : (await (await Promise.resolve().then(function () { return Item$1; })).Item.find({ seedLocalId }));
499
+ : (await (await Promise.resolve().then(function () { return Item$1; })).Item.find({ seedLocalId, hold: true }));
500
500
  const item = itemFromEvent ?? loaded;
501
501
  if (!item) {
502
502
  sendBack({ type: 'publishError', error: new Error(`Item not found: ${seedLocalId}`) });
@@ -1078,6 +1078,9 @@ function outboxOpResult(op) {
1078
1078
  // --- Draining ---------------------------------------------------------------------------------
1079
1079
  let started = false;
1080
1080
  let paused = false;
1081
+ /** Set by stopOutbox (client.stop) until the next startOutbox. */
1082
+ let stopped = false;
1083
+ let stopTabMessages;
1081
1084
  let draining;
1082
1085
  let drainAgain = false;
1083
1086
  let retryTimer;
@@ -1091,7 +1094,8 @@ function startOutbox() {
1091
1094
  if (started)
1092
1095
  return;
1093
1096
  started = true;
1094
- onTabMessage((message) => {
1097
+ stopped = false;
1098
+ stopTabMessages = onTabMessage((message) => {
1095
1099
  if (message.type === 'outbox-nudge' && isLeaderTab())
1096
1100
  scheduleDrain();
1097
1101
  if (message.type === 'outbox-settled')
@@ -1101,7 +1105,7 @@ function startOutbox() {
1101
1105
  }
1102
1106
  /** Drains soon in this tab (if it leads); calls made while a drain runs make it run once more. */
1103
1107
  function scheduleDrain() {
1104
- if (!isLeaderTab())
1108
+ if (stopped || !isLeaderTab())
1105
1109
  return;
1106
1110
  if (draining) {
1107
1111
  drainAgain = true;
@@ -1112,7 +1116,7 @@ function scheduleDrain() {
1112
1116
  do {
1113
1117
  drainAgain = false;
1114
1118
  await drainOutbox();
1115
- } while (drainAgain && !paused);
1119
+ } while (drainAgain && !paused && !stopped);
1116
1120
  }
1117
1121
  catch (error) {
1118
1122
  logger$8('drain failed', error);
@@ -1455,6 +1459,24 @@ async function getOutboxOps(opIds) {
1455
1459
  return [];
1456
1460
  return BaseDb.getAppDb().select().from(pendingWrites).where(inArray(pendingWrites.opId, opIds));
1457
1461
  }
1462
+ /**
1463
+ * Stops draining in this tab (client.stop): no new drain starts, retries are dropped, and this
1464
+ * resolves once a drain that was running has finished. Ops stay pending in the database; the next
1465
+ * startOutbox (any write after init) resumes them, as after a reload.
1466
+ */
1467
+ async function stopOutbox() {
1468
+ started = false;
1469
+ stopped = true;
1470
+ stopTabMessages?.();
1471
+ stopTabMessages = undefined;
1472
+ if (retryTimer !== undefined) {
1473
+ clearTimeout(retryTimer);
1474
+ retryTimer = undefined;
1475
+ }
1476
+ notBefore.clear();
1477
+ while (draining)
1478
+ await draining;
1479
+ }
1458
1480
 
1459
1481
  /** A storage op's row fields, from either op shape. */
1460
1482
  function storageValueRowOf(value) {
@@ -2213,8 +2235,8 @@ const getItemsData = async ({ modelName, modelFileId, schemaName, deleted, inclu
2213
2235
  conditions.push(eq(seeds.type, easName(modelName)));
2214
2236
  }
2215
2237
  if (!modelFileId && schemaName && modelName) {
2216
- const _mod_0 = await import('./tabEvents-CaVmngqr.js');
2217
- const _ns_0 = _mod_0.be;
2238
+ const _mod_0 = await import('./tabEvents-BHPY5I08.js');
2239
+ const _ns_0 = _mod_0.bh;
2218
2240
  const { resolveModelRecord } = _ns_0;
2219
2241
  modelFileId = (await resolveModelRecord(modelName, { schemaName }))?.schemaFileId ?? undefined;
2220
2242
  if (!modelFileId)
@@ -2469,7 +2491,7 @@ const resolveRelatedValue = fromCallback(({ sendBack, input: { context } }) => {
2469
2491
  const { isRelation, propertyValue, propertyName, propertyRecordSchema, populatedFromDb, } = context;
2470
2492
  const _resolveRelatedValue = async () => {
2471
2493
  // Use dynamic import to break circular dependency
2472
- const schemaMod = await import('./index-BVBmz_cc.js');
2494
+ const schemaMod = await import('./index-uDLe9y9H.js');
2473
2495
  const { ModelPropertyDataTypes } = schemaMod;
2474
2496
  if (!propertyValue || !isRelation || populatedFromDb) {
2475
2497
  return;
@@ -2983,7 +3005,7 @@ async function resolveStorageRef(kind, row) {
2983
3005
  }
2984
3006
  if (kind === 'html') {
2985
3007
  if (!out.refResolvedValue && out.propertyValue) {
2986
- const { resolveHtmlStorageSeedLocalId } = await import('./readHtmlBodyForStorageSeed-D6KPtWoR.js');
3008
+ const { resolveHtmlStorageSeedLocalId } = await import('./readHtmlBodyForStorageSeed-D3OPk2iU.js');
2987
3009
  const localId = await resolveHtmlStorageSeedLocalId(out.propertyValue);
2988
3010
  if (localId)
2989
3011
  out.refResolvedValue = `${localId}.html`;
@@ -3032,7 +3054,7 @@ async function resolveStorageDisplay(kind, row, options = {}) {
3032
3054
  }
3033
3055
  }
3034
3056
  if (!renderValue && options.fetch && ref.propertyValue) {
3035
- const { readHtmlBodyForStorageSeedPropertyValue } = await import('./readHtmlBodyForStorageSeed-D6KPtWoR.js');
3057
+ const { readHtmlBodyForStorageSeedPropertyValue } = await import('./readHtmlBodyForStorageSeed-D3OPk2iU.js');
3036
3058
  renderValue = await readHtmlBodyForStorageSeedPropertyValue(ref.propertyValue);
3037
3059
  }
3038
3060
  return { ref, filePath, renderValue };
@@ -3044,15 +3066,15 @@ async function resolveStorageDisplay(kind, row, options = {}) {
3044
3066
  : BaseFileManager.pathExists(BaseFileManager.getFilesPath(dir, name)).then((exists) => exists ? BaseFileManager.getFilesPath(dir, name) : undefined);
3045
3067
  // ensureImageLocal also makes the smallest size variant when the original is already there
3046
3068
  if (kind === 'image' && options.fetch) {
3047
- const _mod_1 = await import('./tabEvents-CaVmngqr.js');
3048
- const _ns_1 = _mod_1.bl;
3069
+ const _mod_1 = await import('./tabEvents-BHPY5I08.js');
3070
+ const _ns_1 = _mod_1.bo;
3049
3071
  const { ensureImageLocal } = _ns_1;
3050
3072
  await ensureImageLocal({ transactionId: name, fileName: name, widths: [ImageSize.EXTRA_SMALL] });
3051
3073
  }
3052
3074
  let filePath = await find();
3053
3075
  if (!filePath && kind === 'file' && options.fetch) {
3054
- const _mod_2 = await import('./tabEvents-CaVmngqr.js');
3055
- const _ns_2 = _mod_2.bj;
3076
+ const _mod_2 = await import('./tabEvents-BHPY5I08.js');
3077
+ const _ns_2 = _mod_2.bm;
3056
3078
  const { downloadTransactionIdWithDedupe } = _ns_2;
3057
3079
  await downloadTransactionIdWithDedupe(name);
3058
3080
  filePath = await find();
@@ -3086,7 +3108,7 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
3086
3108
  }
3087
3109
  const _hydrateFromDb = async () => {
3088
3110
  const normalizedDataType = normalizeDataType(propertyRecordSchema?.dataType);
3089
- const row = await currentPropertyRow({ seedLocalId, seedUid }, {
3111
+ const read = () => currentPropertyRow({ seedLocalId, seedUid }, {
3090
3112
  propertyId: context.propertyId,
3091
3113
  propertyName,
3092
3114
  modelName,
@@ -3094,10 +3116,15 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
3094
3116
  dataType: normalizedDataType,
3095
3117
  refValueType: normalizeDataType(propertyRecordSchema?.refValueType),
3096
3118
  });
3119
+ let row = await read();
3097
3120
  if (!row)
3098
3121
  return;
3099
3122
  const { getPropertyConflict } = await Promise.resolve().then(function () { return conflicts; });
3100
3123
  const conflict = await getPropertyConflict(row.seedLocalId ?? seedLocalId, propertyName);
3124
+ // Sync records a conflict and moves its draft to newest in one transaction: a row read before
3125
+ // the conflict may be the synced one
3126
+ if (conflict)
3127
+ row = (await read()) ?? row;
3101
3128
  // Only with a definition: without one, a row's refSeedType alone doesn't decide the display here
3102
3129
  const kind = propertyRecordSchema ? storedValueKind(propertyRecordSchema) : undefined;
3103
3130
  let { refResolvedValue, localStorageDir } = row;
@@ -3480,12 +3507,12 @@ async function keepLocalDraftsOverSyncedRows(synced) {
3480
3507
  const now = Date.now();
3481
3508
  const remoteAt = remote.attestationCreatedAt ?? 0;
3482
3509
  const createdAt = Math.max(draft.createdAt ?? 0, remoteAt + 1);
3483
- // Written after the conflict: the change feed has no trigger on pending_writes, so this write
3510
+ // Written with the conflict: the change feed has no trigger on pending_writes, so this write
3484
3511
  // is what makes a loaded property re-read and pick the conflict up (ADR 0020).
3485
- const keepDraftNewest = async (recordedConflict) => {
3512
+ const keepDraftNewest = async (on, recordedConflict) => {
3486
3513
  if (createdAt === draft.createdAt && !recordedConflict)
3487
3514
  return;
3488
- await db.update(metadata).set({ createdAt }).where(eq(metadata.localId, draft.localId));
3515
+ await on.update(metadata).set({ createdAt }).where(eq(metadata.localId, draft.localId));
3489
3516
  };
3490
3517
  // The attested value the draft replaced: the newest attested row that sync didn't just write
3491
3518
  const base = candidates
@@ -3495,7 +3522,7 @@ async function keepLocalDraftsOverSyncedRows(synced) {
3495
3522
  const remoteValue = remote.propertyValue ?? null;
3496
3523
  const localValue = draft.propertyValue ?? null;
3497
3524
  if (remoteValue === localValue || remoteValue === baseValue) {
3498
- await keepDraftNewest(false);
3525
+ await keepDraftNewest(db, false);
3499
3526
  continue;
3500
3527
  }
3501
3528
  const opId = generateId();
@@ -3508,19 +3535,23 @@ async function keepLocalDraftsOverSyncedRows(synced) {
3508
3535
  remoteUid: remote.uid,
3509
3536
  opId,
3510
3537
  };
3511
- await db.insert(pendingWrites).values({
3512
- opId,
3513
- seedLocalId: draft.seedLocalId,
3514
- propertyName: draft.propertyName,
3515
- kind: 'set',
3516
- value: JSON.stringify({ newValue: localValue }),
3517
- baseRowId: draft.localId,
3518
- createdAt: now,
3519
- status: 'applied',
3520
- appliedAt: now,
3521
- conflict: JSON.stringify(conflict),
3538
+ // One transaction: a reader that sees the conflict also sees the draft as the newest row, or it
3539
+ // could show the synced value beside the conflict
3540
+ await BaseDb.transaction(async (tx) => {
3541
+ await tx.insert(pendingWrites).values({
3542
+ opId,
3543
+ seedLocalId: draft.seedLocalId,
3544
+ propertyName: draft.propertyName,
3545
+ kind: 'set',
3546
+ value: JSON.stringify({ newValue: localValue }),
3547
+ baseRowId: draft.localId,
3548
+ createdAt: now,
3549
+ status: 'applied',
3550
+ appliedAt: now,
3551
+ conflict: JSON.stringify(conflict),
3552
+ });
3553
+ await keepDraftNewest(tx, true);
3522
3554
  });
3523
- await keepDraftNewest(true);
3524
3555
  eventEmitter.emit('itemProperty.conflict', conflict);
3525
3556
  }
3526
3557
  }
@@ -3535,194 +3566,6 @@ var conflicts = /*#__PURE__*/Object.freeze({
3535
3566
  recordPropertyEdit: recordPropertyEdit
3536
3567
  });
3537
3568
 
3538
- /**
3539
- * The cache behind an entity class (ADR 0014). `peek` takes no hold; `hold`, `add({ hold: true })`
3540
- * and `holdInstance` take one each, and `release` gives one back. Entries are found by key or by
3541
- * actor, so a raw instance and its proxy find the same entry.
3542
- */
3543
- class EntityCache {
3544
- constructor() {
3545
- this.byKey = new Map();
3546
- this.byActor = new WeakMap();
3547
- }
3548
- /** Cache `instance` under `keys` (empty and duplicate keys are skipped). Returns its entry. */
3549
- add(instance, keys, options) {
3550
- const existing = this.entryOf(instance);
3551
- if (existing) {
3552
- if (options.hold)
3553
- existing.refCount += 1;
3554
- for (const key of keys)
3555
- if (key)
3556
- this.addKey(instance, key);
3557
- return existing;
3558
- }
3559
- const entry = {
3560
- instance,
3561
- refCount: options.hold ? 1 : 0,
3562
- keys: new Set(),
3563
- };
3564
- this.byActor.set(instance.getService(), entry);
3565
- for (const key of keys)
3566
- if (key)
3567
- this.addKey(instance, key);
3568
- return entry;
3569
- }
3570
- /** The cached instance under `key`, without taking a hold. */
3571
- peek(key) {
3572
- return key ? this.byKey.get(key)?.instance : undefined;
3573
- }
3574
- /** The cached instance under `key`, taking a hold the caller releases with `release`. */
3575
- hold(key) {
3576
- const entry = key ? this.byKey.get(key) : undefined;
3577
- if (!entry)
3578
- return undefined;
3579
- entry.refCount += 1;
3580
- return entry.instance;
3581
- }
3582
- /** Take a hold on a cached instance. False when it isn't cached (unloaded, evicted). */
3583
- holdInstance(instance) {
3584
- const entry = this.entryOf(instance);
3585
- if (!entry)
3586
- return false;
3587
- entry.refCount += 1;
3588
- return true;
3589
- }
3590
- /**
3591
- * Give back one hold. True when the instance should be torn down: its last hold went, or it
3592
- * isn't cached at all (evicted while the caller held it).
3593
- */
3594
- release(instance) {
3595
- const entry = this.entryOf(instance);
3596
- if (!entry)
3597
- return true;
3598
- entry.refCount -= 1;
3599
- return entry.refCount <= 0;
3600
- }
3601
- entryOf(instance) {
3602
- return this.byActor.get(instance.getService());
3603
- }
3604
- has(instance) {
3605
- return this.entryOf(instance) !== undefined;
3606
- }
3607
- /**
3608
- * Store the instance under one more key. A key held by another instance moves to this one:
3609
- * the newest instance for a name or uid wins.
3610
- */
3611
- addKey(instance, key) {
3612
- const entry = this.entryOf(instance);
3613
- if (!entry || !key)
3614
- return;
3615
- const previous = this.byKey.get(key);
3616
- if (previous === entry)
3617
- return;
3618
- previous?.keys.delete(key);
3619
- this.byKey.set(key, entry);
3620
- entry.keys.add(key);
3621
- }
3622
- removeKey(instance, key) {
3623
- const entry = this.entryOf(instance);
3624
- if (!entry || !entry.keys.has(key))
3625
- return;
3626
- entry.keys.delete(key);
3627
- if (this.byKey.get(key) === entry)
3628
- this.byKey.delete(key);
3629
- }
3630
- /** Replace every key of the instance (a rename, an id that changed). */
3631
- setKeys(instance, keys) {
3632
- const entry = this.entryOf(instance);
3633
- if (!entry)
3634
- return;
3635
- const next = new Set(keys.filter((key) => !!key));
3636
- for (const key of [...entry.keys])
3637
- if (!next.has(key))
3638
- this.removeKey(instance, key);
3639
- for (const key of next)
3640
- this.addKey(instance, key);
3641
- }
3642
- keysOf(instance) {
3643
- return [...(this.entryOf(instance)?.keys ?? [])];
3644
- }
3645
- /** Drop the instance under all its keys. Teardown (entityLifecycle) also releases its children. */
3646
- remove(instance) {
3647
- const entry = this.entryOf(instance);
3648
- if (!entry)
3649
- return undefined;
3650
- for (const key of entry.keys) {
3651
- if (this.byKey.get(key) === entry)
3652
- this.byKey.delete(key);
3653
- }
3654
- entry.keys.clear();
3655
- this.byActor.delete(instance.getService());
3656
- return entry;
3657
- }
3658
- /** Every cached instance once, optionally filtered. */
3659
- instances(filter) {
3660
- const seen = new Set();
3661
- const result = [];
3662
- for (const entry of this.byKey.values()) {
3663
- if (seen.has(entry))
3664
- continue;
3665
- seen.add(entry);
3666
- if (!filter || filter(entry.instance))
3667
- result.push(entry.instance);
3668
- }
3669
- return result;
3670
- }
3671
- get size() {
3672
- return this.instances().length;
3673
- }
3674
- }
3675
- /**
3676
- * Evictions and destroys, by scope (`schema:<name>`, `model:<id>`). Work that reads a row and then
3677
- * creates an instance from it (a lookup by id) can't be cancelled by stopping actors: capture
3678
- * `evictionLog.now()` before the read, and skip creating when `evictedSince(scopes, then)`. A scope
3679
- * also counts as evicted while its destroy runs, since its rows still exist until the delete commits.
3680
- */
3681
- const evictionLog = {
3682
- generation: 0,
3683
- last: new Map(),
3684
- running: new Map(),
3685
- now() {
3686
- return this.generation;
3687
- },
3688
- /** Record an eviction of these scopes. Call the returned function once a destroy's rows are gone. */
3689
- evict(scopes) {
3690
- this.generation += 1;
3691
- for (const scope of scopes) {
3692
- this.last.set(scope, this.generation);
3693
- this.running.set(scope, (this.running.get(scope) ?? 0) + 1);
3694
- }
3695
- let finished = false;
3696
- return () => {
3697
- if (finished)
3698
- return;
3699
- finished = true;
3700
- // Work that read a row during the destroy and checks after it must still see the eviction
3701
- this.generation += 1;
3702
- for (const scope of scopes) {
3703
- this.last.set(scope, this.generation);
3704
- const remaining = (this.running.get(scope) ?? 1) - 1;
3705
- if (remaining > 0)
3706
- this.running.set(scope, remaining);
3707
- else
3708
- this.running.delete(scope);
3709
- }
3710
- };
3711
- },
3712
- /** True when a scope is being destroyed, or was evicted after `since`. */
3713
- evictedSince(scopes, since) {
3714
- for (const scope of scopes) {
3715
- if (!scope)
3716
- continue;
3717
- if (this.running.has(scope))
3718
- return true;
3719
- if (this.generation !== since && (this.last.get(scope) ?? 0) > since)
3720
- return true;
3721
- }
3722
- return false;
3723
- },
3724
- };
3725
-
3726
3569
  /**
3727
3570
  * Default timeout for create/find/all with waitForReady. Loads that touch OPFS and the DB can take
3728
3571
  * several seconds on slow devices and CI runners; a load that is really stuck still errors.
@@ -3813,6 +3656,17 @@ async function waitForEntityReady(instance, options = {}) {
3813
3656
  throw cause instanceof Error ? cause : new EntityLoadError('Entity failed to load', { cause });
3814
3657
  }
3815
3658
  }
3659
+ /**
3660
+ * A write or publish on an instance that was unloaded (no hold kept it past the grace period,
3661
+ * or it was destroyed, evicted or dropped by another tab). Look it up again, and hold it while
3662
+ * using it.
3663
+ */
3664
+ class EntityUnloadedError extends Error {
3665
+ constructor(message) {
3666
+ super(message);
3667
+ this.name = 'EntityUnloadedError';
3668
+ }
3669
+ }
3816
3670
  /** Run `dispose` when the entity is torn down (unsubscribe a watch, revoke an object URL). */
3817
3671
  function onEntityTeardown(instance, dispose) {
3818
3672
  const lifecycle = lifecycleOf(instance);
@@ -3844,9 +3698,10 @@ function teardownEntity(instance, cache) {
3844
3698
  lifecycle.error = new EntityLoadError('Entity was unloaded before it finished loading');
3845
3699
  lifecycle.settle();
3846
3700
  }
3701
+ // At once: the parent already waited out its grace period, or was destroyed or evicted
3847
3702
  for (const release of lifecycle.children.values()) {
3848
3703
  try {
3849
- release();
3704
+ release({ immediate: true });
3850
3705
  }
3851
3706
  catch {
3852
3707
  // A child that fails to release must not keep the rest held
@@ -3871,9 +3726,12 @@ function teardownEntity(instance, cache) {
3871
3726
  // Already stopped
3872
3727
  }
3873
3728
  }
3874
- /** Give back one hold; tear the entity down when it was the last. */
3875
- function releaseEntity(instance, cache) {
3876
- if (cache.release(instance))
3729
+ /**
3730
+ * Give back one hold. With the last one the entity is torn down after the grace period (at once
3731
+ * with `immediate`, or when the grace period is 0); a hold taken meanwhile keeps it.
3732
+ */
3733
+ function releaseEntity(instance, cache, options) {
3734
+ if (cache.release(instance, options))
3877
3735
  teardownEntity(instance, cache);
3878
3736
  }
3879
3737
  /**
@@ -3886,6 +3744,14 @@ function evictEntities(cache, filter) {
3886
3744
  teardownEntity(instance, cache);
3887
3745
  return evicted;
3888
3746
  }
3747
+ /**
3748
+ * Stop and drop every cached entity of every class, whoever holds it (client.stop()). Reaches the
3749
+ * caches through EntityCache.all, so callers needn't import the entity classes.
3750
+ */
3751
+ function evictAllEntities() {
3752
+ for (const cache of EntityCache.all)
3753
+ evictEntities(cache, () => true);
3754
+ }
3889
3755
  /**
3890
3756
  * Delete an entity's rows. By default it leaves the cache first, so no lookup returns it meanwhile;
3891
3757
  * with `leaveCache: 'after'` it stays cached until the rows are gone, so a lookup that read a row
@@ -3923,7 +3789,7 @@ function holdChild(parent, child, childCache) {
3923
3789
  return true;
3924
3790
  if (!childCache.holdInstance(child))
3925
3791
  return false;
3926
- lifecycle.children.set(key, () => releaseEntity(child, childCache));
3792
+ lifecycle.children.set(key, (options) => releaseEntity(child, childCache, options));
3927
3793
  return true;
3928
3794
  }
3929
3795
  function releaseChildHold(parent, child) {
@@ -3940,6 +3806,258 @@ function heldChildActors(parent) {
3940
3806
  return [...lifecycleOf(parent).children.keys()];
3941
3807
  }
3942
3808
 
3809
+ /** Default for `SeedConfig.entityCache.unloadGraceMs`. */
3810
+ const DEFAULT_UNLOAD_GRACE_MS = 60000;
3811
+ let defaultUnloadGraceMs = DEFAULT_UNLOAD_GRACE_MS;
3812
+ let configuredUnloadGraceMs;
3813
+ /** How long an instance no one holds stays cached before it is torn down. 0: no grace period. */
3814
+ function entityUnloadGraceMs() {
3815
+ return configuredUnloadGraceMs ?? defaultUnloadGraceMs;
3816
+ }
3817
+ /** `client.init` sets the configured value; `undefined` (client stop, or none given) uses the default. */
3818
+ function setEntityUnloadGraceMs(ms) {
3819
+ configuredUnloadGraceMs = ms === undefined ? undefined : Math.max(0, ms);
3820
+ }
3821
+ /**
3822
+ * The cache behind an entity class (ADR 0014). `peek` takes no hold; `hold`, `add({ hold: true })`
3823
+ * and `holdInstance` take one each, and `release` gives one back. Entries are found by key or by
3824
+ * actor, so a raw instance and its proxy find the same entry.
3825
+ *
3826
+ * An entry with no holds (its last one released, or added or looked up without one) is torn down
3827
+ * after the grace period (`entityUnloadGraceMs`) unless a hold is taken first, which keeps the same
3828
+ * instance. With a grace period of 0, the last release tears it down at once and an entry that
3829
+ * never had a hold stays cached until it is evicted. Removing an entry (teardown, destroy,
3830
+ * eviction) cancels its timer.
3831
+ */
3832
+ class EntityCache {
3833
+ constructor() {
3834
+ this.byKey = new Map();
3835
+ this.byActor = new WeakMap();
3836
+ EntityCache.all.add(this);
3837
+ }
3838
+ /** Cache `instance` under `keys` (empty and duplicate keys are skipped). Returns its entry. */
3839
+ add(instance, keys, options) {
3840
+ const existing = this.entryOf(instance);
3841
+ if (existing) {
3842
+ if (options.hold)
3843
+ this.addHold(existing);
3844
+ for (const key of keys)
3845
+ if (key)
3846
+ this.addKey(instance, key);
3847
+ return existing;
3848
+ }
3849
+ const entry = {
3850
+ instance,
3851
+ refCount: options.hold ? 1 : 0,
3852
+ keys: new Set(),
3853
+ };
3854
+ this.byActor.set(instance.getService(), entry);
3855
+ for (const key of keys)
3856
+ if (key)
3857
+ this.addKey(instance, key);
3858
+ if (!options.hold)
3859
+ this.keepUnheld(instance);
3860
+ return entry;
3861
+ }
3862
+ /** The cached instance under `key`, without taking a hold. */
3863
+ peek(key) {
3864
+ return key ? this.byKey.get(key)?.instance : undefined;
3865
+ }
3866
+ /** The cached instance under `key`, taking a hold the caller releases with `release`. */
3867
+ hold(key) {
3868
+ const entry = key ? this.byKey.get(key) : undefined;
3869
+ if (!entry)
3870
+ return undefined;
3871
+ this.addHold(entry);
3872
+ return entry.instance;
3873
+ }
3874
+ /** Take a hold on a cached instance. False when it isn't cached (unloaded, evicted). */
3875
+ holdInstance(instance) {
3876
+ const entry = this.entryOf(instance);
3877
+ if (!entry)
3878
+ return false;
3879
+ this.addHold(entry);
3880
+ return true;
3881
+ }
3882
+ /**
3883
+ * Give back one hold. True when the instance should be torn down now: its last hold went and
3884
+ * there is no grace period (or `immediate`), or it isn't cached at all (evicted while the caller
3885
+ * held it). After the last hold with a grace period, the teardown is scheduled instead. An
3886
+ * instance with no holds (a caller that never held it) is left as it is.
3887
+ */
3888
+ release(instance, options = {}) {
3889
+ const entry = this.entryOf(instance);
3890
+ if (!entry)
3891
+ return true;
3892
+ if (entry.refCount <= 0)
3893
+ return false;
3894
+ entry.refCount -= 1;
3895
+ if (entry.refCount > 0)
3896
+ return false;
3897
+ if (options.immediate || entityUnloadGraceMs() === 0)
3898
+ return true;
3899
+ this.scheduleUnload(entry);
3900
+ return false;
3901
+ }
3902
+ /**
3903
+ * An instance a caller looked up without a hold: when no one holds it, restart its grace period,
3904
+ * so it stays cached that long after its last use. Does nothing without a grace period.
3905
+ */
3906
+ keepUnheld(instance) {
3907
+ const entry = this.entryOf(instance);
3908
+ if (entry && entry.refCount <= 0 && entityUnloadGraceMs() > 0)
3909
+ this.scheduleUnload(entry);
3910
+ }
3911
+ addHold(entry) {
3912
+ entry.refCount += 1;
3913
+ this.cancelUnload(entry);
3914
+ }
3915
+ scheduleUnload(entry) {
3916
+ this.cancelUnload(entry);
3917
+ const teardown = () => {
3918
+ this.cancelUnload(entry);
3919
+ if (this.byActor.get(entry.instance.getService()) === entry && entry.refCount <= 0) {
3920
+ teardownEntity(entry.instance, this);
3921
+ }
3922
+ };
3923
+ const timer = setTimeout(teardown, entityUnloadGraceMs());
3924
+ timer.unref?.();
3925
+ entry.unloadTimer = timer;
3926
+ }
3927
+ cancelUnload(entry) {
3928
+ if (entry.unloadTimer === undefined)
3929
+ return;
3930
+ clearTimeout(entry.unloadTimer);
3931
+ entry.unloadTimer = undefined;
3932
+ }
3933
+ entryOf(instance) {
3934
+ return this.byActor.get(instance.getService());
3935
+ }
3936
+ has(instance) {
3937
+ return this.entryOf(instance) !== undefined;
3938
+ }
3939
+ /**
3940
+ * Store the instance under one more key. A key held by another instance moves to this one:
3941
+ * the newest instance for a name or uid wins.
3942
+ */
3943
+ addKey(instance, key) {
3944
+ const entry = this.entryOf(instance);
3945
+ if (!entry || !key)
3946
+ return;
3947
+ const previous = this.byKey.get(key);
3948
+ if (previous === entry)
3949
+ return;
3950
+ previous?.keys.delete(key);
3951
+ this.byKey.set(key, entry);
3952
+ entry.keys.add(key);
3953
+ }
3954
+ removeKey(instance, key) {
3955
+ const entry = this.entryOf(instance);
3956
+ if (!entry || !entry.keys.has(key))
3957
+ return;
3958
+ entry.keys.delete(key);
3959
+ if (this.byKey.get(key) === entry)
3960
+ this.byKey.delete(key);
3961
+ }
3962
+ /** Replace every key of the instance (a rename, an id that changed). */
3963
+ setKeys(instance, keys) {
3964
+ const entry = this.entryOf(instance);
3965
+ if (!entry)
3966
+ return;
3967
+ const next = new Set(keys.filter((key) => !!key));
3968
+ for (const key of [...entry.keys])
3969
+ if (!next.has(key))
3970
+ this.removeKey(instance, key);
3971
+ for (const key of next)
3972
+ this.addKey(instance, key);
3973
+ }
3974
+ keysOf(instance) {
3975
+ return [...(this.entryOf(instance)?.keys ?? [])];
3976
+ }
3977
+ /** Drop the instance under all its keys. Teardown (entityLifecycle) also releases its children. */
3978
+ remove(instance) {
3979
+ const entry = this.entryOf(instance);
3980
+ if (!entry)
3981
+ return undefined;
3982
+ this.cancelUnload(entry);
3983
+ for (const key of entry.keys) {
3984
+ if (this.byKey.get(key) === entry)
3985
+ this.byKey.delete(key);
3986
+ }
3987
+ entry.keys.clear();
3988
+ this.byActor.delete(instance.getService());
3989
+ return entry;
3990
+ }
3991
+ /** Every cached instance once, optionally filtered. */
3992
+ instances(filter) {
3993
+ const seen = new Set();
3994
+ const result = [];
3995
+ for (const entry of this.byKey.values()) {
3996
+ if (seen.has(entry))
3997
+ continue;
3998
+ seen.add(entry);
3999
+ if (!filter || filter(entry.instance))
4000
+ result.push(entry.instance);
4001
+ }
4002
+ return result;
4003
+ }
4004
+ get size() {
4005
+ return this.instances().length;
4006
+ }
4007
+ }
4008
+ /** Every cache made, one per entity class; client.stop() evicts them all (evictAllEntities). */
4009
+ EntityCache.all = new Set();
4010
+ /**
4011
+ * Evictions and destroys, by scope (`schema:<name>`, `model:<id>`). Work that reads a row and then
4012
+ * creates an instance from it (a lookup by id) can't be cancelled by stopping actors: capture
4013
+ * `evictionLog.now()` before the read, and skip creating when `evictedSince(scopes, then)`. A scope
4014
+ * also counts as evicted while its destroy runs, since its rows still exist until the delete commits.
4015
+ */
4016
+ const evictionLog = {
4017
+ generation: 0,
4018
+ last: new Map(),
4019
+ running: new Map(),
4020
+ now() {
4021
+ return this.generation;
4022
+ },
4023
+ /** Record an eviction of these scopes. Call the returned function once a destroy's rows are gone. */
4024
+ evict(scopes) {
4025
+ this.generation += 1;
4026
+ for (const scope of scopes) {
4027
+ this.last.set(scope, this.generation);
4028
+ this.running.set(scope, (this.running.get(scope) ?? 0) + 1);
4029
+ }
4030
+ let finished = false;
4031
+ return () => {
4032
+ if (finished)
4033
+ return;
4034
+ finished = true;
4035
+ // Work that read a row during the destroy and checks after it must still see the eviction
4036
+ this.generation += 1;
4037
+ for (const scope of scopes) {
4038
+ this.last.set(scope, this.generation);
4039
+ const remaining = (this.running.get(scope) ?? 1) - 1;
4040
+ if (remaining > 0)
4041
+ this.running.set(scope, remaining);
4042
+ else
4043
+ this.running.delete(scope);
4044
+ }
4045
+ };
4046
+ },
4047
+ /** True when a scope is being destroyed, or was evicted after `since`. */
4048
+ evictedSince(scopes, since) {
4049
+ for (const scope of scopes) {
4050
+ if (!scope)
4051
+ continue;
4052
+ if (this.running.has(scope))
4053
+ return true;
4054
+ if (this.generation !== since && (this.last.get(scope) ?? 0) > since)
4055
+ return true;
4056
+ }
4057
+ return false;
4058
+ },
4059
+ };
4060
+
3943
4061
  const logger$4 = debug('seedSdk:itemProperty:loadProperty');
3944
4062
  /**
3945
4063
  * Load a property's value and definition: its current row (with a pending outbox value over it,
@@ -3970,15 +4088,14 @@ async function loadProperty(context) {
3970
4088
  });
3971
4089
  timing.mark('metadata');
3972
4090
  if (!metadataRecord) {
3973
- // Metadata not found - this is a new property, will be created elsewhere.
3974
- // Still resolve propertyRecordSchema from Model so getSegmentedItemProperties and
3975
- // getPublishPayload can route and attest the property (e.g. title, description).
4091
+ // No row yet: its first assignment writes one. The definition still comes from the model,
4092
+ // since the setter checks and routes values by it (planPropertyWrite).
3976
4093
  let propertyRecordSchema = undefined;
3977
4094
  const modelNameForNew = context.modelName;
3978
4095
  if (modelNameForNew) {
3979
4096
  try {
3980
- const _mod_3 = await import('./tabEvents-CaVmngqr.js');
3981
- const _ns_3 = _mod_3.be;
4097
+ const _mod_3 = await import('./tabEvents-BHPY5I08.js');
4098
+ const _ns_3 = _mod_3.bh;
3982
4099
  const { resolveItemModelFileId, modelNameForType } = _ns_3;
3983
4100
  const itemModelFileId = await resolveItemModelFileId({
3984
4101
  modelFileId: context.modelFileId,
@@ -4017,8 +4134,8 @@ async function loadProperty(context) {
4017
4134
  // Load propertyRecordSchema from database to make ItemProperty independent from Model
4018
4135
  let propertyRecordSchema = undefined;
4019
4136
  // Model names are only unique per schema: pin lookups to the item's own model row.
4020
- const _mod_4 = await import('./tabEvents-CaVmngqr.js');
4021
- const _ns_4 = _mod_4.be;
4137
+ const _mod_4 = await import('./tabEvents-BHPY5I08.js');
4138
+ const _ns_4 = _mod_4.bh;
4022
4139
  const { resolveItemModelFileId, modelNameForType } = _ns_4;
4023
4140
  const modelFileId = await resolveItemModelFileId({
4024
4141
  modelFileId: context.modelFileId,
@@ -4122,11 +4239,11 @@ async function loadPropertyDefinition(db, { propertyId, modelName, modelFileId,
4122
4239
  }
4123
4240
  if (!modelName)
4124
4241
  return undefined;
4125
- const { loadModelPropertyRecordSchemas } = await import('./modelPropertyRecordSchemas-C7UgA5TH.js');
4242
+ const { loadModelPropertyRecordSchemas } = await import('./modelPropertyRecordSchemas-BGvtTyaG.js');
4126
4243
  const definition = (await loadModelPropertyRecordSchemas(modelName, modelFileId, db)).get(propertyName);
4127
4244
  if (definition)
4128
4245
  return definition;
4129
- const _mod_5 = await import('./errors-DLSoqSHG.js');
4246
+ const _mod_5 = await import('./errors-DpC9W4i3.js');
4130
4247
  const _ns_5 = _mod_5.a4;
4131
4248
  const { Model } = _ns_5;
4132
4249
  const { modelPropertiesToObject } = await Promise.resolve().then(function () { return model; });
@@ -4232,13 +4349,17 @@ let validationLoading;
4232
4349
  function whenValidationLoaded() {
4233
4350
  if (validationService)
4234
4351
  return Promise.resolve();
4235
- validationLoading ?? (validationLoading = import('./SchemaValidationService-CnmKyzR-.js')
4236
- .then(({ SchemaValidationService }) => {
4237
- validationService = new SchemaValidationService();
4238
- })
4239
- .finally(() => {
4240
- validationLoading = undefined;
4241
- }));
4352
+ // async/await, not import().then: rollup's dynamic-import rewrite (rollup.config.mjs) only
4353
+ // neutralizes the minified chunk-export read (`.then(n => n._)`) in this form
4354
+ validationLoading ?? (validationLoading = (async () => {
4355
+ try {
4356
+ const { SchemaValidationService } = await import('./SchemaValidationService-C1xqJFxI.js');
4357
+ validationService = new SchemaValidationService();
4358
+ }
4359
+ finally {
4360
+ validationLoading = undefined;
4361
+ }
4362
+ })());
4242
4363
  return validationLoading;
4243
4364
  }
4244
4365
  const isValidationLoaded = () => validationService !== undefined;
@@ -4467,17 +4588,17 @@ hints = {}) => {
4467
4588
  }
4468
4589
  try {
4469
4590
  if (hints.propertyId != null) {
4470
- const _mod_6 = await import('./tabEvents-CaVmngqr.js');
4471
- const _ns_6 = _mod_6.bf;
4591
+ const _mod_6 = await import('./tabEvents-BHPY5I08.js');
4592
+ const _ns_6 = _mod_6.bi;
4472
4593
  const { getPropertyDefinition } = _ns_6;
4473
4594
  const definition = await getPropertyDefinition(hints.propertyId);
4474
4595
  if (definition)
4475
4596
  return definition;
4476
4597
  }
4477
- const _mod_7 = await import('./tabEvents-CaVmngqr.js');
4478
- const _ns_7 = _mod_7.be;
4598
+ const _mod_7 = await import('./tabEvents-BHPY5I08.js');
4599
+ const _ns_7 = _mod_7.bh;
4479
4600
  const { resolveItemModelFileId } = _ns_7;
4480
- const { getModelPropertyDefinitions, resolvePropertyKey } = await import('./property-BxUYznH0.js');
4601
+ const { getModelPropertyDefinitions, resolvePropertyKey } = await import('./property-QjljUeb9.js');
4481
4602
  const modelFileId = (await resolveItemModelFileId(hints)) ?? undefined;
4482
4603
  const name = modelName || ((await modelTypeToModelName(modelType)) ?? '');
4483
4604
  // An ambiguous bare name reads nothing here; the in-memory model below may still know it
@@ -4485,7 +4606,7 @@ hints = {}) => {
4485
4606
  const key = resolvePropertyKey(definitions, propertyName);
4486
4607
  if (key)
4487
4608
  return definitions[key];
4488
- const _mod_8 = await import('./errors-DLSoqSHG.js');
4609
+ const _mod_8 = await import('./errors-DpC9W4i3.js');
4489
4610
  const _ns_8 = _mod_8.a4;
4490
4611
  const { Model } = _ns_8;
4491
4612
  const { modelPropertiesToObject } = await Promise.resolve().then(function () { return model; });
@@ -4506,8 +4627,8 @@ hints = {}) => {
4506
4627
  const modelTypeToModelName = async (modelType) => {
4507
4628
  if (!modelType)
4508
4629
  return undefined;
4509
- const _mod_9 = await import('./tabEvents-CaVmngqr.js');
4510
- const _ns_9 = _mod_9.be;
4630
+ const _mod_9 = await import('./tabEvents-BHPY5I08.js');
4631
+ const _ns_9 = _mod_9.bh;
4511
4632
  const { modelNameForType } = _ns_9;
4512
4633
  return modelNameForType(modelType).catch(() => undefined);
4513
4634
  };
@@ -4670,7 +4791,7 @@ class ItemProperty {
4670
4791
  return;
4671
4792
  }
4672
4793
  // Use dynamic import to break circular dependency
4673
- const schemaMod = await import('./index-BVBmz_cc.js');
4794
+ const schemaMod = await import('./index-uDLe9y9H.js');
4674
4795
  const { ModelPropertyDataTypes } = schemaMod;
4675
4796
  const { context } = snapshot;
4676
4797
  const { propertyRecordSchema } = context;
@@ -4883,7 +5004,7 @@ class ItemProperty {
4883
5004
  // The change feed reports writes by stored name: watch every name this property's rows have
4884
5005
  const propertyNames = [...property.names];
4885
5006
  if (propertyId != null) {
4886
- const _mod_10 = await import('./index-D0V-mjCV.js');
5007
+ const _mod_10 = await import('./index-BjWk0x4-.js');
4887
5008
  const _ns_10 = _mod_10.s;
4888
5009
  const { metadata } = _ns_10;
4889
5010
  const { eq: eqOp } = await import('drizzle-orm');
@@ -4923,12 +5044,17 @@ class ItemProperty {
4923
5044
  // A pending edit settles the conflict when it applies, so an overlaid row shows none.
4924
5045
  // `assignSeq` marks a read begun before an assignment in this tab: it may predate that op,
4925
5046
  // which the context already shows, so the feed drops it.
5047
+ // Sync records a conflict and moves its draft to newest in one transaction, so a row read
5048
+ // before the conflict may be the synced one: read the row again once a conflict shows.
4926
5049
  const readRow = async () => {
4927
5050
  const assignSeq = this._assignSeq;
4928
- const row = await currentPropertyRow({ seedLocalId, seedUid }, { match: property, propertyName }, { overlay: true, db });
5051
+ const read = () => currentPropertyRow({ seedLocalId, seedUid }, { match: property, propertyName }, { overlay: true, db });
5052
+ let row = await read();
4929
5053
  if (!row)
4930
5054
  return row;
4931
5055
  const conflict = row.overlaid ? null : await getPropertyConflict(row.seedLocalId ?? seedLocalId, propertyName);
5056
+ if (conflict)
5057
+ row = (await read()) ?? row;
4932
5058
  return { ...row, conflict, assignSeq };
4933
5059
  };
4934
5060
  // In the browser the feed watch below reads the row at once, so only Node (no change feed)
@@ -5057,6 +5183,33 @@ class ItemProperty {
5057
5183
  });
5058
5184
  }
5059
5185
  }
5186
+ /** Takes a property definition read from its row, as the constructor takes the initial one. */
5187
+ _applyDefinition(propertyRecordSchema) {
5188
+ this._service.send({ type: 'updateContext', propertyRecordSchema });
5189
+ this._dataType = normalizeDataType(propertyRecordSchema.dataType);
5190
+ const isList = isDataType(propertyRecordSchema.dataType, ModelPropertyDataTypes.List);
5191
+ this._isList = isList;
5192
+ this._isRelation = isList
5193
+ ? !!propertyRecordSchema.ref
5194
+ : isDataType(propertyRecordSchema.dataType, ModelPropertyDataTypes.Relation);
5195
+ }
5196
+ /**
5197
+ * Gives cached instances of these properties their rows' current definitions, after a schema
5198
+ * change wrote the rows (refreshCachedProperties). An instance keeps the definition it loaded
5199
+ * with otherwise: Node has no live query, and the browser's arrives some time after the write.
5200
+ */
5201
+ static async refreshDefinitions(propertyFileIds) {
5202
+ const instances = this.cache.instances().filter((instance) => !isActorStopped(instance._service));
5203
+ if (instances.length === 0)
5204
+ return;
5205
+ const definitions = await getPropertyDefinitionsByFileId(propertyFileIds);
5206
+ for (const instance of instances) {
5207
+ const fileId = instance._getSnapshotContext().propertyRecordSchema?.id;
5208
+ const definition = fileId ? definitions.get(fileId) : undefined;
5209
+ if (definition)
5210
+ instance._applyDefinition(definition);
5211
+ }
5212
+ }
5060
5213
  /**
5061
5214
  * Set up liveQuery subscription to watch for property schema changes in the properties table.
5062
5215
  * When ModelProperty dataType (or other schema fields) changes in the database, ItemProperty
@@ -5077,8 +5230,8 @@ class ItemProperty {
5077
5230
  const ctx = this._service.getSnapshot().context;
5078
5231
  let modelFileId;
5079
5232
  try {
5080
- const _mod_11 = await import('./tabEvents-CaVmngqr.js');
5081
- const _ns_11 = _mod_11.be;
5233
+ const _mod_11 = await import('./tabEvents-BHPY5I08.js');
5234
+ const _ns_11 = _mod_11.bh;
5082
5235
  const { resolveItemModelFileId } = _ns_11;
5083
5236
  modelFileId = await resolveItemModelFileId({
5084
5237
  modelFileId: ctx.modelFileId,
@@ -5131,29 +5284,7 @@ class ItemProperty {
5131
5284
  const required = row.required;
5132
5285
  const propertyRecordSchema = propertyDefinitionFromRow({ ...row, required: required == null ? null : !!required }, refModelName);
5133
5286
  logger(`[ItemProperty._setupPropertySchemaLiveQuery] Schema updated for ${propertyName}: dataType=${row.dataType}`);
5134
- this._service.send({
5135
- type: 'updateContext',
5136
- propertyRecordSchema,
5137
- });
5138
- // Update instance fields to match new schema (mirror constructor logic)
5139
- this._dataType = normalizeDataType(propertyRecordSchema.dataType);
5140
- if (isDataType(propertyRecordSchema.dataType, ModelPropertyDataTypes.Relation)) {
5141
- ;
5142
- this._isRelation = true;
5143
- }
5144
- else {
5145
- ;
5146
- this._isRelation = false;
5147
- }
5148
- if (isDataType(propertyRecordSchema.dataType, ModelPropertyDataTypes.List)) {
5149
- ;
5150
- this._isList = true;
5151
- this._isRelation = !!(propertyRecordSchema.ref);
5152
- }
5153
- else {
5154
- ;
5155
- this._isList = false;
5156
- }
5287
+ this._applyDefinition(propertyRecordSchema);
5157
5288
  },
5158
5289
  error: (error) => {
5159
5290
  logger(`[ItemProperty._setupPropertySchemaLiveQuery] LiveQuery error: ${error}`);
@@ -5205,6 +5336,8 @@ class ItemProperty {
5205
5336
  if (cached) {
5206
5337
  if (holds)
5207
5338
  this.cache.holdInstance(cached);
5339
+ else
5340
+ this.cache.keepUnheld(cached);
5208
5341
  for (const key of [keyByLocal, keyByUid])
5209
5342
  this.cache.addKey(cached, key);
5210
5343
  this.syncFromRow(cached, props);
@@ -5337,8 +5470,11 @@ class ItemProperty {
5337
5470
  }
5338
5471
  return undefined;
5339
5472
  }
5340
- /** Takes a hold on the instance it returns: release it with `unload()`. */
5341
- static async find({ propertyName, seedLocalId, seedUid, modelName: modelNameOption, waitForReady = true, readyTimeout = DEFAULT_READY_TIMEOUT_MS, hold, }) {
5473
+ /**
5474
+ * The property's instance, loaded from its row when it isn't cached. Takes no hold unless
5475
+ * `hold: true` (release it with `unload()`).
5476
+ */
5477
+ static async find({ propertyName, seedLocalId, seedUid, modelName: modelNameOption, waitForReady = true, readyTimeout = DEFAULT_READY_TIMEOUT_MS, hold = false, }) {
5342
5478
  if ((!seedLocalId && !seedUid) || !propertyName) {
5343
5479
  return undefined;
5344
5480
  }
@@ -5355,8 +5491,10 @@ class ItemProperty {
5355
5491
  return undefined;
5356
5492
  for (const key of [keyByLocal, keyByUid])
5357
5493
  this.cache.addKey(cached, key);
5358
- if (hold !== false)
5494
+ if (hold)
5359
5495
  this.cache.holdInstance(cached);
5496
+ else
5497
+ this.cache.keepUnheld(cached);
5360
5498
  return cached;
5361
5499
  };
5362
5500
  foundProperty = fromCache();
@@ -5400,10 +5538,10 @@ class ItemProperty {
5400
5538
  /**
5401
5539
  * Get all ItemProperty instances for an item.
5402
5540
  * Loads property data via getItemProperties, creates instances via create, optionally waits for idle.
5403
- * Takes a hold on each instance, as `create` does.
5541
+ * Takes no holds unless `hold: true`, as `find`.
5404
5542
  */
5405
5543
  static async all(params, options) {
5406
- const { waitForReady = false, readyTimeout = DEFAULT_READY_TIMEOUT_MS, hold } = options ?? {};
5544
+ const { waitForReady = false, readyTimeout = DEFAULT_READY_TIMEOUT_MS, hold = false } = options ?? {};
5407
5545
  const { seedLocalId, seedUid } = params;
5408
5546
  if (!seedLocalId && !seedUid) {
5409
5547
  return [];
@@ -5411,8 +5549,8 @@ class ItemProperty {
5411
5549
  const propertiesData = await getItemProperties({ seedLocalId, seedUid });
5412
5550
  const instances = [];
5413
5551
  const seenNormalized = new Set();
5414
- const _mod_12 = await import('./tabEvents-CaVmngqr.js');
5415
- const _ns_12 = _mod_12.be;
5552
+ const _mod_12 = await import('./tabEvents-BHPY5I08.js');
5553
+ const _ns_12 = _mod_12.bh;
5416
5554
  const { resolveItemModelFileId } = _ns_12;
5417
5555
  const itemModelFileId = await resolveItemModelFileId({ seedLocalId, seedUid });
5418
5556
  // One lookup per model type, not per property
@@ -5433,7 +5571,7 @@ class ItemProperty {
5433
5571
  // (`textId` → `text`, `authorIdentityIds` → `authors`)
5434
5572
  const definitionsKey = JSON.stringify([modelName, modelFileId ?? null]);
5435
5573
  if (modelName && !definitionsByModel.has(definitionsKey)) {
5436
- const { getModelPropertyDefinitions } = await import('./property-BxUYznH0.js');
5574
+ const { getModelPropertyDefinitions } = await import('./property-QjljUeb9.js');
5437
5575
  definitionsByModel.set(definitionsKey,
5438
5576
  // No model row: the stored name decides
5439
5577
  getModelPropertyDefinitions(modelName, { modelFileId }).then(Object.fromEntries, () => ({})));
@@ -5607,7 +5745,7 @@ class ItemProperty {
5607
5745
  const { seedLocalId, propertyName } = this._getSnapshotContext();
5608
5746
  if (!seedLocalId || !propertyName)
5609
5747
  return;
5610
- const { appendOutboxOpAndWait, markPropertyConflictsResolved, startItemOutbox, throwItemWriteError } = await import('./index-CYGWPoOx.js');
5748
+ const { appendOutboxOpAndWait, markPropertyConflictsResolved, startItemOutbox, throwItemWriteError } = await import('./index-BMHqJ4kN.js');
5611
5749
  if (choice === 'remote') {
5612
5750
  startItemOutbox();
5613
5751
  await appendOutboxOpAndWait({
@@ -5654,6 +5792,7 @@ class ItemProperty {
5654
5792
  * any tab, else its stored row.
5655
5793
  */
5656
5794
  setValue(value) {
5795
+ this._assertLoaded('set');
5657
5796
  // An empty Image, File or Html value has nothing to store: it clears the property
5658
5797
  if ((value == null || (typeof value === 'string' && value.trim() === '')) && this._holdsStorageSeed(this._getSnapshotContext())) {
5659
5798
  this._assign(null, { retract: false });
@@ -5754,8 +5893,8 @@ class ItemProperty {
5754
5893
  context = this._getSnapshotContext();
5755
5894
  if (!context.seedLocalId) {
5756
5895
  // An item known only by its seed uid: its local seed, if it has one
5757
- const _mod_13 = await import('./tabEvents-CaVmngqr.js');
5758
- const _ns_13 = _mod_13.bd;
5896
+ const _mod_13 = await import('./tabEvents-BHPY5I08.js');
5897
+ const _ns_13 = _mod_13.bg;
5759
5898
  const { findSeedRow } = _ns_13;
5760
5899
  const seedLocalId = context.seedUid ? (await findSeedRow({ uid: context.seedUid }))?.localId : undefined;
5761
5900
  if (!seedLocalId)
@@ -5794,7 +5933,7 @@ class ItemProperty {
5794
5933
  /** Waits for an appended op to settle, then shows its row, or the current value if it failed. */
5795
5934
  async _followWrite(write, appended, plan) {
5796
5935
  try {
5797
- const { getOutboxOps, outboxOpResult, startItemOutbox, waitForOutboxOp } = await import('./index-CYGWPoOx.js');
5936
+ const { getOutboxOps, outboxOpResult, startItemOutbox, waitForOutboxOp } = await import('./index-BMHqJ4kN.js');
5798
5937
  startItemOutbox();
5799
5938
  const opId = await appended;
5800
5939
  await waitForOutboxOp(opId);
@@ -5853,7 +5992,7 @@ class ItemProperty {
5853
5992
  this._service.send({ type: 'updateContext', ...outcome.applied, isSaving: false });
5854
5993
  return;
5855
5994
  }
5856
- const { throwItemWriteError } = await import('./index-CYGWPoOx.js');
5995
+ const { throwItemWriteError } = await import('./index-BMHqJ4kN.js');
5857
5996
  let error = outcome.error;
5858
5997
  try {
5859
5998
  throwItemWriteError(outcome.error);
@@ -5919,6 +6058,7 @@ class ItemProperty {
5919
6058
  * ItemPropertySaveValidationError when the value broke a rule and was not written.
5920
6059
  */
5921
6060
  async save() {
6061
+ this._assertLoaded('save');
5922
6062
  const ctx = this._getSnapshotContext();
5923
6063
  const label = `save ${ctx?.modelName ?? '?'}.${ctx?.propertyName ?? '?'}`;
5924
6064
  const { assertItemOwned } = await Promise.resolve().then(function () { return ownership; });
@@ -5949,6 +6089,14 @@ class ItemProperty {
5949
6089
  * Every cache key holding this instance: its item's local id and seed uid, and the name it had
5950
6090
  * before a rename (List of relation). They share one entry.
5951
6091
  */
6092
+ /** Throws EntityUnloadedError, naming the property and its item, when this instance was unloaded. */
6093
+ _assertLoaded(action) {
6094
+ if (!isEntityTornDown(this))
6095
+ return;
6096
+ const { seedLocalId, seedUid, modelName, propertyName } = this._getSnapshotContext();
6097
+ throw new EntityUnloadedError(`Cannot ${action} ${modelName ?? '?'}.${propertyName ?? '?'} of item ${seedLocalId ?? seedUid ?? '(no id)'}: ` +
6098
+ 'this ItemProperty instance was unloaded. Look the item or property up again, and hold it while you use it.');
6099
+ }
5952
6100
  /** Releases this caller's hold; the last one stops the property and drops it from the cache. */
5953
6101
  unload() {
5954
6102
  releaseEntity(this, ItemProperty.cache);
@@ -5979,7 +6127,7 @@ class ItemProperty {
5979
6127
  if (db && seedLocalId) {
5980
6128
  // Through the outbox (ADR 0019): after the property's pending edits, which would
5981
6129
  // otherwise write its rows back
5982
- const { appendOutboxOpAndWait, startItemOutbox, throwItemWriteError } = await import('./index-CYGWPoOx.js');
6130
+ const { appendOutboxOpAndWait, startItemOutbox, throwItemWriteError } = await import('./index-BMHqJ4kN.js');
5983
6131
  startItemOutbox();
5984
6132
  await appendOutboxOpAndWait({
5985
6133
  seedLocalId,
@@ -5989,7 +6137,7 @@ class ItemProperty {
5989
6137
  }).catch(throwItemWriteError);
5990
6138
  }
5991
6139
  else if (db) {
5992
- const _mod_14 = await import('./index-D0V-mjCV.js');
6140
+ const _mod_14 = await import('./index-BjWk0x4-.js');
5993
6141
  const _ns_14 = _mod_14.s;
5994
6142
  const seedSchemaMod = _ns_14;
5995
6143
  const { metadata } = seedSchemaMod;
@@ -6018,6 +6166,7 @@ class ItemProperty {
6018
6166
  }
6019
6167
  /** Cached as `Item_<id>_<propertyName>` under its item's local id and seed uid. */
6020
6168
  ItemProperty.cache = new EntityCache();
6169
+ addCachedPropertyRefresher((propertyFileIds) => ItemProperty.refreshDefinitions(propertyFileIds));
6021
6170
 
6022
6171
  var ItemProperty$1 = /*#__PURE__*/Object.freeze({
6023
6172
  __proto__: null,
@@ -6221,7 +6370,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
6221
6370
  propertyRecordSchema?.validation &&
6222
6371
  metadataValues.propertyValue != null &&
6223
6372
  metadataValues.propertyValue !== '') {
6224
- const { SchemaValidationService } = await import('./SchemaValidationService-CnmKyzR-.js');
6373
+ const { SchemaValidationService } = await import('./SchemaValidationService-C1xqJFxI.js');
6225
6374
  const validationService = new SchemaValidationService();
6226
6375
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, normalizeDataType(propertyRecordSchema.dataType), propertyRecordSchema.validation, propertyRecordSchema.refValueType
6227
6376
  ? normalizeDataType(String(propertyRecordSchema.refValueType))
@@ -6315,7 +6464,7 @@ const createNewItem = async ({ modelName, modelFileId, ...propertyData }) => {
6315
6464
  }
6316
6465
  const seedType = easName(modelName);
6317
6466
  // Dynamic import to break circular dependency
6318
- const _mod_15 = await import('./errors-DLSoqSHG.js');
6467
+ const _mod_15 = await import('./errors-DpC9W4i3.js');
6319
6468
  const _ns_15 = _mod_15.a4;
6320
6469
  const modelMod = _ns_15;
6321
6470
  const { Model } = modelMod;
@@ -6373,7 +6522,7 @@ const createNewItem = async ({ modelName, modelFileId, ...propertyData }) => {
6373
6522
  }
6374
6523
  rows.push({ propertyName, propertyValue, propertyRecordSchema, schemaUid: schemaUids.get(propertyName) });
6375
6524
  }
6376
- const { appendOutboxOpAndWait, startItemOutbox } = await import('./index-CYGWPoOx.js');
6525
+ const { appendOutboxOpAndWait, startItemOutbox } = await import('./index-BMHqJ4kN.js');
6377
6526
  startItemOutbox();
6378
6527
  const fields = await timed(`${label} seed fields`, () => resolveNewSeedFields(seedType));
6379
6528
  const applied = await timed(`${label} outbox apply`, () => appendOutboxOpAndWait({
@@ -6392,7 +6541,7 @@ const createNewItem = async ({ modelName, modelFileId, ...propertyData }) => {
6392
6541
  }
6393
6542
  catch (error) {
6394
6543
  // Staged values of a create that never got appended (once appended, the op's discard does it)
6395
- const _mod_16 = await import('./errors-DLSoqSHG.js');
6544
+ const _mod_16 = await import('./errors-DpC9W4i3.js');
6396
6545
  const _ns_16 = _mod_16.a7;
6397
6546
  const { deleteFiles } = _ns_16;
6398
6547
  await deleteFiles(stagedPaths);
@@ -6468,14 +6617,14 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6468
6617
  };
6469
6618
  // The model's property definitions from their rows; a model created in this session whose
6470
6619
  // rows aren't written yet gives its in-memory ones
6471
- const { getModelPropertyDefinitions } = await import('./property-BxUYznH0.js');
6620
+ const { getModelPropertyDefinitions } = await import('./property-QjljUeb9.js');
6472
6621
  let propertySchemas = Object.fromEntries(await getModelPropertyDefinitions(modelName, modelScope).catch((err) => {
6473
6622
  logger(`No property definitions for ${modelName}: ${err}`);
6474
6623
  return [];
6475
6624
  }));
6476
6625
  if (Object.keys(propertySchemas).length === 0) {
6477
6626
  const { modelPropertiesToObject } = await Promise.resolve().then(function () { return model; });
6478
- const _mod_17 = await import('./errors-DLSoqSHG.js');
6627
+ const _mod_17 = await import('./errors-DpC9W4i3.js');
6479
6628
  const _ns_17 = _mod_17.a4;
6480
6629
  const { Model } = _ns_17;
6481
6630
  const model$1 = Model.resolve(modelName, modelScope);
@@ -6503,7 +6652,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
6503
6652
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
6504
6653
  let propSchema = propertySchemas[propertyName];
6505
6654
  if (!propSchema && isRefTypeFromMeta) {
6506
- const schemaMod = await import('./index-BVBmz_cc.js');
6655
+ const schemaMod = await import('./index-uDLe9y9H.js');
6507
6656
  const { ModelPropertyDataTypes } = schemaMod;
6508
6657
  propSchema = {
6509
6658
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -6886,7 +7035,7 @@ const getModel = () => {
6886
7035
  // the fragile `import(...).then(n => n.X)` chunk-namespace pattern.
6887
7036
  if (!modelImportPromise) {
6888
7037
  modelImportPromise = (async () => {
6889
- const _mod_18 = await import('./errors-DLSoqSHG.js');
7038
+ const _mod_18 = await import('./errors-DpC9W4i3.js');
6890
7039
  const _ns_18 = _mod_18.a4;
6891
7040
  const mod = _ns_18;
6892
7041
  ModelClass = mod.Model;
@@ -7002,6 +7151,7 @@ class Item {
7002
7151
  });
7003
7152
  };
7004
7153
  this.unpublish = async () => {
7154
+ this._assertLoaded('unpublish');
7005
7155
  const { assertItemOwned } = await Promise.resolve().then(function () { return ownership; });
7006
7156
  const { getRevokeExecutor } = await Promise.resolve().then(function () { return publishConfig; });
7007
7157
  await assertItemOwned(this);
@@ -7045,6 +7195,7 @@ class Item {
7045
7195
  * if it failed. Throws OwnershipError if none of the client's addresses own the item.
7046
7196
  */
7047
7197
  this.publish = async (options) => {
7198
+ this._assertLoaded('publish');
7048
7199
  const { assertItemOwned } = await Promise.resolve().then(function () { return ownership; });
7049
7200
  const { getPublishExecutor, PUBLISH_NOT_CONFIGURED_MESSAGE } = await Promise.resolve().then(function () { return publishConfig; });
7050
7201
  await assertItemOwned(this);
@@ -7085,14 +7236,14 @@ class Item {
7085
7236
  };
7086
7237
  this.getPublishUploads = async (options) => {
7087
7238
  // Use dynamic import to break circular dependency
7088
- const _mod_19 = await import('./getPublishUploads-sS6JfPgz.js');
7089
- const _ns_19 = _mod_19.n;
7239
+ const _mod_19 = await import('./getPublishUploads-BdZmYCo2.js');
7240
+ const _ns_19 = _mod_19.q;
7090
7241
  const getPublishUploadsMod = _ns_19;
7091
7242
  const { getPublishUploads } = getPublishUploadsMod;
7092
7243
  return await getPublishUploads(this, options);
7093
7244
  };
7094
7245
  this.getPublishPayload = async (uploadedTransactions, options) => {
7095
- const _mod_20 = await import('./getPublishPayload-BnIwpwz1.js');
7246
+ const _mod_20 = await import('./getPublishPayload-yidQCgY_.js');
7096
7247
  const _ns_20 = _mod_20.c;
7097
7248
  const getPublishPayloadMod = _ns_20;
7098
7249
  const { getPublishPayload } = getPublishPayloadMod;
@@ -7241,13 +7392,13 @@ class Item {
7241
7392
  * Cache a new item under its ids and keep its keys in step with them (a seed uid arrives on
7242
7393
  * publish, moves on republish), then start its load.
7243
7394
  */
7244
- static cacheAndLoad(instance) {
7395
+ static cacheAndLoad(instance, hold = true) {
7245
7396
  const keys = () => {
7246
7397
  const { seedLocalId, seedUid } = instance._getSnapshotContext();
7247
7398
  return [seedLocalId, seedUid];
7248
7399
  };
7249
7400
  let current = keys().join('\u0000');
7250
- this.cache.add(instance, keys(), { hold: true });
7401
+ this.cache.add(instance, keys(), { hold });
7251
7402
  const idWatch = instance._service.subscribe(() => {
7252
7403
  const next = keys();
7253
7404
  if (next.join('\u0000') === current || isEntityTornDown(instance))
@@ -7286,6 +7437,7 @@ class Item {
7286
7437
  sendUpdate: (target, prop, value) => {
7287
7438
  if (prop === 'publisher')
7288
7439
  throw new Error('Cannot set item.publisher: publisher is read-only.');
7440
+ target._assertLoaded(`set ${prop} on`);
7289
7441
  Item.sendTrackedPropertyUpdate(target, prop, value);
7290
7442
  if (prop === 'seedUid' && typeof value === 'string' && value.length > 0) {
7291
7443
  target._persistSeedUid(value);
@@ -7298,6 +7450,7 @@ class Item {
7298
7450
  return {
7299
7451
  get: () => property.value,
7300
7452
  set: (value) => {
7453
+ target._assertLoaded(`set ${prop} on`);
7301
7454
  property.value = value;
7302
7455
  },
7303
7456
  };
@@ -7313,6 +7466,15 @@ class Item {
7313
7466
  reactiveProxies.set(instance._service, proxy);
7314
7467
  return proxy;
7315
7468
  }
7469
+ /** Throws EntityUnloadedError, naming the item, when this instance was unloaded. */
7470
+ _assertLoaded(action) {
7471
+ if (!isEntityTornDown(this))
7472
+ return;
7473
+ const { seedLocalId, seedUid, modelName } = this._getSnapshotContext();
7474
+ throw new EntityUnloadedError(`Cannot ${action} ${modelName ?? 'item'} ${seedLocalId ?? seedUid ?? '(no id)'}: this Item instance was ` +
7475
+ 'unloaded. Look the item up again (Item.find), and hold it while you use it ' +
7476
+ '(Item.find({ hold: true }) or Item.retain, then unload()).');
7477
+ }
7316
7478
  /**
7317
7479
  * The ItemProperty a model property name reads and writes on the item: by its name, or by its
7318
7480
  * storage name (`html` finds `htmlId` and the other way round). Internal names don't resolve.
@@ -7407,11 +7569,12 @@ class Item {
7407
7569
  static async create(props, options) {
7408
7570
  const waitForReady = options?.waitForReady !== false;
7409
7571
  const readyTimeout = options?.readyTimeout ?? DEFAULT_READY_TIMEOUT_MS;
7572
+ const hold = options?.hold !== false;
7410
7573
  if (!props.modelName && props.type) {
7411
7574
  // The model the seed's type names (its easName, at the model's nameMatch level): `blog_post`
7412
7575
  // finds "Blog Post". No match leaves the type, which then fails as an unknown model.
7413
- const _mod_21 = await import('./tabEvents-CaVmngqr.js');
7414
- const _ns_21 = _mod_21.be;
7576
+ const _mod_21 = await import('./tabEvents-BHPY5I08.js');
7577
+ const _ns_21 = _mod_21.bh;
7415
7578
  const { resolveModelRecordByNameOrType } = _ns_21;
7416
7579
  const model = await resolveModelRecordByNameOrType(props.type, {
7417
7580
  modelFileId: props.modelFileId,
@@ -7423,7 +7586,10 @@ class Item {
7423
7586
  // Local id first, so list rows (local + uid) resolve the same instance as early draft loads
7424
7587
  const cached = this.cache.peek(props.seedLocalId) ?? this.cache.peek(props.seedUid);
7425
7588
  if (cached) {
7426
- this.cache.holdInstance(cached);
7589
+ if (hold)
7590
+ this.cache.holdInstance(cached);
7591
+ else
7592
+ this.cache.keepUnheld(cached);
7427
7593
  const propertyInstances = cached.getService().getSnapshot().context.propertyInstances;
7428
7594
  for (const [propertyName, propertyValue] of Object.entries(props)) {
7429
7595
  propertyInstances?.get(propertyName)?.getService().send({ type: 'updateContext', propertyValue });
@@ -7434,7 +7600,8 @@ class Item {
7434
7600
  await waitForEntityReady(cached, { timeout: readyTimeout });
7435
7601
  }
7436
7602
  catch (err) {
7437
- cached.unload();
7603
+ if (hold)
7604
+ cached.unload();
7438
7605
  throw err;
7439
7606
  }
7440
7607
  return cached;
@@ -7443,14 +7610,15 @@ class Item {
7443
7610
  // Exclude latestVersionUid from props as it has incompatible types (string vs VersionsType)
7444
7611
  const { latestVersionUid: _latestVersionUid, ...propsWithoutVersionUid } = props;
7445
7612
  const proxiedInstance = Item.wrapInProxy(new Item({ ...propsWithoutVersionUid }));
7446
- this.cacheAndLoad(proxiedInstance);
7613
+ this.cacheAndLoad(proxiedInstance, hold);
7447
7614
  if (!waitForReady)
7448
7615
  return proxiedInstance;
7449
7616
  try {
7450
7617
  await waitForEntityReady(proxiedInstance, { timeout: readyTimeout });
7451
7618
  }
7452
7619
  catch (err) {
7453
- proxiedInstance.unload();
7620
+ if (hold)
7621
+ proxiedInstance.unload();
7454
7622
  throw err;
7455
7623
  }
7456
7624
  return proxiedInstance;
@@ -7469,8 +7637,8 @@ class Item {
7469
7637
  const db = BaseDb.getAppDb();
7470
7638
  if (db && props.modelName) {
7471
7639
  // Model names are only unique per schema: resolve the exact models row from the most specific scope.
7472
- const _mod_22 = await import('./tabEvents-CaVmngqr.js');
7473
- const _ns_22 = _mod_22.be;
7640
+ const _mod_22 = await import('./tabEvents-BHPY5I08.js');
7641
+ const _ns_22 = _mod_22.bh;
7474
7642
  const { resolveModelRecord } = _ns_22;
7475
7643
  const modelRecord = await resolveModelRecord(props.modelName, {
7476
7644
  modelFileId: props.modelFileId ?? modelInstance?.id,
@@ -7478,7 +7646,7 @@ class Item {
7478
7646
  });
7479
7647
  const modelRecords = modelRecord ? [modelRecord] : [];
7480
7648
  if (!modelRecord) {
7481
- const _mod_23 = await import('./errors-DLSoqSHG.js');
7649
+ const _mod_23 = await import('./errors-DpC9W4i3.js');
7482
7650
  const _ns_23 = _mod_23.a8;
7483
7651
  const { UnknownModelError } = _ns_23;
7484
7652
  throw new UnknownModelError(props.modelName, schemaName ?? modelInstance?.schemaName);
@@ -7489,8 +7657,8 @@ class Item {
7489
7657
  // Scope the constructor's Model lookup to this model's schema (as getItemData does on reload),
7490
7658
  // so a same-named model cached from another schema can't supply the property set.
7491
7659
  if (modelRecord && !props.schemaName) {
7492
- const _mod_24 = await import('./tabEvents-CaVmngqr.js');
7493
- const _ns_24 = _mod_24.be;
7660
+ const _mod_24 = await import('./tabEvents-BHPY5I08.js');
7661
+ const _ns_24 = _mod_24.bh;
7494
7662
  const { getModelSchemaName } = _ns_24;
7495
7663
  const modelSchemaName = await getModelSchemaName(modelRecord.id, db);
7496
7664
  if (modelSchemaName) {
@@ -7560,10 +7728,16 @@ class Item {
7560
7728
  const propsWithModel = { ...propsWithoutVersionUid };
7561
7729
  const newInstance = new Item(propsWithModel);
7562
7730
  const proxiedInstance = Item.wrapInProxy(newInstance);
7731
+ // Held while create saves its values; `hold: false` gives the hold back as it returns
7563
7732
  this.cacheAndLoad(proxiedInstance);
7733
+ const created = () => {
7734
+ if (!hold)
7735
+ this.cache.release(proxiedInstance);
7736
+ return proxiedInstance;
7737
+ };
7564
7738
  // Storage values must be saved before returning, so wait for readiness even when not requested.
7565
7739
  if (!waitForReady && pipelineValues.length === 0)
7566
- return proxiedInstance;
7740
+ return created();
7567
7741
  try {
7568
7742
  await waitForEntityReady(proxiedInstance, { timeout: readyTimeout });
7569
7743
  await this.savePipelineValues(proxiedInstance, pipelineValues, readyTimeout);
@@ -7573,7 +7747,7 @@ class Item {
7573
7747
  await this.discardCreatedItem(proxiedInstance, seedLocalId);
7574
7748
  throw err;
7575
7749
  }
7576
- return proxiedInstance;
7750
+ return created();
7577
7751
  }
7578
7752
  /**
7579
7753
  * Stops a just-created item and deletes what create wrote: a `discard` outbox op (ADR 0019),
@@ -7588,7 +7762,7 @@ class Item {
7588
7762
  /* best-effort cache cleanup */
7589
7763
  }
7590
7764
  try {
7591
- const { appendOutboxOpAndWait, deleteFiles, startItemOutbox } = await import('./index-CYGWPoOx.js');
7765
+ const { appendOutboxOpAndWait, deleteFiles, startItemOutbox } = await import('./index-BMHqJ4kN.js');
7592
7766
  startItemOutbox();
7593
7767
  const applied = await appendOutboxOpAndWait({
7594
7768
  seedLocalId,
@@ -7611,7 +7785,7 @@ class Item {
7611
7785
  for (const [propertyName, value] of pipelineValues) {
7612
7786
  const property = await this.waitForPropertyInstance(item, propertyName, timeout);
7613
7787
  if (!property) {
7614
- const _mod_25 = await import('./errors-DLSoqSHG.js');
7788
+ const _mod_25 = await import('./errors-DpC9W4i3.js');
7615
7789
  const _ns_25 = _mod_25.a8;
7616
7790
  const { ItemCreateError } = _ns_25;
7617
7791
  throw new ItemCreateError(`Item.create: property ${item.modelName}.${propertyName} did not load for item ${item.seedLocalId}; value was not saved`, { code: 'property_not_loaded', modelName: item.modelName, property: propertyName, seedLocalId: item.seedLocalId });
@@ -7623,14 +7797,14 @@ class Item {
7623
7797
  }
7624
7798
  catch (error) {
7625
7799
  if (error instanceof ItemPropertySaveValidationError) {
7626
- const _mod_26 = await import('./errors-DLSoqSHG.js');
7800
+ const _mod_26 = await import('./errors-DpC9W4i3.js');
7627
7801
  const _ns_26 = _mod_26.a8;
7628
7802
  const { ItemCreateValidationError } = _ns_26;
7629
7803
  const created = new ItemCreateValidationError(item.modelName, error.validationErrors.map((e) => ({ property: propertyName, code: e.code, message: e.message })));
7630
7804
  created.cause = error;
7631
7805
  throw created;
7632
7806
  }
7633
- const _mod_27 = await import('./errors-DLSoqSHG.js');
7807
+ const _mod_27 = await import('./errors-DpC9W4i3.js');
7634
7808
  const _ns_27 = _mod_27.a8;
7635
7809
  const { ItemCreateError } = _ns_27;
7636
7810
  throw new ItemCreateError(`Item.create: failed to save ${item.modelName}.${propertyName} for item ${item.seedLocalId}: ` +
@@ -7715,7 +7889,15 @@ class Item {
7715
7889
  modelName,
7716
7890
  }));
7717
7891
  }
7718
- static async find({ modelName, seedLocalId, seedUid, waitForReady = true, readyTimeout = DEFAULT_READY_TIMEOUT_MS, }) {
7892
+ /**
7893
+ * The Item for a seedLocalId or seedUid, loaded from its rows when it isn't cached. Takes no
7894
+ * cache hold: an item no one holds stays cached for the grace period
7895
+ * (`SeedConfig.entityCache.unloadGraceMs`) after this lookup, then unloads. A caller that keeps
7896
+ * the item longer passes `hold: true` and releases it with `unload()`, or holds it with
7897
+ * `Item.retain` (React hooks do). Returns undefined, keeping no hold, when there is no such item
7898
+ * or it isn't ready in `readyTimeout`.
7899
+ */
7900
+ static async find({ modelName, seedLocalId, seedUid, waitForReady = true, readyTimeout = DEFAULT_READY_TIMEOUT_MS, hold = false, }) {
7719
7901
  if (!seedLocalId && !seedUid) {
7720
7902
  return undefined;
7721
7903
  }
@@ -7725,11 +7907,22 @@ class Item {
7725
7907
  return undefined;
7726
7908
  }
7727
7909
  let cached = false;
7910
+ let held;
7728
7911
  try {
7729
7912
  return await timedDb(`find ${modelName ?? '?'} ${id}`, async () => {
7730
- const held = Item.getById(id) ?? undefined;
7731
- cached = held !== undefined;
7732
- const item = held ?? (await Item.createById(id, modelName, seedLocalId ? 'localId' : undefined));
7913
+ const fromCache = hold ? (Item.getById(id) ?? undefined) : Item.peek(id);
7914
+ if (fromCache && !hold)
7915
+ Item.cache.keepUnheld(fromCache);
7916
+ cached = fromCache !== undefined;
7917
+ let item = fromCache;
7918
+ if (!item) {
7919
+ item = await Item.createById(id, modelName, seedLocalId ? 'localId' : undefined);
7920
+ // createById holds what it returns; without one the item waits out the grace period
7921
+ if (item && !hold)
7922
+ Item.cache.release(item);
7923
+ }
7924
+ if (hold)
7925
+ held = item;
7733
7926
  if (item && waitForReady)
7734
7927
  await waitForEntityReady(item, { timeout: readyTimeout });
7735
7928
  return item;
@@ -7737,26 +7930,46 @@ class Item {
7737
7930
  }
7738
7931
  catch (error) {
7739
7932
  timingLogger(`find ${modelName ?? '?'} ${id} returned undefined: ${error}`);
7933
+ held?.unload();
7740
7934
  return undefined;
7741
7935
  }
7742
7936
  }
7937
+ /**
7938
+ * Takes one more hold on a cached, running instance, released with `unload()`. False (and no
7939
+ * hold) when the instance isn't cached or was stopped.
7940
+ */
7941
+ static retain(instance) {
7942
+ const item = instance;
7943
+ return item.getService().getSnapshot().status === 'active' && this.cache.holdInstance(item);
7944
+ }
7945
+ /**
7946
+ * The items of a model (every model when `modelName` is omitted), newest first. Takes no cache
7947
+ * holds, as `find`: an item no one holds unloads after the grace period. With `hold: true` each
7948
+ * item comes with a hold the caller releases with `unload()`; when the call then throws (aborted,
7949
+ * an item not ready in `readyTimeout`), it keeps none of the holds it took.
7950
+ */
7743
7951
  static async all(modelName, deleted, options) {
7744
- const { waitForReady = false, readyTimeout = DEFAULT_READY_TIMEOUT_MS, includeEas = false, addressFilter, modelFileId, schemaName, signal, } = options ?? {};
7952
+ const { hold = false, waitForReady = false, readyTimeout = DEFAULT_READY_TIMEOUT_MS, includeEas = false, addressFilter, modelFileId, schemaName, signal, } = options ?? {};
7745
7953
  signal?.throwIfAborted();
7746
7954
  const itemsData = await getItemsData({ modelName, modelFileId, schemaName, deleted, includeEas, addressFilter });
7747
7955
  const itemInstances = [];
7748
- // Built without waiting; with waitForReady the items are then awaited together, below.
7749
- for (const itemData of itemsData) {
7956
+ try {
7957
+ // Built without waiting; with waitForReady the items are then awaited together, below.
7958
+ for (const itemData of itemsData) {
7959
+ signal?.throwIfAborted();
7960
+ itemInstances.push(await Item.create({ ...itemData, modelName }, { waitForReady: false, hold }));
7961
+ }
7962
+ if (waitForReady && itemInstances.length > 0) {
7963
+ await Promise.all(itemInstances.map((item) => waitForEntityReady(item, { timeout: readyTimeout })));
7964
+ }
7750
7965
  signal?.throwIfAborted();
7751
- itemInstances.push(await Item.create({
7752
- ...itemData,
7753
- modelName,
7754
- }, { waitForReady: false }));
7755
7966
  }
7756
- if (waitForReady && itemInstances.length > 0) {
7757
- await Promise.all(itemInstances.map((item) => waitForEntityReady(item, { timeout: readyTimeout })));
7967
+ catch (error) {
7968
+ if (hold)
7969
+ for (const item of itemInstances)
7970
+ item.unload();
7971
+ throw error;
7758
7972
  }
7759
- signal?.throwIfAborted();
7760
7973
  return orderBy(itemInstances, ['createdAt'], ['desc']);
7761
7974
  }
7762
7975
  /**
@@ -7769,7 +7982,7 @@ class Item {
7769
7982
  if (!appDb || Item.cache.size === 0) {
7770
7983
  return;
7771
7984
  }
7772
- const _mod_28 = await import('./index-D0V-mjCV.js');
7985
+ const _mod_28 = await import('./index-BjWk0x4-.js');
7773
7986
  const _ns_28 = _mod_28.s;
7774
7987
  const { metadata } = _ns_28;
7775
7988
  const { eq, and } = await import('drizzle-orm');
@@ -7881,11 +8094,11 @@ class Item {
7881
8094
  }
7882
8095
  /** Throws ItemCreateValidationError for unknown keys and values that break their property's rules. */
7883
8096
  static async assertValidCreateValues(props, propertyNames, dataTypeByPropertyName, skipKeys) {
7884
- const _mod_29 = await import('./errors-DLSoqSHG.js');
8097
+ const _mod_29 = await import('./errors-DpC9W4i3.js');
7885
8098
  const _ns_29 = _mod_29.a8;
7886
8099
  const { ItemCreateValidationError } = _ns_29;
7887
- const { getModelPropertyDefinitions, resolvePropertyKey } = await import('./property-BxUYznH0.js');
7888
- const { SchemaValidationService } = await import('./SchemaValidationService-CnmKyzR-.js');
8100
+ const { getModelPropertyDefinitions, resolvePropertyKey } = await import('./property-QjljUeb9.js');
8101
+ const { SchemaValidationService } = await import('./SchemaValidationService-C1xqJFxI.js');
7889
8102
  const validationService = new SchemaValidationService();
7890
8103
  const modelName = props.modelName;
7891
8104
  const known = new Set(propertyNames);
@@ -8239,7 +8452,7 @@ class Item {
8239
8452
  itemActor.send(event);
8240
8453
  };
8241
8454
  try {
8242
- const _mod_30 = await import('./index-D0V-mjCV.js');
8455
+ const _mod_30 = await import('./index-BjWk0x4-.js');
8243
8456
  const _ns_30 = _mod_30.s;
8244
8457
  const seedSchemaMod = _ns_30;
8245
8458
  const { seeds, metadata } = seedSchemaMod;
@@ -8253,8 +8466,8 @@ class Item {
8253
8466
  return;
8254
8467
  }
8255
8468
  // Query initial seed and version data
8256
- const _mod_31 = await import('./tabEvents-CaVmngqr.js');
8257
- const _ns_31 = _mod_31.bd;
8469
+ const _mod_31 = await import('./tabEvents-BHPY5I08.js');
8470
+ const _ns_31 = _mod_31.bg;
8258
8471
  const { findSeedRow } = _ns_31;
8259
8472
  const seed = await findSeedRow({ localId: seedLocalId, uid: seedUid }, db);
8260
8473
  if (!seed) {
@@ -8554,7 +8767,7 @@ class Item {
8554
8767
  return;
8555
8768
  }
8556
8769
  // Through the outbox (ADR 0019): after the item's pending edits, not before them
8557
- const { appendOutboxOpAndWait, startItemOutbox, throwItemWriteError } = await import('./index-CYGWPoOx.js');
8770
+ const { appendOutboxOpAndWait, startItemOutbox, throwItemWriteError } = await import('./index-BMHqJ4kN.js');
8558
8771
  startItemOutbox();
8559
8772
  await appendOutboxOpAndWait({
8560
8773
  seedLocalId: context.seedLocalId,
@@ -8581,5 +8794,5 @@ var Item$1 = /*#__PURE__*/Object.freeze({
8581
8794
  Item: Item
8582
8795
  });
8583
8796
 
8584
- export { createReactiveProxy as $, getCorrectId as A, isItemOwned as B, ClearNotSupportedError as C, isPublishedSeedRef as D, propertyKeyFromStoredName as E, currentPropertyRows as F, metadataPropertyGroupKeys as G, compareMetadataRowsLatestFirst as H, Item as I, readMetadataPropertiesById as J, isPublishedMetadataRow as K, getLatestPublishedVersionRow as L, isVersionRevoked as M, readModelMetadataProperties as N, OUTBOX_DEFER_MS as O, metadataPropertyNameForms as P, currentPropertyRow as Q, getLatestVersionRow as R, parseListPropertyValueFromStorage as S, applyContextUpdate as T, isInternalUpdate as U, evictionLog as V, holdChild as W, isEntityTornDown as X, sameEntity as Y, DEFAULT_READY_TIMEOUT_MS as Z, waitForEntityReady as _, appendOutboxOpAndWait as a, findSetConflict as a$, runEntityLoad as a0, evictEntities as a1, entityStatus as a2, releaseEntity as a3, destroyEntity as a4, EntityCache as a5, getGetAdditionalSyncAddresses as a6, modelPropertiesToObject as a7, listRelationEasPropertyName as a8, easPropertyNameForPublish as a9, getVersionData as aA, isLocalUnsealedDraft as aB, isSeedRowOwned as aC, localUnsealedDraftSql as aD, ownedPublisherSql as aE, ownedSeedsSql as aF, pickLatestMetadataRowPerProperty as aG, placeholderUidSql as aH, propertyMachine as aI, publisherInAddressListSql as aJ, publisherIsInOwnedSet as aK, setAdditionalSyncAddresses as aL, setGetPublisherForNewSeeds as aM, setPublishExecutor as aN, setRevokeExecutor as aO, setUploadExecutor as aP, getSeedPublisher as aQ, deleteStagedFile as aR, storageFileName as aS, STORAGE_SUBDIR as aT, resolveNewSeedFields as aU, lookupPropertySchemaUid as aV, stageStorageContent as aW, requireStagedFile as aX, createSeed as aY, createMetadata as aZ, storageValueRowOf as a_, metadataStorageName as aa, resolveMetadataPropertyId as ab, storageSeedTransactionId as ac, storageUploadPath as ad, matchMetadataProperty as ae, metadataRowsOfProperty as af, METADATA_LATEST_FIRST_ORDER_SQL as ag, getEasSchemaUidForModel as ah, isStorageSeedRef as ai, isActorStopped as aj, differsFromOriginals as ak, onEntityTeardown as al, getStorageTransactionIdForSeedUid as am, latestVersionOrder as an, otherVersionRowsWithUid as ao, mergeVersionRowInto as ap, findMetadataPropertyByName as aq, resolvePublisherFromSeedRow as ar, PUBLISH_NOT_CONFIGURED_MESSAGE as as, createNewItem as at, getArweaveUrlForTransaction as au, getGetPublisherForNewSeeds as av, getMetadataLatest as aw, getPublishExecutor as ax, getRevokeExecutor as ay, getUploadExecutor as az, waitForPendingOutboxOps as b, recordPropertyEdit as b0, currentPropertyRow$1 as b1, resolve as b2, conflicts as b3, propertySchemaUid as b4, Item$1 as b5, OUTBOX_MAX_ATTEMPTS as c, OUTBOX_PRUNE_AFTER_MS as d, OUTBOX_PRUNE_FAILED_AFTER_MS as e, OUTBOX_RETRY_DELAYS_MS as f, getOutboxOps as g, OutboxOpDeferredError as h, OutboxOpFailedError as i, OutboxOpRejectedError as j, appendOutboxOp as k, drainOutbox as l, markPropertyConflictsResolved as m, getItemConflicts as n, outboxOpResult as o, getPendingSetValue as p, getPropertyConflict as q, outboxOpValue as r, pruneOutbox as s, registerOutboxApplier as t, startOutbox as u, ItemProperty as v, waitForOutboxOp as w, ItemPropertySaveValidationError as x, OwnershipError as y, assertItemOwned as z };
8585
- //# sourceMappingURL=Item-Bf4kWKpH.js.map
8797
+ export { createReactiveProxy as $, getCorrectId as A, isItemOwned as B, ClearNotSupportedError as C, isPublishedSeedRef as D, propertyKeyFromStoredName as E, currentPropertyRows as F, metadataPropertyGroupKeys as G, compareMetadataRowsLatestFirst as H, Item as I, readMetadataPropertiesById as J, isPublishedMetadataRow as K, getLatestPublishedVersionRow as L, isVersionRevoked as M, readModelMetadataProperties as N, OUTBOX_DEFER_MS as O, metadataPropertyNameForms as P, currentPropertyRow as Q, getLatestVersionRow as R, parseListPropertyValueFromStorage as S, applyContextUpdate as T, isInternalUpdate as U, evictionLog as V, holdChild as W, isEntityTornDown as X, sameEntity as Y, DEFAULT_READY_TIMEOUT_MS as Z, waitForEntityReady as _, appendOutboxOpAndWait as a, createSeed as a$, runEntityLoad as a0, evictEntities as a1, entityStatus as a2, releaseEntity as a3, destroyEntity as a4, EntityCache as a5, getGetAdditionalSyncAddresses as a6, modelPropertiesToObject as a7, listRelationEasPropertyName as a8, easPropertyNameForPublish as a9, getPublishExecutor as aA, getRevokeExecutor as aB, getUploadExecutor as aC, getVersionData as aD, isLocalUnsealedDraft as aE, isSeedRowOwned as aF, localUnsealedDraftSql as aG, ownedPublisherSql as aH, ownedSeedsSql as aI, pickLatestMetadataRowPerProperty as aJ, placeholderUidSql as aK, propertyMachine as aL, publisherInAddressListSql as aM, publisherIsInOwnedSet as aN, setAdditionalSyncAddresses as aO, setGetPublisherForNewSeeds as aP, setPublishExecutor as aQ, setRevokeExecutor as aR, setUploadExecutor as aS, getSeedPublisher as aT, deleteStagedFile as aU, storageFileName as aV, STORAGE_SUBDIR as aW, resolveNewSeedFields as aX, lookupPropertySchemaUid as aY, stageStorageContent as aZ, requireStagedFile as a_, metadataStorageName as aa, resolveMetadataPropertyId as ab, storageSeedTransactionId as ac, storageUploadPath as ad, matchMetadataProperty as ae, metadataRowsOfProperty as af, METADATA_LATEST_FIRST_ORDER_SQL as ag, getEasSchemaUidForModel as ah, isStorageSeedRef as ai, isActorStopped as aj, differsFromOriginals as ak, onEntityTeardown as al, getStorageTransactionIdForSeedUid as am, latestVersionOrder as an, otherVersionRowsWithUid as ao, mergeVersionRowInto as ap, findMetadataPropertyByName as aq, storedValueKind as ar, resolveStorageDisplay as as, resolvePublisherFromSeedRow as at, EntityUnloadedError as au, PUBLISH_NOT_CONFIGURED_MESSAGE as av, createNewItem as aw, getArweaveUrlForTransaction as ax, getGetPublisherForNewSeeds as ay, getMetadataLatest as az, waitForPendingOutboxOps as b, createMetadata as b0, storageValueRowOf as b1, findSetConflict as b2, recordPropertyEdit as b3, setEntityUnloadGraceMs as b4, stopOutbox as b5, evictAllEntities as b6, currentPropertyRow$1 as b7, resolve as b8, conflicts as b9, propertySchemaUid as ba, Item$1 as bb, OUTBOX_MAX_ATTEMPTS as c, OUTBOX_PRUNE_AFTER_MS as d, OUTBOX_PRUNE_FAILED_AFTER_MS as e, OUTBOX_RETRY_DELAYS_MS as f, getOutboxOps as g, OutboxOpDeferredError as h, OutboxOpFailedError as i, OutboxOpRejectedError as j, appendOutboxOp as k, drainOutbox as l, markPropertyConflictsResolved as m, getItemConflicts as n, outboxOpResult as o, getPendingSetValue as p, getPropertyConflict as q, outboxOpValue as r, pruneOutbox as s, registerOutboxApplier as t, startOutbox as u, ItemProperty as v, waitForOutboxOp as w, ItemPropertySaveValidationError as x, OwnershipError as y, assertItemOwned as z };
8798
+ //# sourceMappingURL=Item-CXLcIHsi.js.map