@seedprotocol/sdk 0.7.2 → 0.7.3-next.654.g52217f6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/dist/{BasePathResolver-BdxCSIzn.js → BasePathResolver-CfSfMW5_.js} +7 -10
  2. package/dist/BasePathResolver-CfSfMW5_.js.map +1 -0
  3. package/dist/{ClientManager-ClCwwhwo.js → ClientManager-C-QXqUK9.js} +438 -153
  4. package/dist/ClientManager-C-QXqUK9.js.map +1 -0
  5. package/dist/{Item-B9Y4VuK1.js → Item-C7sUUu2B.js} +291 -105
  6. package/dist/Item-C7sUUu2B.js.map +1 -0
  7. package/dist/{ModelProperty-BMePcicQ.js → ModelProperty-DJxeOOrc.js} +28 -27
  8. package/dist/ModelProperty-DJxeOOrc.js.map +1 -0
  9. package/dist/{Schema-COsEXXaR.js → Schema-fXtvd-yL.js} +30 -30
  10. package/dist/{Schema-COsEXXaR.js.map → Schema-fXtvd-yL.js.map} +1 -1
  11. package/dist/{SchemaValidationService-DabGMzSE.js → SchemaValidationService-CvRS2HSO.js} +10 -9
  12. package/dist/{SchemaValidationService-DabGMzSE.js.map → SchemaValidationService-CvRS2HSO.js.map} +1 -1
  13. package/dist/{backfillMetadataPropertyIds-Ck6fumnm.js → backfillMetadataPropertyIds-SXW-8C64.js} +4 -4
  14. package/dist/{backfillMetadataPropertyIds-Ck6fumnm.js.map → backfillMetadataPropertyIds-SXW-8C64.js.map} +1 -1
  15. package/dist/cjs/{ModelProperty-BT6Un_MB.js → ModelProperty-DXZ39Wyv.js} +24 -23
  16. package/dist/cjs/{ModelProperty-BT6Un_MB.js.map → ModelProperty-DXZ39Wyv.js.map} +1 -1
  17. package/dist/cjs/{Schema-BXhXdUsA.js → Schema-DdP109QD.js} +26 -25
  18. package/dist/cjs/{Schema-BXhXdUsA.js.map → Schema-DdP109QD.js.map} +1 -1
  19. package/dist/cjs/{SchemaValidationService-CC18QDfc.js → SchemaValidationService-CSXxx7sQ.js} +5 -4
  20. package/dist/cjs/{SchemaValidationService-CC18QDfc.js.map → SchemaValidationService-CSXxx7sQ.js.map} +1 -1
  21. package/dist/cjs/{backfillMetadataPropertyIds-DEHC9ejq.js → backfillMetadataPropertyIds-CPYoaMl4.js} +6 -5
  22. package/dist/cjs/{backfillMetadataPropertyIds-DEHC9ejq.js.map → backfillMetadataPropertyIds-CPYoaMl4.js.map} +1 -1
  23. package/dist/cjs/{eas-C3CL0l7l.js → eas-B2YDQssV.js} +6 -5
  24. package/dist/cjs/{eas-C3CL0l7l.js.map → eas-B2YDQssV.js.map} +1 -1
  25. package/dist/cjs/{getItem-CrwWYCkj.js → getItem-DgnaQzbE.js} +5 -4
  26. package/dist/cjs/{getItem-CrwWYCkj.js.map → getItem-DgnaQzbE.js.map} +1 -1
  27. package/dist/cjs/{getPublishPayload-DRJh7WR0.js → getPublishPayload-CqlqRdot.js} +12 -11
  28. package/dist/cjs/{getPublishPayload-DRJh7WR0.js.map → getPublishPayload-CqlqRdot.js.map} +1 -1
  29. package/dist/cjs/getPublishUploads-DsXY9S4U.js +872 -0
  30. package/dist/cjs/getPublishUploads-DsXY9S4U.js.map +1 -0
  31. package/dist/cjs/{index-BA1RIYFG.js → index-BHaWOwNF.js} +6 -5
  32. package/dist/cjs/index-BHaWOwNF.js.map +1 -0
  33. package/dist/cjs/{index-Dls7aMjr.js → index-C4XlgCJ4.js} +1200 -528
  34. package/dist/cjs/index-C4XlgCJ4.js.map +1 -0
  35. package/dist/cjs/{property-ZerTWizX.js → property-fa0iju0J.js} +8 -7
  36. package/dist/cjs/{property-ZerTWizX.js.map → property-fa0iju0J.js.map} +1 -1
  37. package/dist/cjs/{publishDraftGraph-CPOAcQFf.js → publishDraftGraph-3ASwAlD7.js} +4 -4
  38. package/dist/cjs/{publishDraftGraph-CPOAcQFf.js.map → publishDraftGraph-3ASwAlD7.js.map} +1 -1
  39. package/dist/cjs/{resetAmbiguousLegacyItemData-adDl4LcT.js → resetAmbiguousLegacyItemData-Bu_MBBYt.js} +5 -4
  40. package/dist/cjs/{resetAmbiguousLegacyItemData-adDl4LcT.js.map → resetAmbiguousLegacyItemData-Bu_MBBYt.js.map} +1 -1
  41. package/dist/cjs/{resolveModelForSyncedSeed-DoNThPdL.js → resolveModelForSyncedSeed-BANIiuFU.js} +2 -2
  42. package/dist/cjs/{resolveModelForSyncedSeed-DoNThPdL.js.map → resolveModelForSyncedSeed-BANIiuFU.js.map} +1 -1
  43. package/dist/cjs/{syncDbWithEas-CYfPkus9.js → syncDbWithEas-CrmxxmUW.js} +10 -9
  44. package/dist/cjs/{syncDbWithEas-CYfPkus9.js.map → syncDbWithEas-CrmxxmUW.js.map} +1 -1
  45. package/dist/{configurePlatform-xU3Hsno3.js → configurePlatform-BRw2j0ZN.js} +7 -4
  46. package/dist/{configurePlatform-xU3Hsno3.js.map → configurePlatform-BRw2j0ZN.js.map} +1 -1
  47. package/dist/{db-W1g29qsM.js → db-D9K_f5cF.js} +14 -14
  48. package/dist/{db-W1g29qsM.js.map → db-D9K_f5cF.js.map} +1 -1
  49. package/dist/{eas-CSwV6MvB.js → eas-DHxfswCt.js} +8 -5
  50. package/dist/eas-DHxfswCt.js.map +1 -0
  51. package/dist/{getItem-BYQeM3DY.js → getItem-d6N_aM6S.js} +8 -5
  52. package/dist/{getItem-BYQeM3DY.js.map → getItem-d6N_aM6S.js.map} +1 -1
  53. package/dist/{getPublishPayload-D5CQZd-y.js → getPublishPayload-BHrxVtzY.js} +16 -16
  54. package/dist/{getPublishPayload-D5CQZd-y.js.map → getPublishPayload-BHrxVtzY.js.map} +1 -1
  55. package/dist/getPublishUploads-BEqRiKIS.js +657 -0
  56. package/dist/getPublishUploads-BEqRiKIS.js.map +1 -0
  57. package/dist/{index-Bev-hZF-.js → index-CiMEoGu3.js} +12 -11
  58. package/dist/index-CiMEoGu3.js.map +1 -0
  59. package/dist/{index-CSOQFAOn.js → index-DglvthOk.js} +2 -2
  60. package/dist/index-DglvthOk.js.map +1 -0
  61. package/dist/{index-DRXC5Mra.js → index-s15q14rm.js} +29 -29
  62. package/dist/{index-DRXC5Mra.js.map → index-s15q14rm.js.map} +1 -1
  63. package/dist/{index.browser-DO20vYuP.js → index.browser-Cm06tP4X.js} +553 -165
  64. package/dist/index.browser-Cm06tP4X.js.map +1 -0
  65. package/dist/{index.node-C4iyOhdo.js → index.node-C30dmFgn.js} +5 -5
  66. package/dist/{index.node-C4iyOhdo.js.map → index.node-C30dmFgn.js.map} +1 -1
  67. package/dist/main.cjs +4 -3
  68. package/dist/main.cjs.map +1 -1
  69. package/dist/main.js +32 -44
  70. package/dist/main.js.map +1 -1
  71. package/dist/mimeTypes-DHAHC4eZ.js +204 -0
  72. package/dist/mimeTypes-DHAHC4eZ.js.map +1 -0
  73. package/dist/node.js +13 -12
  74. package/dist/node.js.map +1 -1
  75. package/dist/platform.browser.js +9 -7
  76. package/dist/platform.browser.js.map +1 -1
  77. package/dist/platform.node.js +3 -3
  78. package/dist/{property-BT1zDSkd.js → property-DhmmYAvQ.js} +12 -9
  79. package/dist/property-DhmmYAvQ.js.map +1 -0
  80. package/dist/{publishDraftGraph-Bcfrdj7-.js → publishDraftGraph-yYP74WRt.js} +8 -8
  81. package/dist/{publishDraftGraph-Bcfrdj7-.js.map → publishDraftGraph-yYP74WRt.js.map} +1 -1
  82. package/dist/{resetAmbiguousLegacyItemData-Ci6PM_vC.js → resetAmbiguousLegacyItemData-Bk0QyDW8.js} +2 -2
  83. package/dist/{resetAmbiguousLegacyItemData-Ci6PM_vC.js.map → resetAmbiguousLegacyItemData-Bk0QyDW8.js.map} +1 -1
  84. package/dist/{resolveModelForSyncedSeed-CLlumTBq.js → resolveModelForSyncedSeed-8cAzvUFd.js} +2 -2
  85. package/dist/{resolveModelForSyncedSeed-CLlumTBq.js.map → resolveModelForSyncedSeed-8cAzvUFd.js.map} +1 -1
  86. package/dist/src/Item/Item.d.ts +1 -1
  87. package/dist/src/Item/Item.d.ts.map +1 -1
  88. package/dist/src/ItemProperty/service/actors/saveValueToDb/saveItemStorage.d.ts.map +1 -1
  89. package/dist/src/browser/helpers/FileManager.d.ts +4 -1
  90. package/dist/src/browser/helpers/FileManager.d.ts.map +1 -1
  91. package/dist/src/browser/helpers/tolerantWebAccess.d.ts +79 -4
  92. package/dist/src/browser/helpers/tolerantWebAccess.d.ts.map +1 -1
  93. package/dist/src/browser/workers/FileDownloader.d.ts +19 -4
  94. package/dist/src/browser/workers/FileDownloader.d.ts.map +1 -1
  95. package/dist/src/browser/workers/filesDownload.d.ts.map +1 -1
  96. package/dist/src/client/clientManagerMachine.d.ts.map +1 -1
  97. package/dist/src/db/migrateLegacyItemStorageRows.d.ts +57 -0
  98. package/dist/src/db/migrateLegacyItemStorageRows.d.ts.map +1 -0
  99. package/dist/src/db/read/getCompositeChildPaths.d.ts +13 -0
  100. package/dist/src/db/read/getCompositeChildPaths.d.ts.map +1 -0
  101. package/dist/src/db/read/getItems.d.ts.map +1 -1
  102. package/dist/src/db/read/getPublishUploads.d.ts +32 -3
  103. package/dist/src/db/read/getPublishUploads.d.ts.map +1 -1
  104. package/dist/src/db/read/summarizePublishWork.d.ts.map +1 -1
  105. package/dist/src/db/write/convertVerbatimItemStorageRow.d.ts +44 -0
  106. package/dist/src/db/write/convertVerbatimItemStorageRow.d.ts.map +1 -0
  107. package/dist/src/db/write/createNewItem.d.ts.map +1 -1
  108. package/dist/src/events/files/download.d.ts.map +1 -1
  109. package/dist/src/helpers/FileManager/BaseFileManager.d.ts +3 -3
  110. package/dist/src/helpers/FileManager/BaseFileManager.d.ts.map +1 -1
  111. package/dist/src/helpers/FileManager/IFileManager.d.ts +25 -1
  112. package/dist/src/helpers/FileManager/IFileManager.d.ts.map +1 -1
  113. package/dist/src/helpers/arweaveContentTags.d.ts +33 -0
  114. package/dist/src/helpers/arweaveContentTags.d.ts.map +1 -0
  115. package/dist/src/helpers/compositeUpload.d.ts +28 -0
  116. package/dist/src/helpers/compositeUpload.d.ts.map +1 -0
  117. package/dist/src/helpers/itemStorageFile.d.ts +57 -0
  118. package/dist/src/helpers/itemStorageFile.d.ts.map +1 -0
  119. package/dist/src/helpers/mapWithConcurrency.d.ts +7 -0
  120. package/dist/src/helpers/mapWithConcurrency.d.ts.map +1 -0
  121. package/dist/src/helpers/mimeTypes.d.ts +43 -0
  122. package/dist/src/helpers/mimeTypes.d.ts.map +1 -0
  123. package/dist/src/helpers/ownership.d.ts +19 -3
  124. package/dist/src/helpers/ownership.d.ts.map +1 -1
  125. package/dist/src/helpers/storageDir.d.ts +16 -0
  126. package/dist/src/helpers/storageDir.d.ts.map +1 -0
  127. package/dist/src/helpers/tabCoordinator.d.ts +5 -1
  128. package/dist/src/helpers/tabCoordinator.d.ts.map +1 -1
  129. package/dist/src/helpers/tabEvents.d.ts +23 -2
  130. package/dist/src/helpers/tabEvents.d.ts.map +1 -1
  131. package/dist/src/helpers/tabLocks.d.ts +11 -1
  132. package/dist/src/helpers/tabLocks.d.ts.map +1 -1
  133. package/dist/src/index.d.ts +6 -4
  134. package/dist/src/index.d.ts.map +1 -1
  135. package/dist/src/types/fileManager.d.ts +3 -14
  136. package/dist/src/types/fileManager.d.ts.map +1 -1
  137. package/dist/src/types/publish.d.ts +14 -0
  138. package/dist/src/types/publish.d.ts.map +1 -1
  139. package/dist/{syncDbWithEas-BQsXjGhe.js → syncDbWithEas--HUA9WNb.js} +15 -14
  140. package/dist/syncDbWithEas--HUA9WNb.js.map +1 -0
  141. package/dist/{tabEvents-C9qUKx_z.js → tabEvents-DguZpCCv.js} +338 -60
  142. package/dist/tabEvents-DguZpCCv.js.map +1 -0
  143. package/dist/tolerantWebAccess-BZYWt09Y.js +551 -0
  144. package/dist/tolerantWebAccess-BZYWt09Y.js.map +1 -0
  145. package/dist/{updateSeedRevokedAt-D6q0h7pj.js → updateSeedRevokedAt-D_EG-q3b.js} +3 -3
  146. package/dist/{updateSeedRevokedAt-D6q0h7pj.js.map → updateSeedRevokedAt-D_EG-q3b.js.map} +1 -1
  147. package/package.json +5 -5
  148. package/dist/BasePathResolver-BdxCSIzn.js.map +0 -1
  149. package/dist/ClientManager-ClCwwhwo.js.map +0 -1
  150. package/dist/Item-B9Y4VuK1.js.map +0 -1
  151. package/dist/ModelProperty-BMePcicQ.js.map +0 -1
  152. package/dist/cjs/getPublishUploads-Bh22D3zJ.js +0 -495
  153. package/dist/cjs/getPublishUploads-Bh22D3zJ.js.map +0 -1
  154. package/dist/cjs/index-BA1RIYFG.js.map +0 -1
  155. package/dist/cjs/index-Dls7aMjr.js.map +0 -1
  156. package/dist/eas-CSwV6MvB.js.map +0 -1
  157. package/dist/getPublishUploads-BGpDsrBp.js +0 -484
  158. package/dist/getPublishUploads-BGpDsrBp.js.map +0 -1
  159. package/dist/index-Bev-hZF-.js.map +0 -1
  160. package/dist/index-CSOQFAOn.js.map +0 -1
  161. package/dist/index.browser-DO20vYuP.js.map +0 -1
  162. package/dist/property-BT1zDSkd.js.map +0 -1
  163. package/dist/syncDbWithEas-BQsXjGhe.js.map +0 -1
  164. package/dist/tabEvents-C9qUKx_z.js.map +0 -1
  165. package/dist/tolerantWebAccess-B-9bwxbw.js +0 -160
  166. package/dist/tolerantWebAccess-B-9bwxbw.js.map +0 -1
