@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
@@ -0,0 +1,872 @@
1
+ 'use strict';
2
+
3
+ var main_cjs = require('./index-C4XlgCJ4.js');
4
+ var arweave = require('@seedprotocol/arweave');
5
+ var publishDraftGraph = require('./publishDraftGraph-3ASwAlD7.js');
6
+ var debug = require('debug');
7
+ var drizzleOrm = require('drizzle-orm');
8
+ require('pluralize');
9
+ require('immer');
10
+ require('reflect-metadata');
11
+ require('xstate');
12
+ require('drizzle-orm/sqlite-core');
13
+ require('@seedprotocol/eas');
14
+ require('@sinclair/typebox');
15
+ require('drizzle-orm/casing');
16
+ require('lodash-es');
17
+ require('@noble/hashes/sha256');
18
+ require('@noble/hashes/sha3');
19
+ require('@noble/hashes/utils');
20
+ require('nanoid');
21
+ require('nanoid-dictionary');
22
+ require('@seedprotocol/query');
23
+ require('rxjs');
24
+ require('fs/promises');
25
+ require('fs');
26
+ require('path');
27
+ require('url');
28
+ require('node:url');
29
+ require('@libsql/client');
30
+ require('drizzle-orm/libsql');
31
+ require('drizzle-orm/libsql/migrator');
32
+ require('js-yaml');
33
+ require('child_process');
34
+ require('@seedprotocol/arweave/node');
35
+ require('@seedprotocol/eas/node');
36
+ require('./property-fa0iju0J.js');
37
+
38
+ /**
39
+ * File extension <-> MIME type, shared by the upload side (`getPublishUploads.ts`, which sets the
40
+ * `Content-Type` tag) and the download worker (`browser/workers/filesDownload.ts`, which picks the
41
+ * extension of a file saved under `files/`). The worker runs from a string and cannot import this
42
+ * module, so {@link MIME_TO_EXTENSION} is injected into its source as JSON.
43
+ */
44
+ /**
45
+ * Lowercase extension (no dot) to MIME type. Includes the odd extensions the SDK itself produces:
46
+ * `saveImage` names a file `<id>.<subtype>` (e.g. `.svg+xml`, `.x-icon`), so subtypes appear here too.
47
+ */
48
+ const EXTENSION_TO_MIME = {
49
+ // images
50
+ png: 'image/png',
51
+ apng: 'image/apng',
52
+ jpg: 'image/jpeg',
53
+ jpeg: 'image/jpeg',
54
+ jfif: 'image/jpeg',
55
+ gif: 'image/gif',
56
+ webp: 'image/webp',
57
+ avif: 'image/avif',
58
+ heic: 'image/heic',
59
+ heif: 'image/heif',
60
+ svg: 'image/svg+xml',
61
+ 'svg+xml': 'image/svg+xml',
62
+ bmp: 'image/bmp',
63
+ ico: 'image/x-icon',
64
+ 'x-icon': 'image/x-icon',
65
+ 'vnd.microsoft.icon': 'image/x-icon',
66
+ tif: 'image/tiff',
67
+ tiff: 'image/tiff',
68
+ // text / documents
69
+ html: 'text/html',
70
+ htm: 'text/html',
71
+ xhtml: 'application/xhtml+xml',
72
+ json: 'application/json',
73
+ txt: 'text/plain',
74
+ plain: 'text/plain',
75
+ md: 'text/markdown',
76
+ markdown: 'text/markdown',
77
+ csv: 'text/csv',
78
+ tsv: 'text/tab-separated-values',
79
+ xml: 'application/xml',
80
+ css: 'text/css',
81
+ js: 'text/javascript',
82
+ mjs: 'text/javascript',
83
+ pdf: 'application/pdf',
84
+ rtf: 'application/rtf',
85
+ epub: 'application/epub+zip',
86
+ zip: 'application/zip',
87
+ gz: 'application/gzip',
88
+ doc: 'application/msword',
89
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
90
+ xls: 'application/vnd.ms-excel',
91
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
92
+ ppt: 'application/vnd.ms-powerpoint',
93
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
94
+ odt: 'application/vnd.oasis.opendocument.text',
95
+ // audio
96
+ mp3: 'audio/mpeg',
97
+ mpeg: 'audio/mpeg',
98
+ wav: 'audio/wav',
99
+ ogg: 'audio/ogg',
100
+ oga: 'audio/ogg',
101
+ opus: 'audio/opus',
102
+ m4a: 'audio/mp4',
103
+ aac: 'audio/aac',
104
+ flac: 'audio/flac',
105
+ weba: 'audio/webm',
106
+ // video
107
+ mp4: 'video/mp4',
108
+ m4v: 'video/mp4',
109
+ webm: 'video/webm',
110
+ mov: 'video/quicktime',
111
+ quicktime: 'video/quicktime',
112
+ ogv: 'video/ogg',
113
+ mkv: 'video/x-matroska',
114
+ avi: 'video/x-msvideo',
115
+ // fonts
116
+ woff: 'font/woff',
117
+ woff2: 'font/woff2',
118
+ ttf: 'font/ttf',
119
+ otf: 'font/otf',
120
+ };
121
+ /**
122
+ * MIME type to the extension a downloaded file gets. One canonical extension per type (the
123
+ * first one listed here wins over {@link EXTENSION_TO_MIME}'s aliases), plus a few common
124
+ * non-canonical spellings a gateway may send.
125
+ */
126
+ (() => {
127
+ const preferred = {
128
+ 'image/jpeg': 'jpg',
129
+ 'image/svg+xml': 'svg',
130
+ 'image/x-icon': 'ico',
131
+ 'image/tiff': 'tiff',
132
+ 'text/html': 'html',
133
+ 'text/plain': 'txt',
134
+ 'text/markdown': 'md',
135
+ 'text/javascript': 'js',
136
+ 'audio/mpeg': 'mp3',
137
+ 'audio/ogg': 'ogg',
138
+ 'audio/mp4': 'm4a',
139
+ 'video/mp4': 'mp4',
140
+ 'video/quicktime': 'mov',
141
+ 'video/ogg': 'ogv',
142
+ };
143
+ const out = { ...preferred };
144
+ for (const [ext, mime] of Object.entries(EXTENSION_TO_MIME)) {
145
+ if (!(mime in out))
146
+ out[mime] = ext;
147
+ }
148
+ // Non-canonical names some servers use for the same formats.
149
+ Object.assign(out, {
150
+ 'audio/mp3': 'mp3',
151
+ 'audio/x-wav': 'wav',
152
+ 'audio/wave': 'wav',
153
+ 'audio/vnd.wave': 'wav',
154
+ 'audio/x-m4a': 'm4a',
155
+ 'audio/x-flac': 'flac',
156
+ 'application/x-zip-compressed': 'zip',
157
+ 'image/vnd.microsoft.icon': 'ico',
158
+ });
159
+ return out;
160
+ })();
161
+ /**
162
+ * Content types that say nothing about the content. A Blob carrying one of these is treated as
163
+ * untyped.
164
+ */
165
+ const GENERIC_MIME_TYPES = [
166
+ '',
167
+ 'application/octet-stream',
168
+ 'binary/octet-stream',
169
+ ];
170
+ /** Lowercase `type/subtype` without parameters; `undefined` when empty or generic. */
171
+ const normalizeMimeType = (mimeType) => {
172
+ const t = (mimeType ?? '').split(';')[0].trim().toLowerCase();
173
+ if (!t || GENERIC_MIME_TYPES.includes(t) || !t.includes('/'))
174
+ return undefined;
175
+ return t;
176
+ };
177
+ /** MIME type for a path or file name by its extension, if it has a known one. */
178
+ const getMimeTypeFromPath = (filePathOrName) => {
179
+ const name = filePathOrName.split('/').pop() ?? '';
180
+ const dot = name.lastIndexOf('.');
181
+ if (dot <= 0 || dot === name.length - 1)
182
+ return undefined;
183
+ return EXTENSION_TO_MIME[name.slice(dot + 1).toLowerCase()];
184
+ };
185
+ /**
186
+ * MIME type from the leading bytes, for formats with an unambiguous signature. Used when a local
187
+ * file has no (known) extension, e.g. a file seed named after its id.
188
+ */
189
+ const sniffMimeType = (bytes) => {
190
+ const at = (offset, ...sig) => bytes.length >= offset + sig.length && sig.every((b, i) => bytes[offset + i] === b);
191
+ const ascii = (offset, s) => at(offset, ...Array.from(s).map((c) => c.charCodeAt(0)));
192
+ if (at(0, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a))
193
+ return 'image/png';
194
+ if (at(0, 0xff, 0xd8, 0xff))
195
+ return 'image/jpeg';
196
+ if (ascii(0, 'GIF87a') || ascii(0, 'GIF89a'))
197
+ return 'image/gif';
198
+ if (ascii(0, 'RIFF') && ascii(8, 'WEBP'))
199
+ return 'image/webp';
200
+ if (ascii(0, 'RIFF') && ascii(8, 'WAVE'))
201
+ return 'audio/wav';
202
+ if (ascii(0, 'RIFF') && ascii(8, 'AVI '))
203
+ return 'video/x-msvideo';
204
+ if (ascii(0, 'BM') && bytes.length > 14)
205
+ return 'image/bmp';
206
+ if (at(0, 0x49, 0x49, 0x2a, 0x00) || at(0, 0x4d, 0x4d, 0x00, 0x2a))
207
+ return 'image/tiff';
208
+ if (ascii(0, '%PDF-'))
209
+ return 'application/pdf';
210
+ if (ascii(0, 'OggS'))
211
+ return 'audio/ogg';
212
+ if (ascii(0, 'fLaC'))
213
+ return 'audio/flac';
214
+ if (ascii(0, 'ID3'))
215
+ return 'audio/mpeg';
216
+ if (at(0, 0x1a, 0x45, 0xdf, 0xa3))
217
+ return 'video/webm';
218
+ if (ascii(4, 'ftyp')) {
219
+ const brand = String.fromCharCode(...Array.from(bytes.slice(8, 12)));
220
+ if (brand === 'avif' || brand === 'avis')
221
+ return 'image/avif';
222
+ if (['heic', 'heix', 'heif', 'mif1', 'msf1'].includes(brand))
223
+ return 'image/heic';
224
+ if (brand === 'qt ')
225
+ return 'video/quicktime';
226
+ if (brand === 'M4A ')
227
+ return 'audio/mp4';
228
+ return 'video/mp4';
229
+ }
230
+ return undefined;
231
+ };
232
+ /**
233
+ * Best MIME type for upload bytes: the source's own type (a Blob/File `type`) when it is specific,
234
+ * then the file name's extension, then the bytes' signature.
235
+ */
236
+ const resolveUploadMimeType = (params) => normalizeMimeType(params.sourceType) ??
237
+ (params.fileName ? getMimeTypeFromPath(params.fileName) : undefined) ??
238
+ (params.bytes ? sniffMimeType(params.bytes) : undefined);
239
+
240
+ /**
241
+ * `Promise.all(items.map(fn))` with at most `limit` calls in flight. Results keep the input order.
242
+ * Rejects with the first error (by time); after that no new calls start, though calls already in
243
+ * flight run to completion.
244
+ */
245
+ async function mapWithConcurrency(items, limit, fn) {
246
+ const results = new Array(items.length);
247
+ const workerCount = Math.max(1, Math.min(Math.floor(limit) || 1, items.length));
248
+ let next = 0;
249
+ let failed = false;
250
+ const worker = async () => {
251
+ while (!failed && next < items.length) {
252
+ const index = next++;
253
+ try {
254
+ results[index] = await fn(items[index], index);
255
+ }
256
+ catch (error) {
257
+ failed = true;
258
+ throw error;
259
+ }
260
+ }
261
+ };
262
+ await Promise.all(Array.from({ length: workerCount }, worker));
263
+ return results;
264
+ }
265
+
266
+ /**
267
+ * Composite uploads: several ItemStorage files of one item in a single Arweave transaction.
268
+ *
269
+ * Producer: `getPublishUploads.ts` (`processUploadPropertyData`), for an item with a
270
+ * `storageTransactionId` property and ItemStorage properties (e.g. a Post's `html` and `json`).
271
+ * Consumer: the download worker (`browser/workers/filesDownload.ts`), which keeps its own copy of
272
+ * {@link decodeCompositeUpload} because it runs from a string; a test keeps the two in step.
273
+ *
274
+ * Format (unchanged for text children, so composites already on Arweave still read):
275
+ *
276
+ * ===FILE_SEPARATOR===<name>===FILE_SEPARATOR===<utf-8 text> (repeated per child)
277
+ *
278
+ * A child that is not valid UTF-8 text (or whose text contains the separator) is written as
279
+ * base64 under the name `<name>;base64`. Composites written before this suffix existed converted
280
+ * every child to text, which corrupted binary children; those bytes cannot be recovered.
281
+ */
282
+ const COMPOSITE_SEPARATOR = '===FILE_SEPARATOR===';
283
+ const COMPOSITE_BASE64_SUFFIX = ';base64';
284
+ const bytesToBase64 = (bytes) => {
285
+ let binary = '';
286
+ const chunk = 0x8000;
287
+ for (let i = 0; i < bytes.length; i += chunk) {
288
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
289
+ }
290
+ return btoa(binary);
291
+ };
292
+ /** The child's text when it can travel as text: valid UTF-8, no NUL bytes, no separator. */
293
+ const childAsText = (bytes) => {
294
+ if (bytes.includes(0))
295
+ return undefined;
296
+ let text;
297
+ try {
298
+ text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
299
+ }
300
+ catch {
301
+ return undefined;
302
+ }
303
+ return text.includes(COMPOSITE_SEPARATOR) ? undefined : text;
304
+ };
305
+ const encodeCompositeUpload = (children) => {
306
+ let composite = '';
307
+ for (const { name, bytes } of children) {
308
+ const text = childAsText(bytes);
309
+ composite +=
310
+ text !== undefined
311
+ ? `${COMPOSITE_SEPARATOR}${name}${COMPOSITE_SEPARATOR}${text}`
312
+ : `${COMPOSITE_SEPARATOR}${name}${COMPOSITE_BASE64_SUFFIX}${COMPOSITE_SEPARATOR}${bytesToBase64(bytes)}`;
313
+ }
314
+ return new TextEncoder().encode(composite);
315
+ };
316
+ new TextEncoder().encode(COMPOSITE_SEPARATOR);
317
+
318
+ const logger = debug('seedSdk:item:getPublishUploads');
319
+ /** L1 transactions {@link getPublishUploads} creates at once (each asks the gateway for price and anchor). */
320
+ const CREATE_TRANSACTION_CONCURRENCY = 4;
321
+ const toUint8Array = async (data) => {
322
+ if (typeof Blob !== 'undefined' && data instanceof Blob) {
323
+ return new Uint8Array(await data.arrayBuffer());
324
+ }
325
+ return new Uint8Array(data);
326
+ };
327
+ /** A local file's bytes plus its MIME type: the Blob's own type, else the name's extension, else a sniff of the bytes. */
328
+ const readUploadFile = async (filePath, fileName = filePath) => {
329
+ const data = await main_cjs.BaseFileManager.readFileAsBuffer(filePath);
330
+ const bytes = await toUint8Array(data);
331
+ const sourceType = typeof Blob !== 'undefined' && data instanceof Blob ? data.type : undefined;
332
+ return { bytes, contentType: resolveUploadMimeType({ sourceType, fileName, bytes }) };
333
+ };
334
+ const prepareArweaveTransaction = async (data, contentHash, contentType, additionalTags) => {
335
+ const tags = main_cjs.buildArweaveContentTags(contentHash, contentType, additionalTags);
336
+ const tx = await arweave.BaseArweaveClient.createTransaction(data, {
337
+ tags: tags.length ? tags : undefined,
338
+ });
339
+ return tx;
340
+ };
341
+ /**
342
+ * The one place an upload's bytes become a {@link PublishUploadData}: everything after this
343
+ * (Content-SHA-256, tags, the L1 transaction or the bundler DataItem, signing) works from what it
344
+ * returns. A future private-publish option that encrypts content belongs here, before the hash and
345
+ * tags are computed, so both publish paths pick it up.
346
+ */
347
+ const buildPublishUploadData = (data, contentType, target, options) => {
348
+ const contentHash = main_cjs.getContentSha256(data);
349
+ return {
350
+ data,
351
+ contentHash,
352
+ contentType,
353
+ tags: main_cjs.buildArweaveContentTags(contentHash, contentType, options?.arweaveUploadTags),
354
+ ...target,
355
+ };
356
+ };
357
+ const DATA_URI_IMAGE = /^data:(image\/[a-zA-Z0-9.+-]+);base64,([\s\S]*)$/i;
358
+ function decodeDataUriImage(dataUri) {
359
+ const m = DATA_URI_IMAGE.exec((dataUri ?? '').trim());
360
+ if (!m)
361
+ return null;
362
+ try {
363
+ const mimeType = m[1].toLowerCase().trim();
364
+ const base64 = m[2].replace(/\s/g, '');
365
+ const binary = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
366
+ return { mimeType, bytes: binary };
367
+ }
368
+ catch {
369
+ return null;
370
+ }
371
+ }
372
+ const getStorageSeedUploadData = async (itemStorageSeedProperties, options) => {
373
+ const uploads = [];
374
+ for (const itemProperty of itemStorageSeedProperties) {
375
+ const snapshot = itemProperty.getService().getSnapshot();
376
+ const context = 'context' in snapshot ? snapshot.context : null;
377
+ if (!context) {
378
+ continue;
379
+ }
380
+ const propertyValue = context.propertyValue;
381
+ const refResolvedValue = context.refResolvedValue;
382
+ if (!refResolvedValue) {
383
+ continue;
384
+ }
385
+ // propertyValue is the storage seed's seedLocalId; use it for the upload so processRelationOrImageProperty can match
386
+ const { seedLocalId } = main_cjs.resolveSeedIdsFromRefString(main_cjs.normalizeRelationPropertyValue(propertyValue) ?? '');
387
+ if (!seedLocalId) {
388
+ continue;
389
+ }
390
+ const dataType = itemProperty.propertyDef?.refValueType ??
391
+ itemProperty.propertyDef?.dataType ??
392
+ 'Image';
393
+ if (main_cjs.isDataType(dataType, main_cjs.ModelPropertyDataTypes.Html)) {
394
+ if (options?.deferHtmlStorageSeedLocalIds?.includes(seedLocalId)) {
395
+ continue;
396
+ }
397
+ if (options?.onlyHtmlStorageSeedLocalIds?.length &&
398
+ !options.onlyHtmlStorageSeedLocalIds.includes(seedLocalId)) {
399
+ continue;
400
+ }
401
+ }
402
+ else if (options?.onlyHtmlStorageSeedLocalIds?.length) {
403
+ continue;
404
+ }
405
+ const baseDir = main_cjs.getStorageDirForDataType(dataType);
406
+ const filePath = `${baseDir}/${refResolvedValue}`;
407
+ const exists = await main_cjs.BaseFileManager.pathExists(filePath);
408
+ if (!exists) {
409
+ continue;
410
+ }
411
+ const { bytes: fileContents, contentType } = await readUploadFile(filePath, refResolvedValue);
412
+ uploads.push(buildPublishUploadData(fileContents, contentType, {
413
+ itemPropertyName: itemProperty.propertyName,
414
+ itemPropertyLocalId: itemProperty.localId,
415
+ seedLocalId,
416
+ versionLocalId: itemProperty.versionLocalId,
417
+ }, options));
418
+ }
419
+ return uploads;
420
+ };
421
+ async function appendCoPublishedImageUploadData(item, uploads, options) {
422
+ const appDb = main_cjs.BaseDb.getAppDb();
423
+ if (!appDb || options?.onlyHtmlStorageSeedLocalIds?.length)
424
+ return uploads;
425
+ const rows = await appDb
426
+ .select()
427
+ .from(main_cjs.htmlEmbeddedImageCoPublish)
428
+ .where(drizzleOrm.eq(main_cjs.htmlEmbeddedImageCoPublish.parentSeedLocalId, item.seedLocalId));
429
+ const seen = new Set(uploads.map((u) => u.seedLocalId));
430
+ for (const row of rows) {
431
+ if (seen.has(row.imageSeedLocalId))
432
+ continue;
433
+ const imageItem = await main_cjs.Item.find({ seedLocalId: row.imageSeedLocalId, modelName: 'Image' });
434
+ if (!imageItem)
435
+ continue;
436
+ const st = imageItem.internalProperties['storageTransactionId'] ??
437
+ imageItem.allProperties['storageTransactionId'];
438
+ const stSnap = st?.getService().getSnapshot();
439
+ const stCtx = stSnap && 'context' in stSnap ? stSnap.context : undefined;
440
+ const stValue = typeof stCtx?.propertyValue === 'string'
441
+ ? (stCtx.propertyValue ?? '')
442
+ : '';
443
+ const decoded = decodeDataUriImage(stValue);
444
+ const more = [];
445
+ if (decoded && st && st.localId && st.versionLocalId) {
446
+ more.push(buildPublishUploadData(decoded.bytes, decoded.mimeType, {
447
+ itemPropertyName: st.propertyName,
448
+ itemPropertyLocalId: st.localId,
449
+ seedLocalId: imageItem.seedLocalId,
450
+ versionLocalId: st.versionLocalId,
451
+ }, options));
452
+ }
453
+ for (const u of more) {
454
+ if (!seen.has(u.seedLocalId)) {
455
+ uploads.push(u);
456
+ seen.add(u.seedLocalId);
457
+ }
458
+ }
459
+ }
460
+ return uploads;
461
+ }
462
+ const isUsablePath = (filePath) => !!filePath && !filePath.endsWith('undefined') && !filePath.endsWith('null');
463
+ /** The newest metadata row of an ItemStorage property, read from the DB (not the live query). */
464
+ const getLatestItemStorageRow = async (childProperty) => {
465
+ const appDb = main_cjs.BaseDb.getAppDb();
466
+ const seedLocalId = childProperty.seedLocalId;
467
+ const propertyName = childProperty.storagePropertyName || childProperty.propertyName;
468
+ if (!appDb || !seedLocalId || !propertyName)
469
+ return undefined;
470
+ const where = [drizzleOrm.eq(main_cjs.metadata.seedLocalId, seedLocalId), drizzleOrm.eq(main_cjs.metadata.propertyName, propertyName)];
471
+ if (childProperty.versionLocalId)
472
+ where.push(drizzleOrm.eq(main_cjs.metadata.versionLocalId, childProperty.versionLocalId));
473
+ const rows = await appDb.select().from(main_cjs.metadata).where(drizzleOrm.and(...where));
474
+ return [...rows].sort(main_cjs.compareMetadataRowsLatestFirst)[0];
475
+ };
476
+ /**
477
+ * Write a legacy ItemStorage draft row's verbatim content to `<seedUid or seedLocalId><extension>`
478
+ * and record it on the row (refResolvedValue, localStorageDir) and in the property context. The
479
+ * row's propertyValue is cleared once the file is written, so the row has the same shape as one a
480
+ * save makes and a later edit of the file never leaves stale text behind it.
481
+ */
482
+ const migrateVerbatimItemStorageRow = async (childProperty, row) => {
483
+ const seedId = row.seedUid || childProperty.seedUid || row.seedLocalId || childProperty.seedLocalId;
484
+ if (!seedId || !row.localId)
485
+ return undefined;
486
+ const propertyDef = childProperty.propertyDef;
487
+ const converted = await main_cjs.convertVerbatimItemStorageRow(row.localId, {
488
+ seedId,
489
+ localStorageDir: propertyDef?.localStorageDir || row.localStorageDir,
490
+ filenameSuffix: propertyDef?.filenameSuffix,
491
+ });
492
+ if (!converted)
493
+ return undefined;
494
+ const { fileName, filePath, localStorageDir, content } = converted;
495
+ // The content is still the value: keep it as renderValue (the property may show it from propertyValue).
496
+ childProperty.getService().send({
497
+ type: 'updateContext',
498
+ refResolvedValue: fileName,
499
+ localStorageDir,
500
+ renderValue: content,
501
+ });
502
+ logger(`resolveItemStorageChildFile: wrote verbatim ${childProperty.propertyName} content to ${filePath}`);
503
+ return filePath;
504
+ };
505
+ /**
506
+ * Local file of one ItemStorage child of a composite upload. Tries, in order: the property's
507
+ * localStoragePath (context set by save / hydration / the live query), its newest metadata row's
508
+ * refResolvedValue + localStorageDir, then (for a local draft whose propertyValue is the content
509
+ * itself, as rows made before Item.create saved ItemStorage values) that content written to its
510
+ * file, then (for a local draft, or no row) the name
511
+ * saveItemStorage gives a new file (`<seedUid or seedLocalId><extension>` in the model's storage
512
+ * directory). A published or derived row is never swapped for a local file of another name: that
513
+ * file would be older content.
514
+ *
515
+ * `missingLocalEdit` lists the paths tried when nothing exists although the newest row is a saved
516
+ * local edit (no attestation uid, not derived from one, refResolvedValue set by saveItemStorage):
517
+ * that edit's file should be there. A published or derived row without a file (e.g. content not
518
+ * downloaded, or a property the composite never had) is skipped as before.
519
+ */
520
+ const resolveItemStorageChildFile = async (childProperty) => {
521
+ const tried = [];
522
+ const tryPath = async (filePath) => {
523
+ if (!isUsablePath(filePath) || tried.includes(filePath))
524
+ return undefined;
525
+ tried.push(filePath);
526
+ return (await main_cjs.BaseFileManager.pathExists(filePath)) ? filePath : undefined;
527
+ };
528
+ const fromContext = await tryPath(childProperty.localStoragePath);
529
+ if (fromContext)
530
+ return { filePath: fromContext };
531
+ const row = await getLatestItemStorageRow(childProperty).catch((error) => {
532
+ logger('resolveItemStorageChildFile: metadata lookup failed', error);
533
+ return undefined;
534
+ });
535
+ const propertyDef = childProperty.propertyDef;
536
+ const dir = main_cjs.getItemStorageSubdir(propertyDef?.localStorageDir || row?.localStorageDir);
537
+ if (row?.refResolvedValue) {
538
+ const fromRow = await tryPath(main_cjs.BaseFileManager.getFilesPath(dir, row.refResolvedValue));
539
+ if (fromRow)
540
+ return { filePath: fromRow };
541
+ }
542
+ const isLocalDraft = !!row && !row.uid && row.derivedFromUid == null;
543
+ // A local draft holding the content itself (no file reference): what Item.create / createNewItem
544
+ // stored for ItemStorage values before they went through the save pipeline. Write it to the file a
545
+ // save would have, point the row and the property at it, and upload that.
546
+ if (row && main_cjs.isVerbatimItemStorageDraftRow(row)) {
547
+ const migrated = await migrateVerbatimItemStorageRow(childProperty, row).catch((error) => {
548
+ logger('resolveItemStorageChildFile: writing verbatim ItemStorage content failed', error);
549
+ return undefined;
550
+ });
551
+ if (migrated)
552
+ return { filePath: migrated };
553
+ }
554
+ const suffix = propertyDef?.filenameSuffix;
555
+ const seedIds = !row || isLocalDraft
556
+ ? [row?.seedUid, childProperty.seedUid, row?.seedLocalId, childProperty.seedLocalId]
557
+ : [];
558
+ for (const seedId of seedIds) {
559
+ if (!seedId)
560
+ continue;
561
+ const derived = await tryPath(main_cjs.BaseFileManager.getFilesPath(dir, main_cjs.getItemStorageLocalFileName(seedId, suffix)));
562
+ if (derived)
563
+ return { filePath: derived };
564
+ }
565
+ // saveItemStorage sets refResolvedValue on the draft row once the file is written. A draft row
566
+ // without one is the empty row createNewItem makes for every model property: nothing to upload.
567
+ return isLocalDraft && !!row?.refResolvedValue ? { missingLocalEdit: tried } : {};
568
+ };
569
+ /**
570
+ * True if publish would include at least one Arweave upload (local file / storage seed present).
571
+ * Does not create Arweave transactions or hit the network — use for routing (e.g. skip EAS-only)
572
+ * when {@link getPublishUploads} would fail early (e.g. gateway unreachable during tx creation).
573
+ */
574
+ async function storageSeedHasUploadCandidates(itemStorageSeedProperties) {
575
+ for (const itemProperty of itemStorageSeedProperties) {
576
+ const snapshot = itemProperty.getService().getSnapshot();
577
+ const context = 'context' in snapshot ? snapshot.context : null;
578
+ if (!context) {
579
+ continue;
580
+ }
581
+ const propertyValue = context.propertyValue;
582
+ const refResolvedValue = context.refResolvedValue;
583
+ if (!refResolvedValue) {
584
+ continue;
585
+ }
586
+ const { seedLocalId } = main_cjs.resolveSeedIdsFromRefString(main_cjs.normalizeRelationPropertyValue(propertyValue) ?? '');
587
+ if (!seedLocalId) {
588
+ continue;
589
+ }
590
+ const dataType = itemProperty.propertyDef?.refValueType ??
591
+ itemProperty.propertyDef?.dataType ??
592
+ 'Image';
593
+ const baseDir = main_cjs.getStorageDirForDataType(dataType);
594
+ const filePath = `${baseDir}/${refResolvedValue}`;
595
+ if (await main_cjs.BaseFileManager.pathExists(filePath)) {
596
+ return true;
597
+ }
598
+ }
599
+ return false;
600
+ }
601
+ async function uploadPropertyWouldUpload(uploadProperty, relatedItemProperty) {
602
+ for (const childProperty of uploadProperty.childProperties) {
603
+ // Not strict: a local edit whose file is missing still means "would upload", so the publish
604
+ // goes ahead and fails loudly in processUploadPropertyData instead of skipping the upload.
605
+ const resolved = await resolveItemStorageChildFile(childProperty);
606
+ if (resolved.filePath || resolved.missingLocalEdit) {
607
+ return true;
608
+ }
609
+ }
610
+ if (relatedItemProperty && relatedItemProperty.localStoragePath) {
611
+ const filePath = relatedItemProperty.localStoragePath;
612
+ if (!filePath || filePath.endsWith('undefined')) {
613
+ return false;
614
+ }
615
+ return await main_cjs.BaseFileManager.pathExists(filePath);
616
+ }
617
+ return false;
618
+ }
619
+ async function itemOwnUploadCandidates(item, relatedItemProperty, recurseStorageRelations) {
620
+ const { itemUploadProperties, itemRelationProperties, itemImageProperties } = await publishDraftGraph.getSegmentedItemProperties(item);
621
+ for (const uploadProperty of itemUploadProperties) {
622
+ if (await uploadPropertyWouldUpload(uploadProperty, relatedItemProperty)) {
623
+ return true;
624
+ }
625
+ }
626
+ if (await storageSeedHasUploadCandidates(itemImageProperties)) {
627
+ return true;
628
+ }
629
+ if (!recurseStorageRelations)
630
+ return false;
631
+ const storageProperties = new Set(itemImageProperties);
632
+ for (const relationProperty of itemRelationProperties) {
633
+ if (!storageProperties.has(relationProperty))
634
+ continue;
635
+ const snapshot = relationProperty.getService().getSnapshot();
636
+ const context = 'context' in snapshot ? snapshot.context : null;
637
+ if (!context) {
638
+ continue;
639
+ }
640
+ const propertyValue = context.propertyValue;
641
+ if (!propertyValue || relationProperty.uid) {
642
+ continue;
643
+ }
644
+ const { seedLocalId, seedUid } = main_cjs.resolveSeedIdsFromRefString(main_cjs.normalizeRelationPropertyValue(propertyValue) ?? '');
645
+ if (!seedLocalId && !seedUid) {
646
+ throw new Error(`Invalid relation value for ${relationProperty.propertyName}: expected local seed id or 0x uid`);
647
+ }
648
+ const relatedItem = await main_cjs.Item.find({
649
+ seedLocalId,
650
+ seedUid,
651
+ });
652
+ if (!relatedItem) {
653
+ // Related seed referenced by attested uid with no local copy: already published, nothing to upload.
654
+ if (main_cjs.isPublishedSeedRef(propertyValue))
655
+ continue;
656
+ throw new Error(`No relatedItem found for ${relationProperty.propertyName}`);
657
+ }
658
+ if (await itemOwnUploadCandidates(relatedItem, relationProperty, false)) {
659
+ return true;
660
+ }
661
+ }
662
+ return false;
663
+ }
664
+ /** Same walk as getPublishUploads: the item and the draft items its publish carries along. */
665
+ async function itemHasPublishUploadCandidates(item, relatedItemProperty) {
666
+ if (await itemOwnUploadCandidates(item, relatedItemProperty, true))
667
+ return true;
668
+ const { drafts } = await publishDraftGraph.getPublishDraftGraph(item, { strict: true });
669
+ for (const { item: draft, via, viaList } of drafts) {
670
+ if (await itemOwnUploadCandidates(draft, viaList ? undefined : via, true))
671
+ return true;
672
+ }
673
+ return false;
674
+ }
675
+ const processUploadPropertyData = async (uploadProperty, uploads, relatedItemProperty, options) => {
676
+ const itemProperty = uploadProperty.itemProperty;
677
+ const childUploads = [];
678
+ for (const childProperty of uploadProperty.childProperties) {
679
+ const { filePath, missingLocalEdit } = await resolveItemStorageChildFile(childProperty);
680
+ if (!filePath) {
681
+ if (missingLocalEdit) {
682
+ // Uploading without it would publish a composite that silently lacks this edit.
683
+ throw new Error(`Cannot publish ${itemProperty.seedLocalId}: the local file for ${childProperty.propertyName} ` +
684
+ `was not found (looked in ${missingLocalEdit.join(', ')})`);
685
+ }
686
+ continue;
687
+ }
688
+ childUploads.push({
689
+ propertyName: childProperty.propertyName,
690
+ localStoragePath: filePath,
691
+ });
692
+ }
693
+ let fileContents;
694
+ let fileContentType;
695
+ if (!childUploads || childUploads.length === 0) {
696
+ if (relatedItemProperty && relatedItemProperty.localStoragePath) {
697
+ const filePath = relatedItemProperty.localStoragePath;
698
+ if (!filePath || filePath.endsWith('undefined')) {
699
+ return uploads;
700
+ }
701
+ const exists = await main_cjs.BaseFileManager.pathExists(filePath);
702
+ if (!exists) {
703
+ return uploads;
704
+ }
705
+ try {
706
+ const read = await readUploadFile(filePath);
707
+ fileContents = read.bytes;
708
+ fileContentType = read.contentType;
709
+ }
710
+ catch (e) {
711
+ const fs = await main_cjs.BaseFileManager.getFs();
712
+ fileContents = await toUint8Array(fs.readFileSync(filePath));
713
+ fileContentType = resolveUploadMimeType({ fileName: filePath, bytes: fileContents });
714
+ }
715
+ }
716
+ if (!fileContents) {
717
+ return uploads;
718
+ }
719
+ }
720
+ if (childUploads.length > 0) {
721
+ // Composite of the item's ItemStorage files; see helpers/compositeUpload.ts for the format.
722
+ // Children are read as bytes: a binary child is base64-framed instead of decoded as text.
723
+ const children = [];
724
+ const fs = await main_cjs.BaseFileManager.getFs();
725
+ for (const childUpload of childUploads) {
726
+ let childUploadContents;
727
+ try {
728
+ childUploadContents = await fs.promises.readFile(childUpload.localStoragePath);
729
+ }
730
+ catch (e) {
731
+ childUploadContents = fs.readFileSync(childUpload.localStoragePath);
732
+ }
733
+ children.push({
734
+ name: childUpload.propertyName,
735
+ bytes: typeof childUploadContents === 'string'
736
+ ? new TextEncoder().encode(childUploadContents)
737
+ : new Uint8Array(childUploadContents),
738
+ });
739
+ }
740
+ fileContents = encodeCompositeUpload(children);
741
+ }
742
+ if (!fileContents) {
743
+ throw new Error(`No file contents found for ${itemProperty.propertyName}`);
744
+ }
745
+ const uint8Array = new Uint8Array(fileContents);
746
+ let contentType;
747
+ if (childUploads.length === 0 && relatedItemProperty?.localStoragePath) {
748
+ contentType = fileContentType;
749
+ }
750
+ else if (childUploads.length > 0) {
751
+ contentType = 'application/octet-stream';
752
+ }
753
+ let itemPropertyLocalId = relatedItemProperty
754
+ ? relatedItemProperty.localId
755
+ : itemProperty.localId;
756
+ let itemPropertyName = relatedItemProperty
757
+ ? relatedItemProperty.propertyName
758
+ : itemProperty.propertyName;
759
+ uploads.push(buildPublishUploadData(uint8Array, contentType, {
760
+ itemPropertyName,
761
+ itemPropertyLocalId,
762
+ seedLocalId: itemProperty.seedLocalId,
763
+ versionLocalId: itemProperty.versionLocalId,
764
+ }, options));
765
+ return uploads;
766
+ };
767
+ /** No seed uid yet: a related item in this state is published together with the item. */
768
+ const isDraftItem = (item) => !item.seedUid || item.seedUid === '0x' + '0'.repeat(64);
769
+ /** One item's own uploads: its files, storage seeds, Html-embedded images, and the items its storage relations point at. */
770
+ const getItemOwnPublishUploadData = async (item, uploads, relatedItemProperty, options) => {
771
+ const { itemUploadProperties, itemRelationProperties, itemImageProperties } = await publishDraftGraph.getSegmentedItemProperties(item);
772
+ // Phase 2 of an embedded-image publish: only the deferred Html storage seeds, of this item and of
773
+ // the related items published with it (whose Html can embed images too).
774
+ const onlyDeferredHtml = !!options?.onlyHtmlStorageSeedLocalIds?.length;
775
+ if (onlyDeferredHtml) {
776
+ const storageSeedUploads = await getStorageSeedUploadData(itemImageProperties, options);
777
+ uploads.push(...storageSeedUploads);
778
+ }
779
+ else {
780
+ for (const uploadProperty of itemUploadProperties) {
781
+ uploads = await processUploadPropertyData(uploadProperty, uploads, relatedItemProperty, options);
782
+ }
783
+ const storageSeedUploads = await getStorageSeedUploadData(itemImageProperties, options);
784
+ uploads.push(...storageSeedUploads);
785
+ // Images embedded in this item's Html: the published item's, and a related draft's published with it.
786
+ if (!relatedItemProperty || isDraftItem(item)) {
787
+ uploads = await appendCoPublishedImageUploadData(item, uploads, options);
788
+ }
789
+ }
790
+ if (options?.skipRelationRecursion) {
791
+ return uploads;
792
+ }
793
+ // Relations to Image/File/Html/Json items: their file, read through the relation property.
794
+ const storageProperties = new Set(itemImageProperties);
795
+ for (const relationProperty of itemRelationProperties) {
796
+ if (!storageProperties.has(relationProperty))
797
+ continue;
798
+ const snapshot = relationProperty.getService().getSnapshot();
799
+ const context = 'context' in snapshot ? snapshot.context : null;
800
+ if (!context) {
801
+ continue;
802
+ }
803
+ const propertyValue = context.propertyValue;
804
+ if (!propertyValue || relationProperty.uid) {
805
+ continue;
806
+ }
807
+ const { seedLocalId, seedUid } = main_cjs.resolveSeedIdsFromRefString(main_cjs.normalizeRelationPropertyValue(propertyValue) ?? '');
808
+ if (!seedLocalId && !seedUid) {
809
+ throw new Error(`Invalid relation value for ${relationProperty.propertyName}: expected local seed id or 0x uid`);
810
+ }
811
+ const relatedItem = await main_cjs.Item.find({
812
+ seedLocalId,
813
+ seedUid,
814
+ });
815
+ if (!relatedItem) {
816
+ // Related seed referenced by attested uid with no local copy: already published, nothing to upload.
817
+ if (main_cjs.isPublishedSeedRef(propertyValue))
818
+ continue;
819
+ throw new Error(`No relatedItem found for ${relationProperty.propertyName}`);
820
+ }
821
+ uploads = await getItemOwnPublishUploadData(relatedItem, uploads, relationProperty, {
822
+ ...options,
823
+ skipRelationRecursion: true,
824
+ });
825
+ }
826
+ return uploads;
827
+ };
828
+ /**
829
+ * Upload data for a publish of `item`: its own, and that of every draft item the publish carries
830
+ * along (reachable through relation and list properties, see publishDraftGraph.ts). Raw bytes plus
831
+ * Content-SHA-256 / Content-Type / configured tags; no Arweave transaction is created, so this
832
+ * does not touch the network. The bundler path in `@seedprotocol/publish` signs these as
833
+ * DataItems; {@link getPublishUploads} turns them into L1 transactions.
834
+ */
835
+ const getPublishUploadData = async (item, uploads = [], relatedItemProperty, options) => {
836
+ uploads = await getItemOwnPublishUploadData(item, uploads, relatedItemProperty, options);
837
+ if (options?.skipRelationRecursion) {
838
+ return uploads;
839
+ }
840
+ const { drafts } = await publishDraftGraph.getPublishDraftGraph(item, { strict: true });
841
+ for (const { item: draft, via, viaList } of drafts) {
842
+ uploads = await getItemOwnPublishUploadData(draft, uploads, viaList ? undefined : via, options);
843
+ }
844
+ return uploads;
845
+ };
846
+ /**
847
+ * Arweave L1 transactions for a publish of `item`: {@link getPublishUploadData}, each made into an
848
+ * unsigned transaction carrying the same tags.
849
+ */
850
+ const getPublishUploads = async (item, uploads = [], relatedItemProperty, options) => {
851
+ const uploadData = await getPublishUploadData(item, [], relatedItemProperty, options);
852
+ // Each createTransaction fetches the price / anchor from the gateway: run a few at once.
853
+ const created = await mapWithConcurrency(uploadData, CREATE_TRANSACTION_CONCURRENCY, async (upload) => ({
854
+ itemPropertyName: upload.itemPropertyName,
855
+ itemPropertyLocalId: upload.itemPropertyLocalId,
856
+ seedLocalId: upload.seedLocalId,
857
+ versionLocalId: upload.versionLocalId,
858
+ transactionToSign: await arweave.BaseArweaveClient.createTransaction(upload.data, {
859
+ tags: upload.tags.length ? upload.tags : undefined,
860
+ }),
861
+ }));
862
+ uploads.push(...created);
863
+ return uploads;
864
+ };
865
+
866
+ exports.CREATE_TRANSACTION_CONCURRENCY = CREATE_TRANSACTION_CONCURRENCY;
867
+ exports.getPublishUploadData = getPublishUploadData;
868
+ exports.getPublishUploads = getPublishUploads;
869
+ exports.itemHasPublishUploadCandidates = itemHasPublishUploadCandidates;
870
+ exports.prepareArweaveTransaction = prepareArweaveTransaction;
871
+ exports.resolveItemStorageChildFile = resolveItemStorageChildFile;
872
+ //# sourceMappingURL=getPublishUploads-DsXY9S4U.js.map