@@ -1,14 +1,14 @@
1
1
  import { waitFor, fromCallback, setup, assign, stateIn, createActor, isMachineSnapshot } from 'xstate';
2
- import { a as BaseDb, v as versions, m as metadata, r as seeds, s as schemas, j as models, g as modelSchemas, Z as ZERO_BYTES32, I as INTERNAL_PROPERTY_NAMES, B as BaseFileManager, D as ImageSize, p as properties, x as INTERNAL_DATA_TYPES, i as modelUids, C as INTERNAL_STORAGE_MODEL_FILE_IDS, P as PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP } from './BasePathResolver-BdxCSIzn.js';
2
+ import { B as BaseDb, v as versions, m as metadata, q as seeds, s as schemas, i as models, f as modelSchemas, Z as ZERO_BYTES32, I as INTERNAL_PROPERTY_NAMES, t as BaseFileManager, D as ImageSize, p as properties, x as INTERNAL_DATA_TYPES, g as modelUids, C as INTERNAL_STORAGE_MODEL_FILE_IDS, P as PROPERTY_NAMES_EXEMPT_FROM_ID_SUFFIX_STRIP } from './BasePathResolver-CfSfMW5_.js';
3
3
  import { or, isNull, eq, max, count, and, getTableColumns, sql, desc, inArray, isNotNull, gt } from 'drizzle-orm';
4
4
  import pluralize from 'pluralize';
5
- import { n as normalizeDataType, W as getOwnedAddressesFromDb, E as normalizeAddressList, u as normalizeHexAddress, z as getAddressesForItemsFilter, k as isDataType, s as normalizePublisher, M as ModelPropertyDataTypes, r as resolveItemModelFileId, X as getPropertyIdForSchemaFileId, o as getPropertyIdForModelAndName, l as normalizePropertyRecordSchema, m as eventEmitter } from './db-W1g29qsM.js';
5
+ import { n as normalizeDataType, W as getOwnedAddressesFromDb, E as normalizeAddressList, u as normalizeHexAddress, z as getAddressesForItemsFilter, k as isDataType, s as normalizePublisher, M as ModelPropertyDataTypes, r as resolveItemModelFileId, X as getPropertyIdForSchemaFileId, o as getPropertyIdForModelAndName, l as normalizePropertyRecordSchema, m as eventEmitter } from './db-D9K_f5cF.js';
6
6
  import debug from 'debug';
7
7
  import { BehaviorSubject } from 'rxjs';
8
8
  import { startCase, upperFirst, camelCase, orderBy } from 'lodash-es';
9
9
  import { toSnakeCase } from 'drizzle-orm/casing';
10
10
  import { isValidEasAttestationUid, isPlaceholderUid, BaseQueryClient, BaseEasClient, GET_SCHEMAS, getEasSchemaUidForSchemaDefinition, getSchemaUidForModelFromCache, cachedSchemaLookup, setSchemaUidForModel, getEasSchemaUidForExactDefinition } from '@seedprotocol/eas';
11
- import { t as toSnakeCase$1, H as getStorageTransactionIdForSeedUid, I as convertTxIdToImage, h as ensureImageLocal, J as downloadTransactionIdWithDedupe, b as generateId, K as getDataTypeFromString, M as getMimeType, N as notifyFileSaved, g as getCorrectId, a as isStorageSeedRef } from './tabEvents-C9qUKx_z.js';
11
+ import { t as toSnakeCase$1, Q as getStorageTransactionIdForSeedUid, R as convertTxIdToImage, q as ensureImageLocal, S as downloadTransactionIdWithDedupe, j as generateId, U as getDataTypeFromString, V as getMimeType, W as notifyFileSaved, X as withTabLock, a as getItemStorageSubdir, c as getItemStorageLocalFileName, e as getCorrectId, f as isStorageSeedRef } from './tabEvents-DguZpCCv.js';
12
12
  import { fetchArweaveRawTextAcrossGateways } from '@seedprotocol/arweave';
13
13
  import { modelPropertiesToObject } from './model-DGMe-TTm.js';
14
14
 
@@ -708,7 +708,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
708
708
  const itemPropertyMod = await Promise.resolve().then(function () { return ItemProperty$1; });
709
709
  const { ItemProperty } = itemPropertyMod;
710
710
  const { modelPropertiesToObject } = await import('./model-DGMe-TTm.js');
711
- const _mod_0 = await import('./index-DRXC5Mra.js');
711
+ const _mod_0 = await import('./index-s15q14rm.js');
712
712
  const _ns_0 = _mod_0.f;
713
713
  const { Model } = _ns_0;
714
714
  // Resolve Model and build property schemas (use getByNameAsync for models not yet in cache)
@@ -726,7 +726,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
726
726
  const schemaNameToTry = schemaName ?? model?.schemaName;
727
727
  if (schemaNameToTry) {
728
728
  try {
729
- const _mod_1 = await import('./Schema-COsEXXaR.js');
729
+ const _mod_1 = await import('./Schema-fXtvd-yL.js');
730
730
  const _ns_1 = _mod_1.b;
731
731
  const { Schema } = _ns_1;
732
732
  const schemaInstance = Schema.create(schemaNameToTry, { waitForReady: false });
@@ -742,8 +742,8 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
742
742
  }
743
743
  if (Object.keys(propertySchemas).length === 0) {
744
744
  try {
745
- const _mod_2 = await import('./ClientManager-ClCwwhwo.js');
746
- const _ns_2 = _mod_2.G;
745
+ const _mod_2 = await import('./ClientManager-C-QXqUK9.js');
746
+ const _ns_2 = _mod_2.I;
747
747
  const { loadAllSchemasFromDb } = _ns_2;
748
748
  const allSchemas = await loadAllSchemasFromDb();
749
749
  for (const { schema: schemaFile } of allSchemas) {
@@ -763,10 +763,10 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
763
763
  }
764
764
  if (Object.keys(propertySchemas).length === 0) {
765
765
  try {
766
- const _mod_3 = await import('./ClientManager-ClCwwhwo.js');
767
- const _ns_3 = _mod_3.G;
766
+ const _mod_3 = await import('./ClientManager-C-QXqUK9.js');
767
+ const _ns_3 = _mod_3.I;
768
768
  const { listCompleteSchemaFiles } = _ns_3;
769
- const _mod_4 = await import('./BasePathResolver-BdxCSIzn.js');
769
+ const _mod_4 = await import('./BasePathResolver-CfSfMW5_.js');
770
770
  const _ns_4 = _mod_4.O;
771
771
  const { BaseFileManager } = _ns_4;
772
772
  const schemaFiles = await listCompleteSchemaFiles();
@@ -787,7 +787,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
787
787
  }
788
788
  }
789
789
  if (Object.keys(propertySchemas).length === 0) {
790
- const schemaMod = await import('./index-Bev-hZF-.js');
790
+ const schemaMod = await import('./index-CiMEoGu3.js');
791
791
  const { ModelPropertyDataTypes } = schemaMod;
792
792
  const KNOWN_MODEL_FALLBACKS = {
793
793
  Post: {
@@ -804,7 +804,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
804
804
  }
805
805
  }
806
806
  // Fallbacks above may return schema-file shape ({ type, model, items }); normalize to dataType/ref/refValueType.
807
- const { normalizePropertyRecordSchema } = await import('./property-BT1zDSkd.js');
807
+ const { normalizePropertyRecordSchema } = await import('./property-DhmmYAvQ.js');
808
808
  propertySchemas = Object.fromEntries(Object.entries(propertySchemas).map(([name, def]) => [name, normalizePropertyRecordSchema(def)]));
809
809
  // Collapse rows that map to the same instance key (e.g. authorIdentityIds + authors -> authors).
810
810
  // ItemProperty.create cache does not sync propertyValue on hit; processing order would otherwise
@@ -837,7 +837,7 @@ const createItemPropertyInstances = async (metadataRows, seedLocalId, seedUid, m
837
837
  // Infer propertyRecordSchema from metadata when schema is missing (enables persistence)
838
838
  let propSchema = propertySchemas[propertyName];
839
839
  if (!propSchema && isRefTypeFromMeta) {
840
- const schemaMod = await import('./index-Bev-hZF-.js');
840
+ const schemaMod = await import('./index-CiMEoGu3.js');
841
841
  const { ModelPropertyDataTypes } = schemaMod;
842
842
  propSchema = {
843
843
  dataType: refSeedType === 'html' ? ModelPropertyDataTypes.Html
@@ -1104,9 +1104,9 @@ const runPublish = fromCallback(({ sendBack, input: { context } }) => {
1104
1104
  sendBack({ type: 'publishError', error: new Error(`Item not found for seedLocalId: ${seedLocalId}`) });
1105
1105
  return;
1106
1106
  }
1107
- const getPublishUploadsMod = await import('./getPublishUploads-BGpDsrBp.js');
1107
+ const getPublishUploadsMod = await import('./getPublishUploads-BEqRiKIS.js');
1108
1108
  const { getPublishUploads } = getPublishUploadsMod;
1109
- const _mod_5 = await import('./getPublishPayload-D5CQZd-y.js');
1109
+ const _mod_5 = await import('./getPublishPayload-BHrxVtzY.js');
1110
1110
  const _ns_5 = _mod_5.g;
1111
1111
  const getPublishPayloadMod = _ns_5;
1112
1112
  const { getPublishPayload } = getPublishPayloadMod;
@@ -1731,8 +1731,9 @@ function isSeedRowOwned(row, ownedAddresses) {
1731
1731
  return publisherIsInOwnedSet(publisher, ownedAddresses);
1732
1732
  }
1733
1733
  /**
1734
- * SQL for `addressFilter: 'owned' | 'watched'`. Empty list → no rows (`1=0`).
1735
- * Compares `lower(publisher)` so checksummed rows match persisted lowercase owned.
1734
+ * SQL for an address list on `publisher`. Empty list → no rows (`1=0`).
1735
+ * Compares `lower(publisher)` so checksummed rows match persisted lowercase addresses.
1736
+ * Used for `addressFilter: 'watched'`; `'owned'` uses {@link ownedSeedsSql}.
1736
1737
  */
1737
1738
  function publisherInAddressListSql(column, addresses) {
1738
1739
  const normalized = normalizeAddressList(addresses);
@@ -1741,10 +1742,37 @@ function publisherInAddressListSql(column, addresses) {
1741
1742
  }
1742
1743
  return inArray(sql `lower(${column})`, normalized);
1743
1744
  }
1744
- /** Owned-list SQL on `seeds.publisher`. */
1745
+ /**
1746
+ * @deprecated Matches `seeds.publisher` only. Use {@link ownedSeedsSql}, which agrees
1747
+ * with {@link isSeedRowOwned} (empty owned → local unsealed drafts; attester fallback).
1748
+ */
1745
1749
  function ownedPublisherSql(ownedAddresses) {
1746
1750
  return publisherInAddressListSql(seeds.publisher, ownedAddresses);
1747
1751
  }
1752
+ /** SQL form of {@link isPlaceholderUid}: null, `''`, `'NULL'`, or zero bytes32 (trimmed, any case). */
1753
+ function placeholderUidSql(column) {
1754
+ return or(isNull(column), eq(column, 'NULL'), sql `trim(${column}) = ''`, sql `lower(trim(${column})) = ${ZERO_BYTES32.toLowerCase()}`);
1755
+ }
1756
+ const isBlankSql = (column) => or(isNull(column), eq(column, ''));
1757
+ /** SQL form of {@link isLocalUnsealedDraft} on `seeds`. */
1758
+ function localUnsealedDraftSql() {
1759
+ return and(isBlankSql(seeds.publisher), placeholderUidSql(seeds.uid), isBlankSql(seeds.attestationRaw));
1760
+ }
1761
+ /**
1762
+ * SQL for `addressFilter: 'owned'`: a row passes exactly when {@link isSeedRowOwned} is true.
1763
+ * - Empty owned → local unsealed drafts (pre-connect authoring), not every row.
1764
+ * - Owned set → `lower(trim(publisher))` in the set, or, when publisher is blank, the
1765
+ * `attestationRaw.attester` ({@link resolvePublisherFromSeedRow}). `json_valid` guards
1766
+ * `json_extract`, which throws on malformed JSON.
1767
+ */
1768
+ function ownedSeedsSql(ownedAddresses) {
1769
+ const normalized = normalizeAddressList(ownedAddresses);
1770
+ if (normalized.length === 0) {
1771
+ return localUnsealedDraftSql();
1772
+ }
1773
+ const attester = sql `CASE WHEN json_valid(${seeds.attestationRaw}) THEN lower(trim(json_extract(${seeds.attestationRaw}, '$.attester'))) END`;
1774
+ return or(inArray(sql `lower(trim(${seeds.publisher}))`, normalized), and(isBlankSql(seeds.publisher), inArray(attester, normalized)));
1775
+ }
1748
1776
  /**
1749
1777
  * Checks if the current user owns the item (publisher is in persisted owned addresses).
1750
1778
  *
@@ -1781,7 +1809,10 @@ var ownership = /*#__PURE__*/Object.freeze({
1781
1809
  isItemOwned: isItemOwned,
1782
1810
  isLocalUnsealedDraft: isLocalUnsealedDraft,
1783
1811
  isSeedRowOwned: isSeedRowOwned,
1812
+ localUnsealedDraftSql: localUnsealedDraftSql,
1784
1813
  ownedPublisherSql: ownedPublisherSql,
1814
+ ownedSeedsSql: ownedSeedsSql,
1815
+ placeholderUidSql: placeholderUidSql,
1785
1816
  publisherInAddressListSql: publisherInAddressListSql,
1786
1817
  publisherIsInOwnedSet: publisherIsInOwnedSet,
1787
1818
  resolvePublisherFromSeedRow: resolvePublisherFromSeedRow
@@ -1801,13 +1832,13 @@ const getItemsData = async ({ modelName, modelFileId, schemaName, deleted, inclu
1801
1832
  const appDb = BaseDb.getAppDb();
1802
1833
  const conditions = [];
1803
1834
  if (!includeEas) {
1804
- conditions.push(or(isNull(seeds.uid), eq(seeds.uid, ''), eq(seeds.uid, 'NULL'), eq(seeds.uid, ZERO_BYTES32)));
1835
+ conditions.push(placeholderUidSql(seeds.uid));
1805
1836
  }
1806
1837
  if (modelName) {
1807
1838
  conditions.push(eq(seeds.type, toSnakeCase(modelName)));
1808
1839
  }
1809
1840
  if (!modelFileId && schemaName && modelName) {
1810
- const _mod_6 = await import('./db-W1g29qsM.js');
1841
+ const _mod_6 = await import('./db-D9K_f5cF.js');
1811
1842
  const _ns_6 = _mod_6.Y;
1812
1843
  const { resolveModelRecord } = _ns_6;
1813
1844
  modelFileId = (await resolveModelRecord(modelName, { schemaName }))?.schemaFileId ?? undefined;
@@ -1819,7 +1850,7 @@ const getItemsData = async ({ modelName, modelFileId, schemaName, deleted, inclu
1819
1850
  }
1820
1851
  if (addressFilter === 'owned') {
1821
1852
  const ownedAddresses = await getAddressesForItemsFilter('owned');
1822
- conditions.push(publisherInAddressListSql(seeds.publisher, ownedAddresses));
1853
+ conditions.push(ownedSeedsSql(ownedAddresses));
1823
1854
  }
1824
1855
  else if (addressFilter === 'watched') {
1825
1856
  const watchedAddresses = await getAddressesForItemsFilter('watched');
@@ -2090,7 +2121,7 @@ const resolveRelatedValue = fromCallback(({ sendBack, input: { context } }) => {
2090
2121
  const { isRelation, propertyValue, propertyName, seedUid, propertyRecordSchema, populatedFromDb, schemaUid, } = context;
2091
2122
  const _resolveRelatedValue = async () => {
2092
2123
  // Use dynamic import to break circular dependency
2093
- const schemaMod = await import('./index-Bev-hZF-.js');
2124
+ const schemaMod = await import('./index-CiMEoGu3.js');
2094
2125
  const { ModelPropertyDataTypes } = schemaMod;
2095
2126
  if (!propertyValue || !isRelation || populatedFromDb) {
2096
2127
  return;
@@ -2525,8 +2556,8 @@ async function readHtmlBodyFromChildStorageArweave(seedLocalId) {
2525
2556
  /* offline / bad tx id */
2526
2557
  }
2527
2558
  try {
2528
- const _mod_7 = await import('./tabEvents-C9qUKx_z.js');
2529
- const _ns_7 = _mod_7.O;
2559
+ const _mod_7 = await import('./tabEvents-DguZpCCv.js');
2560
+ const _ns_7 = _mod_7.Y;
2530
2561
  const { downloadTransactionIdWithDedupe } = _ns_7;
2531
2562
  await downloadTransactionIdWithDedupe(txId);
2532
2563
  const retryFp = BaseFileManager.getFilesPath('html', `${seedLocalId}.html`);
@@ -2586,7 +2617,7 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
2586
2617
  // to use dynamically imported ModelPropertyDataTypes
2587
2618
  const _hydrateFromDb = async () => {
2588
2619
  // Use dynamic import to break circular dependency
2589
- const schemaMod = await import('./index-Bev-hZF-.js');
2620
+ const schemaMod = await import('./index-CiMEoGu3.js');
2590
2621
  const { ModelPropertyDataTypes } = schemaMod;
2591
2622
  const appDb = BaseDb.getAppDb();
2592
2623
  const whereClauses = [];
@@ -2865,11 +2896,11 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
2865
2896
  const modelNameForNew = context.modelName;
2866
2897
  if (modelNameForNew) {
2867
2898
  try {
2868
- const _mod_8 = await import('./index-DRXC5Mra.js');
2899
+ const _mod_8 = await import('./index-s15q14rm.js');
2869
2900
  const _ns_8 = _mod_8.f;
2870
2901
  const { Model } = _ns_8;
2871
2902
  const { modelPropertiesToObject } = await import('./model-DGMe-TTm.js');
2872
- const _mod_9 = await import('./db-W1g29qsM.js');
2903
+ const _mod_9 = await import('./db-D9K_f5cF.js');
2873
2904
  const _ns_9 = _mod_9.Y;
2874
2905
  const { resolveItemModelFileId } = _ns_9;
2875
2906
  const normalizedModelName = upperFirst(camelCase(modelNameForNew));
@@ -2923,7 +2954,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
2923
2954
  // It ends up in the context below, and later lookups by name (Model.getByName) can't match it.
2924
2955
  const modelName = context.modelName || (metadataRecord.modelType ? upperFirst(camelCase(metadataRecord.modelType)) : undefined);
2925
2956
  // Model names are only unique per schema: pin lookups to the item's own model row.
2926
- const _mod_10 = await import('./db-W1g29qsM.js');
2957
+ const _mod_10 = await import('./db-D9K_f5cF.js');
2927
2958
  const _ns_10 = _mod_10.Y;
2928
2959
  const { resolveItemModelFileId, resolveModelRecord } = _ns_10;
2929
2960
  const modelFileId = await resolveItemModelFileId({
@@ -2969,16 +3000,16 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
2969
3000
  };
2970
3001
  // Merge with schema from file/DB to get validation rules (enum, pattern, etc.) - properties table doesn't store these
2971
3002
  try {
2972
- const { getPropertySchema } = await import('./property-BT1zDSkd.js');
3003
+ const { getPropertySchema } = await import('./property-DhmmYAvQ.js');
2973
3004
  let schemaFromFile = await getPropertySchema(normalizedModelName, propertyName, {
2974
3005
  modelFileId: modelRecord?.schemaFileId ?? modelFileId,
2975
3006
  });
2976
3007
  if (!schemaFromFile?.validation) {
2977
3008
  // Fallback: get validation from schemaData in database (Schema context may not be loaded yet)
2978
- const _mod_11 = await import('./BasePathResolver-BdxCSIzn.js');
3009
+ const _mod_11 = await import('./BasePathResolver-CfSfMW5_.js');
2979
3010
  const _ns_11 = _mod_11.Q;
2980
3011
  const { schemas: schemasTable } = _ns_11;
2981
- const _mod_12 = await import('./BasePathResolver-BdxCSIzn.js');
3012
+ const _mod_12 = await import('./BasePathResolver-CfSfMW5_.js');
2982
3013
  const _ns_12 = _mod_12.R;
2983
3014
  const { modelSchemas } = _ns_12;
2984
3015
  const modelSchemaRows = await db
@@ -3019,7 +3050,7 @@ const loadOrCreateProperty = fromCallback(({ sendBack, input: { context } }) =>
3019
3050
  }
3020
3051
  if (!propertyRecordSchema && modelName) {
3021
3052
  try {
3022
- const _mod_13 = await import('./index-DRXC5Mra.js');
3053
+ const _mod_13 = await import('./index-s15q14rm.js');
3023
3054
  const _ns_13 = _mod_13.f;
3024
3055
  const { Model } = _ns_13;
3025
3056
  const { modelPropertiesToObject } = await import('./model-DGMe-TTm.js');
@@ -3396,9 +3427,9 @@ const analyzeInput = fromCallback(({ sendBack, input: { context, event } }) => {
3396
3427
  }
3397
3428
  const _analyzeInput = async () => {
3398
3429
  // Use dynamic import to break circular dependency
3399
- const schemaMod = await import('./index-Bev-hZF-.js');
3430
+ const schemaMod = await import('./index-CiMEoGu3.js');
3400
3431
  const { ModelPropertyDataTypes } = schemaMod;
3401
- const { SchemaValidationService } = await import('./SchemaValidationService-DabGMzSE.js');
3432
+ const { SchemaValidationService } = await import('./SchemaValidationService-CvRS2HSO.js');
3402
3433
  let propertyName = propertyNameRaw;
3403
3434
  if (!propertyName) {
3404
3435
  throw new Error('propertyName is required');
@@ -3688,7 +3719,7 @@ const createMetadata = async (metadataValues, propertyRecordSchema, options) =>
3688
3719
  propertyRecordSchema?.validation &&
3689
3720
  metadataValues.propertyValue != null &&
3690
3721
  metadataValues.propertyValue !== '') {
3691
- const { SchemaValidationService } = await import('./SchemaValidationService-DabGMzSE.js');
3722
+ const { SchemaValidationService } = await import('./SchemaValidationService-CvRS2HSO.js');
3692
3723
  const validationService = new SchemaValidationService();
3693
3724
  const validationResult = validationService.validatePropertyValue(metadataValues.propertyValue, normalizeDataType(propertyRecordSchema.dataType), propertyRecordSchema.validation, propertyRecordSchema.refValueType
3694
3725
  ? normalizeDataType(String(propertyRecordSchema.refValueType))
@@ -4270,7 +4301,7 @@ const saveRelation = fromCallback(({ sendBack, input: { context, event } }) => {
4270
4301
  }
4271
4302
  const _saveRelation = async () => {
4272
4303
  // Use dynamic import to break circular dependency
4273
- const schemaMod = await import('./index-Bev-hZF-.js');
4304
+ const schemaMod = await import('./index-CiMEoGu3.js');
4274
4305
  const { ModelPropertyDataTypes } = schemaMod;
4275
4306
  if (!propertyNameRaw) {
4276
4307
  throw new Error('propertyName is required');
@@ -4361,6 +4392,86 @@ const getItemPropertyData = async (props) => {
4361
4392
  return queryRows[0];
4362
4393
  };
4363
4394
 
4395
+ /** Absolute path of the file {@link writeItemStorageFile} writes for `target`. */
4396
+ const getItemStorageFilePath = (target) => BaseFileManager.getFilesPath(getItemStorageSubdir(target.localStorageDir), target.fileName || getItemStorageLocalFileName(target.seedId, target.filenameSuffix));
4397
+ /**
4398
+ * Write an ItemStorage property's content to its local file, where saveItemStorage, reads, publish
4399
+ * (resolveItemStorageChildFile) and download all look for it. Returns what the metadata row records:
4400
+ * `refResolvedValue` (the file name) and `localStorageDir` (with a leading slash).
4401
+ *
4402
+ * Callers that also update the file's metadata row hold {@link withItemStorageFileLock} around
4403
+ * both, so another writer of the same file can't land in between.
4404
+ */
4405
+ const writeItemStorageFile = async (target, content) => {
4406
+ const dir = getItemStorageSubdir(target.localStorageDir);
4407
+ const fileName = target.fileName || getItemStorageLocalFileName(target.seedId, target.filenameSuffix);
4408
+ await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath(dir));
4409
+ const filePath = BaseFileManager.getFilesPath(dir, fileName);
4410
+ await BaseFileManager.saveFile(filePath, content);
4411
+ return { fileName, filePath, localStorageDir: target.localStorageDir || `/${dir}` };
4412
+ };
4413
+ /**
4414
+ * Lock name for one ItemStorage file: `seed:item-storage:<absolute file path>`. The path starts
4415
+ * with the files root, which also names the database (`<filesDir>/db/seed.db`), so the name is
4416
+ * per database as well as per file.
4417
+ */
4418
+ const itemStorageFileLockName = (filePath) => `seed:item-storage:${filePath}`;
4419
+ /**
4420
+ * Runs `fn` holding the lock of one ItemStorage file, across tabs (Web Locks) and within this JS
4421
+ * realm (an in-process queue where Web Locks are missing, e.g. Node < 24.5; see `withTabLock`).
4422
+ *
4423
+ * Writers of a local draft's file (saveItemStorage, convertVerbatimItemStorageRow, createNewItem)
4424
+ * hold it across "read the row → write the file → update the row", so the file and the row end
4425
+ * with the same writer's content. See docs/MULTI_TAB.md.
4426
+ *
4427
+ * Lock ordering: this lock is always the innermost. It may be taken while holding a broader lock
4428
+ * (`seed:item-storage-migration:<db>`, `seed:publish:<seedLocalId>`), never the other way round,
4429
+ * and no other lock (nor a second file lock) is requested while it is held. Keep the section to
4430
+ * local DB and file I/O: no network. Not re-entrant.
4431
+ */
4432
+ function withItemStorageFileLock(filePath, fn) {
4433
+ return withTabLock(itemStorageFileLockName(filePath), fn);
4434
+ }
4435
+ /** Lock attempts before giving up when the row's target file keeps changing under us. */
4436
+ const ROW_LOCK_ATTEMPTS = 3;
4437
+ const readRow = async (localId) => {
4438
+ const rows = await BaseDb.getAppDb()
4439
+ .select()
4440
+ .from(metadata)
4441
+ .where(eq(metadata.localId, localId))
4442
+ .limit(1);
4443
+ return rows[0];
4444
+ };
4445
+ /**
4446
+ * Runs `fn` with a fresh read of metadata row `localId`, holding the lock of the file that row's
4447
+ * content goes to. `fileOf` names that file (absolute path) for a row, or returns undefined when
4448
+ * there is nothing to write (then `fn` isn't called and the result is undefined).
4449
+ *
4450
+ * The file depends on the row, so the row is read once to pick the lock and again once it is held;
4451
+ * if the row now points at another file (another writer changed it meanwhile), the lock is
4452
+ * released and taken again for that file.
4453
+ */
4454
+ async function withLockedItemStorageRow(localId, fileOf, fn) {
4455
+ for (let attempt = 0; attempt < ROW_LOCK_ATTEMPTS; attempt++) {
4456
+ const row = await readRow(localId);
4457
+ const filePath = row && fileOf(row);
4458
+ if (!filePath)
4459
+ return undefined;
4460
+ const outcome = await withItemStorageFileLock(filePath, async () => {
4461
+ const fresh = await readRow(localId);
4462
+ const freshPath = fresh && fileOf(fresh);
4463
+ if (!freshPath)
4464
+ return { done: true, value: undefined };
4465
+ if (freshPath !== filePath)
4466
+ return { done: false };
4467
+ return { done: true, value: await fn(fresh, filePath) };
4468
+ });
4469
+ if (outcome.done)
4470
+ return outcome.value;
4471
+ }
4472
+ throw new Error(`ItemStorage file of metadata row ${localId} kept changing; not written`);
4473
+ }
4474
+
4364
4475
  /** A local edit: no attestation uid of its own and not derived from one. */
4365
4476
  const isLocalDraft = (row) => !row.uid && row.derivedFromUid == null;
4366
4477
  const saveItemStorage = fromCallback(({ sendBack, input: { context, event } }) => {
@@ -4414,22 +4525,25 @@ const saveItemStorage = fromCallback(({ sendBack, input: { context, event } }) =
4414
4525
  const latest = [...queryRows].sort(compareMetadataRowsLatestFirst)[0];
4415
4526
  propertyData = latest && isLocalDraft(latest) ? latest : undefined;
4416
4527
  if (!propertyData && newValue) {
4417
- const filename = `${draftSeedUid || draftSeedLocalId}${propertyRecordSchema.filenameSuffix}`;
4418
- const dir = propertyRecordSchema.localStorageDir?.replace(/^\//, '') || 'files';
4419
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath(dir));
4420
- const writeToPath = BaseFileManager.getFilesPath(dir, filename);
4421
- await BaseFileManager.saveFile(writeToPath, newValue);
4422
- propertyData = await createMetadata({
4423
- propertyName,
4424
- propertyValue: filename,
4425
- modelType: (modelName ?? knownRow?.modelType ?? '').toLowerCase() || undefined,
4426
- seedLocalId: draftSeedLocalId,
4427
- seedUid: draftSeedUid,
4428
- versionLocalId,
4429
- versionUid,
4528
+ const target = {
4529
+ seedId: draftSeedUid || draftSeedLocalId,
4430
4530
  localStorageDir: propertyRecordSchema.localStorageDir,
4431
- refValueType: 'file',
4432
- }, propertyRecordSchema);
4531
+ filenameSuffix: propertyRecordSchema.filenameSuffix,
4532
+ };
4533
+ propertyData = await withItemStorageFileLock(getItemStorageFilePath(target), async () => {
4534
+ const { fileName: filename } = await writeItemStorageFile(target, newValue);
4535
+ return createMetadata({
4536
+ propertyName,
4537
+ propertyValue: filename,
4538
+ modelType: (modelName ?? knownRow?.modelType ?? '').toLowerCase() || undefined,
4539
+ seedLocalId: draftSeedLocalId,
4540
+ seedUid: draftSeedUid,
4541
+ versionLocalId,
4542
+ versionUid,
4543
+ localStorageDir: propertyRecordSchema.localStorageDir,
4544
+ refValueType: 'file',
4545
+ }, propertyRecordSchema);
4546
+ });
4433
4547
  }
4434
4548
  }
4435
4549
  else if (propertyData && !isLocalDraft(propertyData)) {
@@ -4438,31 +4552,64 @@ const saveItemStorage = fromCallback(({ sendBack, input: { context, event } }) =
4438
4552
  if (!propertyData) {
4439
4553
  throw new Error(`No metadata row to save ${propertyName} to`);
4440
4554
  }
4441
- const localStorageDir = propertyRecordSchema.localStorageDir || propertyData.localStorageDir;
4442
- const fileName = propertyData.refResolvedValue ||
4443
- `${propertyData.seedUid || propertyData.seedLocalId}${propertyRecordSchema.filenameSuffix}`;
4444
- if (!localStorageDir || !fileName) {
4445
- throw new Error(`Missing localStorageDir: ${localStorageDir} or fileName: ${fileName}`);
4446
- }
4447
- const dir = localStorageDir.replace(/^\//, '');
4448
- await BaseFileManager.createDirIfNotExists(BaseFileManager.getFilesPath(dir));
4449
- const filePath = BaseFileManager.getFilesPath(dir, fileName);
4450
- try {
4451
- await BaseFileManager.saveFile(filePath, newValue);
4452
- }
4453
- catch (error) {
4454
- const fs = await BaseFileManager.getFs();
4455
- fs.writeFileSync(filePath, newValue);
4456
- }
4457
- await appDb
4458
- .update(metadata)
4459
- .set({
4460
- refResolvedValue: fileName,
4461
- })
4462
- .where(eq(metadata.localId, propertyData.localId));
4555
+ // No storage.path: the `files` directory, as resolveItemStorageChildFile and download assume.
4556
+ const localStorageDirOf = (row) => propertyRecordSchema.localStorageDir || row.localStorageDir || '/files';
4557
+ const fileNameOf = (row) => {
4558
+ if (row.refResolvedValue)
4559
+ return row.refResolvedValue;
4560
+ const seedId = row.seedUid || row.seedLocalId;
4561
+ return seedId ? getItemStorageLocalFileName(seedId, propertyRecordSchema.filenameSuffix) : undefined;
4562
+ };
4563
+ if (!fileNameOf(propertyData)) {
4564
+ throw new Error(`Missing a seed id to name the ${propertyName} file after`);
4565
+ }
4566
+ // Read the row, write the file and update the row under the file's lock, so a conversion of a
4567
+ // legacy row (migration, publish) or another save of this file, in this tab or another, can't
4568
+ // land in between and leave the file with older content than the row says.
4569
+ const saved = await withLockedItemStorageRow(propertyData.localId, (row) => {
4570
+ const fileName = fileNameOf(row);
4571
+ return fileName && BaseFileManager.getFilesPath(getItemStorageSubdir(localStorageDirOf(row)), fileName);
4572
+ }, async (row, filePath) => {
4573
+ const localStorageDir = localStorageDirOf(row);
4574
+ const fileName = fileNameOf(row);
4575
+ try {
4576
+ await writeItemStorageFile({ seedId: row.seedUid || row.seedLocalId || '', localStorageDir, fileName }, newValue);
4577
+ }
4578
+ catch (error) {
4579
+ const fs = await BaseFileManager.getFs();
4580
+ fs.writeFileSync(filePath, newValue);
4581
+ }
4582
+ // A legacy row (made before Item.create saved ItemStorage values) holds the old content itself
4583
+ // in propertyValue. The file is the content now: drop it, or a fresh load shows the old text
4584
+ // until the file is read. A row whose propertyValue is the file name keeps it.
4585
+ const clearsVerbatimValue = !row.refResolvedValue &&
4586
+ row.propertyValue != null &&
4587
+ row.propertyValue !== '' &&
4588
+ row.propertyValue !== fileName;
4589
+ // The row says where the file is (read back by hydration, the browser's metadata live query
4590
+ // and publish); without localStorageDir the live query would clear it from the context.
4591
+ await appDb
4592
+ .update(metadata)
4593
+ .set({
4594
+ refResolvedValue: fileName,
4595
+ localStorageDir,
4596
+ // Same shape as a row the migration or publish converted (convertVerbatimItemStorageRow).
4597
+ ...(clearsVerbatimValue && { propertyValue: null, refValueType: 'file' }),
4598
+ })
4599
+ .where(eq(metadata.localId, row.localId));
4600
+ return { fileName, localStorageDir };
4601
+ });
4602
+ // The row went away (or lost its seed ids) before the lock was granted.
4603
+ if (!saved)
4604
+ throw new Error(`No metadata row to save ${propertyName} to`);
4605
+ const { fileName, localStorageDir } = saved;
4463
4606
  sendBack({
4464
4607
  type: 'updateContext',
4465
4608
  renderValue: newValue,
4609
+ // Where the file is, right away: localStoragePath (and so publish uploads) must not wait for
4610
+ // the browser's metadata live query, which Node does not have at all.
4611
+ refResolvedValue: fileName,
4612
+ localStorageDir,
4466
4613
  // Point the property at the draft row when the edit moved off a published row.
4467
4614
  ...(propertyData.localId !== localId && { localId: propertyData.localId }),
4468
4615
  });
@@ -4834,10 +4981,10 @@ const getPropertyData = async ({ propertyName, seedLocalId, seedUid, modelName,
4834
4981
  let names = [...getMetadataPropertyNamesForQuery(propertyName)];
4835
4982
  if (modelName) {
4836
4983
  try {
4837
- const _mod_14 = await import('./index-DRXC5Mra.js');
4984
+ const _mod_14 = await import('./index-s15q14rm.js');
4838
4985
  const _ns_14 = _mod_14.f;
4839
4986
  const { Model } = _ns_14;
4840
- const _mod_15 = await import('./db-W1g29qsM.js');
4987
+ const _mod_15 = await import('./db-D9K_f5cF.js');
4841
4988
  const _ns_15 = _mod_15.Y;
4842
4989
  const { resolveItemModelFileId } = _ns_15;
4843
4990
  // Model names are only unique per schema: use the seed's own model when it is recorded.
@@ -5028,8 +5175,8 @@ const HTML_PROP_SEED_UID_RE = /^0x[a-fA-F0-9]{64}$/;
5028
5175
  */
5029
5176
  const resolvePropertyRecordSchemaFromSchemaData = async (modelName, propertyName, modelType, schemaName) => {
5030
5177
  try {
5031
- const _mod_16 = await import('./ClientManager-ClCwwhwo.js');
5032
- const _ns_16 = _mod_16.G;
5178
+ const _mod_16 = await import('./ClientManager-C-QXqUK9.js');
5179
+ const _ns_16 = _mod_16.I;
5033
5180
  const { loadAllSchemasFromDb } = _ns_16;
5034
5181
  const allSchemas = await loadAllSchemasFromDb();
5035
5182
  const modelNameAlt = modelType ? upperFirst(camelCase(modelType)) : '';
@@ -5082,11 +5229,11 @@ hints = {}) => {
5082
5229
  return undefined;
5083
5230
  }
5084
5231
  try {
5085
- const _mod_17 = await import('./index-DRXC5Mra.js');
5232
+ const _mod_17 = await import('./index-s15q14rm.js');
5086
5233
  const _ns_17 = _mod_17.f;
5087
5234
  const { Model } = _ns_17;
5088
5235
  const { modelPropertiesToObject } = await import('./model-DGMe-TTm.js');
5089
- const _mod_18 = await import('./db-W1g29qsM.js');
5236
+ const _mod_18 = await import('./db-D9K_f5cF.js');
5090
5237
  const _ns_18 = _mod_18.Y;
5091
5238
  const { resolveItemModelFileId } = _ns_18;
5092
5239
  const modelFileId = await resolveItemModelFileId(hints);
@@ -5246,7 +5393,7 @@ class ItemProperty {
5246
5393
  return;
5247
5394
  }
5248
5395
  // Use dynamic import to break circular dependency
5249
- const schemaMod = await import('./index-Bev-hZF-.js');
5396
+ const schemaMod = await import('./index-CiMEoGu3.js');
5250
5397
  const { ModelPropertyDataTypes } = schemaMod;
5251
5398
  const { context } = snapshot;
5252
5399
  const { propertyRecordSchema } = context;
@@ -5417,7 +5564,7 @@ class ItemProperty {
5417
5564
  const normalizedRefValueType = normalizeDataType(propertyRecordSchema?.refValueType);
5418
5565
  const propertyNames = getMetadataPropertyNamesForQuery(propertyName, normalizedDataType, normalizedRefValueType);
5419
5566
  const propertyNameVariant = propertyNames.length > 1 ? propertyNames[1] : undefined;
5420
- const _mod_19 = await import('./index-CSOQFAOn.js');
5567
+ const _mod_19 = await import('./index-DglvthOk.js');
5421
5568
  const _ns_19 = _mod_19.s;
5422
5569
  const seedSchemaMod = _ns_19;
5423
5570
  const { metadata } = seedSchemaMod;
@@ -5633,7 +5780,7 @@ class ItemProperty {
5633
5780
  const ctx = this._service.getSnapshot().context;
5634
5781
  let modelFileId;
5635
5782
  try {
5636
- const _mod_20 = await import('./db-W1g29qsM.js');
5783
+ const _mod_20 = await import('./db-D9K_f5cF.js');
5637
5784
  const _ns_20 = _mod_20.Y;
5638
5785
  const { resolveItemModelFileId } = _ns_20;
5639
5786
  modelFileId = await resolveItemModelFileId({
@@ -5996,7 +6143,7 @@ class ItemProperty {
5996
6143
  const propertiesData = await getItemProperties({ seedLocalId, seedUid });
5997
6144
  const instances = [];
5998
6145
  const seenNormalized = new Set();
5999
- const _mod_21 = await import('./db-W1g29qsM.js');
6146
+ const _mod_21 = await import('./db-D9K_f5cF.js');
6000
6147
  const _ns_21 = _mod_21.Y;
6001
6148
  const { resolveItemModelFileId } = _ns_21;
6002
6149
  const itemModelFileId = await resolveItemModelFileId({ seedLocalId, seedUid });
@@ -6014,7 +6161,7 @@ class ItemProperty {
6014
6161
  }
6015
6162
  else if (baseName) {
6016
6163
  try {
6017
- const _mod_22 = await import('./index-DRXC5Mra.js');
6164
+ const _mod_22 = await import('./index-s15q14rm.js');
6018
6165
  const _ns_22 = _mod_22.f;
6019
6166
  const { Model } = _ns_22;
6020
6167
  const { modelPropertiesToObject } = await import('./model-DGMe-TTm.js');
@@ -6031,7 +6178,7 @@ class ItemProperty {
6031
6178
  }
6032
6179
  if (modelName && propertyName) {
6033
6180
  try {
6034
- const _mod_23 = await import('./index-DRXC5Mra.js');
6181
+ const _mod_23 = await import('./index-s15q14rm.js');
6035
6182
  const _ns_23 = _mod_23.f;
6036
6183
  const { Model } = _ns_23;
6037
6184
  const { modelPropertiesToObject } = await import('./model-DGMe-TTm.js');
@@ -6353,7 +6500,7 @@ class ItemProperty {
6353
6500
  if (!propertyName || (!seedLocalId && !seedUid))
6354
6501
  return;
6355
6502
  if (db) {
6356
- const _mod_24 = await import('./index-CSOQFAOn.js');
6503
+ const _mod_24 = await import('./index-DglvthOk.js');
6357
6504
  const _ns_24 = _mod_24.s;
6358
6505
  const seedSchemaMod = _ns_24;
6359
6506
  const { metadata } = seedSchemaMod;
@@ -6399,7 +6546,7 @@ const createNewItem = async ({ modelName, modelFileId, ...propertyData }) => {
6399
6546
  }
6400
6547
  const seedType = toSnakeCase(modelName);
6401
6548
  // Dynamic import to break circular dependency
6402
- const _mod_25 = await import('./index-DRXC5Mra.js');
6549
+ const _mod_25 = await import('./index-s15q14rm.js');
6403
6550
  const _ns_25 = _mod_25.f;
6404
6551
  const modelMod = _ns_25;
6405
6552
  const { Model } = modelMod;
@@ -6420,13 +6567,38 @@ const createNewItem = async ({ modelName, modelFileId, ...propertyData }) => {
6420
6567
  for (const propertyName of allPropertyNames) {
6421
6568
  const propertyValue = propertyData[propertyName];
6422
6569
  const propertyRecordSchema = propertySchemas?.[propertyName];
6423
- await createMetadata({
6570
+ // ItemStorage content lives in the property's file (`<seedLocalId><extension>`), as a save puts
6571
+ // it; the row records where. Stored verbatim in the row, publish would never upload it.
6572
+ const isItemStorageValue = propertyRecordSchema?.storageType === 'ItemStorage' &&
6573
+ propertyValue != null &&
6574
+ propertyValue !== '';
6575
+ const insertRow = (storageFields) => createMetadata({
6424
6576
  seedLocalId: newSeedId,
6425
6577
  versionLocalId: newVersionId,
6426
6578
  propertyName,
6427
- propertyValue,
6579
+ propertyValue: storageFields ? undefined : propertyValue,
6580
+ ...storageFields,
6428
6581
  modelName,
6429
6582
  }, propertyRecordSchema, { skipValidation: true, modelFileId });
6583
+ if (!isItemStorageValue) {
6584
+ await insertRow();
6585
+ continue;
6586
+ }
6587
+ // File and row under the file's lock, like every writer of a local draft's file (see
6588
+ // withItemStorageFileLock). The seed is new, so nothing else should be writing it yet.
6589
+ const target = {
6590
+ seedId: newSeedId,
6591
+ localStorageDir: propertyRecordSchema.localStorageDir,
6592
+ filenameSuffix: propertyRecordSchema.filenameSuffix,
6593
+ };
6594
+ await withItemStorageFileLock(getItemStorageFilePath(target), async () => {
6595
+ const written = await writeItemStorageFile(target, propertyValue);
6596
+ await insertRow({
6597
+ refResolvedValue: written.fileName,
6598
+ localStorageDir: written.localStorageDir,
6599
+ refValueType: 'file',
6600
+ });
6601
+ });
6430
6602
  }
6431
6603
  return {
6432
6604
  modelName,
@@ -6557,7 +6729,7 @@ const getModel = () => {
6557
6729
  // the fragile `import(...).then(n => n.X)` chunk-namespace pattern.
6558
6730
  if (!modelImportPromise) {
6559
6731
  modelImportPromise = (async () => {
6560
- const _mod_26 = await import('./index-DRXC5Mra.js');
6732
+ const _mod_26 = await import('./index-s15q14rm.js');
6561
6733
  const _ns_26 = _mod_26.f;
6562
6734
  const mod = _ns_26;
6563
6735
  ModelClass = mod.Model;
@@ -6590,10 +6762,16 @@ const getModel = () => {
6590
6762
  };
6591
6763
  // Define tracked properties for the Proxy
6592
6764
  // These properties will be read from/written to the actor context
6593
- /** Raw File/Image/Html content (not already a storage seed reference) needs ItemProperty.save(). */
6594
- function needsStorageSavePipeline(dataType, value) {
6765
+ /**
6766
+ * Initial values that need ItemProperty.save() rather than a verbatim metadata row: raw File/Image/Html
6767
+ * content (not already a storage seed reference) becomes a storage seed, and an ItemStorage property's
6768
+ * content goes into its file (`<seedLocalId><extension>`), where publish and reads look for it.
6769
+ */
6770
+ function needsStorageSavePipeline(dataType, value, storageType) {
6595
6771
  if (value == null || value === '')
6596
6772
  return false;
6773
+ if (storageType === 'ItemStorage')
6774
+ return true;
6597
6775
  const isStorageType = isDataType(dataType, ModelPropertyDataTypes.File) ||
6598
6776
  isDataType(dataType, ModelPropertyDataTypes.Image) ||
6599
6777
  isDataType(dataType, ModelPropertyDataTypes.Html);
@@ -6706,12 +6884,12 @@ class Item {
6706
6884
  };
6707
6885
  this.getPublishUploads = async (options) => {
6708
6886
  // Use dynamic import to break circular dependency
6709
- const getPublishUploadsMod = await import('./getPublishUploads-BGpDsrBp.js');
6887
+ const getPublishUploadsMod = await import('./getPublishUploads-BEqRiKIS.js');
6710
6888
  const { getPublishUploads } = getPublishUploadsMod;
6711
6889
  return await getPublishUploads(this, [], undefined, options);
6712
6890
  };
6713
6891
  this.getPublishPayload = async (uploadedTransactions, options) => {
6714
- const _mod_27 = await import('./getPublishPayload-D5CQZd-y.js');
6892
+ const _mod_27 = await import('./getPublishPayload-BHrxVtzY.js');
6715
6893
  const _ns_27 = _mod_27.g;
6716
6894
  const getPublishPayloadMod = _ns_27;
6717
6895
  const { getPublishPayload } = getPublishPayloadMod;
@@ -7243,10 +7421,11 @@ class Item {
7243
7421
  // Get property names directly from database to make Item independent from Model
7244
7422
  let propertyNames = [];
7245
7423
  const dataTypeByPropertyName = new Map();
7424
+ const storageTypeByPropertyName = new Map();
7246
7425
  const db = BaseDb.getAppDb();
7247
7426
  if (db && props.modelName) {
7248
7427
  // Model names are only unique per schema: resolve the exact models row from the most specific scope.
7249
- const _mod_28 = await import('./db-W1g29qsM.js');
7428
+ const _mod_28 = await import('./db-D9K_f5cF.js');
7250
7429
  const _ns_28 = _mod_28.Y;
7251
7430
  const { resolveModelRecord } = _ns_28;
7252
7431
  const modelRecord = await resolveModelRecord(props.modelName, {
@@ -7260,10 +7439,10 @@ class Item {
7260
7439
  // Scope the constructor's Model lookup to this model's schema (as getItemData does on reload),
7261
7440
  // so a same-named model cached from another schema can't supply the property set.
7262
7441
  if (modelRecord && !props.schemaName) {
7263
- const _mod_29 = await import('./BasePathResolver-BdxCSIzn.js');
7442
+ const _mod_29 = await import('./BasePathResolver-CfSfMW5_.js');
7264
7443
  const _ns_29 = _mod_29.R;
7265
7444
  const { modelSchemas } = _ns_29;
7266
- const _mod_30 = await import('./BasePathResolver-BdxCSIzn.js');
7445
+ const _mod_30 = await import('./BasePathResolver-CfSfMW5_.js');
7267
7446
  const _ns_30 = _mod_30.Q;
7268
7447
  const { schemas: schemasTable } = _ns_30;
7269
7448
  const schemaRows = await db
@@ -7278,13 +7457,19 @@ class Item {
7278
7457
  }
7279
7458
  if (modelRecords.length > 0 && modelRecords[0].id) {
7280
7459
  const propertyRecords = await db
7281
- .select({ name: properties.name, dataType: properties.dataType })
7460
+ .select({
7461
+ name: properties.name,
7462
+ dataType: properties.dataType,
7463
+ storageType: properties.storageType,
7464
+ })
7282
7465
  .from(properties)
7283
7466
  .where(eq(properties.modelId, modelRecords[0].id));
7284
7467
  propertyNames = propertyRecords.map((r) => r.name).filter((name) => Boolean(name));
7285
7468
  for (const r of propertyRecords) {
7286
7469
  if (r.name && r.dataType)
7287
7470
  dataTypeByPropertyName.set(r.name, r.dataType);
7471
+ if (r.name && r.storageType)
7472
+ storageTypeByPropertyName.set(r.name, r.storageType);
7288
7473
  }
7289
7474
  }
7290
7475
  }
@@ -7293,7 +7478,8 @@ class Item {
7293
7478
  modelFileId: props.modelFileId,
7294
7479
  };
7295
7480
  // File/Image/Html values that are raw content (html string, data URI, URL, File) must go through
7296
- // the property's save pipeline to become storage seeds; createNewItem would store them verbatim.
7481
+ // the property's save pipeline to become storage seeds, and ItemStorage values to be written to
7482
+ // their file with the property context pointing at it (as `prop.value = v; await prop.save()`).
7297
7483
  const pipelineValues = [];
7298
7484
  // Only include properties that are in the model schema
7299
7485
  // Exclude modelInstance, modelName, and schemaName as they're metadata, not item properties
@@ -7303,7 +7489,7 @@ class Item {
7303
7489
  continue;
7304
7490
  }
7305
7491
  if (propertyNames.length === 0 || propertyNames.includes(key)) {
7306
- if (needsStorageSavePipeline(dataTypeByPropertyName.get(key), value)) {
7492
+ if (needsStorageSavePipeline(dataTypeByPropertyName.get(key), value, storageTypeByPropertyName.get(key))) {
7307
7493
  pipelineValues.push([key, value]);
7308
7494
  continue;
7309
7495
  }
@@ -7435,7 +7621,7 @@ class Item {
7435
7621
  return proxiedInstance;
7436
7622
  }
7437
7623
  /**
7438
- * Run each File/Image/Html initial value through its ItemProperty save pipeline (sequentially, to
7624
+ * Run each File/Image/Html/ItemStorage initial value through its ItemProperty save pipeline (sequentially, to
7439
7625
  * avoid SQLite write contention). Rejects on the first failure; the item itself has been created.
7440
7626
  */
7441
7627
  static async savePipelineValues(item, pipelineValues, timeout) {
@@ -7609,7 +7795,7 @@ class Item {
7609
7795
  if (!appDb || Item.instanceCache.size === 0) {
7610
7796
  return;
7611
7797
  }
7612
- const _mod_31 = await import('./index-CSOQFAOn.js');
7798
+ const _mod_31 = await import('./index-DglvthOk.js');
7613
7799
  const _ns_31 = _mod_31.s;
7614
7800
  const { metadata } = _ns_31;
7615
7801
  const { eq, and } = await import('drizzle-orm');
@@ -8068,7 +8254,7 @@ class Item {
8068
8254
  itemActor.send(event);
8069
8255
  };
8070
8256
  try {
8071
- const _mod_32 = await import('./index-CSOQFAOn.js');
8257
+ const _mod_32 = await import('./index-DglvthOk.js');
8072
8258
  const _ns_32 = _mod_32.s;
8073
8259
  const seedSchemaMod = _ns_32;
8074
8260
  const { seeds, versions, metadata } = seedSchemaMod;
@@ -8421,5 +8607,5 @@ var Item$1 = /*#__PURE__*/Object.freeze({
8421
8607
  Item: Item
8422
8608
  });
8423
8609
 
8424
- export { getRevokeExecutor as A, getUploadExecutor as B, ClientManagerState as C, getVersionData$1 as D, isItemOwned as E, isLocalUnsealedDraft as F, isSeedRowOwned as G, ownedPublisherSql as H, Item as I, pickLatestMetadataRowPerProperty as J, propertyMachine as K, publisherInAddressListSql as L, METADATA_LATEST_FIRST_ORDER_SQL as M, publisherIsInOwnedSet as N, setAdditionalSyncAddresses as O, setGetPublisherForNewSeeds as P, setRevokeExecutor as Q, setUploadExecutor as R, getInvariantSafePropertyDescriptor as S, clearDestroySubscriptions as T, unloadEntity as U, ClientManagerEvents as V, resolvePublisherFromSeedRow as W, getPropertyData$1 as X, Item$1 as Y, getEasSchemaUidForModel as a, getLatestPublishedVersionRow as b, chunkValues as c, rowsPerInsert as d, getGetAdditionalSyncAddresses as e, ItemProperty as f, getItemData as g, ItemPropertySaveValidationError as h, isVersionRevoked as i, waitForEntityIdle as j, createReactiveProxy as k, listRelationEasPropertyName as l, findEntity as m, forceRemoveFromCaches as n, runDestroyLifecycle as o, parseListPropertyValueFromStorage as p, compareMetadataRowsLatestFirst as q, resolveStorageNameToSchemaName as r, selectInBatches as s, isPublishedMetadataRow as t, MachineIds as u, createNewItem as v, writeInBatches as w, getEasSchemaForItemProperty as x, getGetPublisherForNewSeeds as y, getMetadataLatest as z };
8425
- //# sourceMappingURL=Item-B9Y4VuK1.js.map
8610
+ export { writeItemStorageFile as $, getRevokeExecutor as A, getUploadExecutor as B, ClientManagerState as C, getVersionData$1 as D, isItemOwned as E, isLocalUnsealedDraft as F, isSeedRowOwned as G, localUnsealedDraftSql as H, Item as I, ownedPublisherSql as J, ownedSeedsSql as K, pickLatestMetadataRowPerProperty as L, METADATA_LATEST_FIRST_ORDER_SQL as M, placeholderUidSql as N, propertyMachine as O, publisherInAddressListSql as P, publisherIsInOwnedSet as Q, setAdditionalSyncAddresses as R, setGetPublisherForNewSeeds as S, setRevokeExecutor as T, setUploadExecutor as U, getInvariantSafePropertyDescriptor as V, clearDestroySubscriptions as W, unloadEntity as X, ClientManagerEvents as Y, withLockedItemStorageRow as Z, getItemStorageFilePath as _, getEasSchemaUidForModel as a, resolvePublisherFromSeedRow as a0, getPropertyData$1 as a1, Item$1 as a2, getLatestPublishedVersionRow as b, compareMetadataRowsLatestFirst as c, chunkValues as d, rowsPerInsert as e, getGetAdditionalSyncAddresses as f, getItemData as g, ItemProperty as h, ItemPropertySaveValidationError as i, isVersionRevoked as j, waitForEntityIdle as k, listRelationEasPropertyName as l, createReactiveProxy as m, findEntity as n, forceRemoveFromCaches as o, parseListPropertyValueFromStorage as p, runDestroyLifecycle as q, resolveStorageNameToSchemaName as r, selectInBatches as s, isPublishedMetadataRow as t, MachineIds as u, createNewItem as v, writeInBatches as w, getEasSchemaForItemProperty as x, getGetPublisherForNewSeeds as y, getMetadataLatest as z };
8611
+ //# sourceMappingURL=Item-C7sUUu2B.js.map