@seedprotocol/sdk 0.1.47 → 0.1.48

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 (141) hide show
  1. package/dist/bin.js.map +1 -1
  2. package/dist/constants-BLctWkrn.js.map +1 -1
  3. package/dist/{index-DWf9Ls94.js → index-DMIKRod-.js} +3995 -3995
  4. package/dist/index-DMIKRod-.js.map +1 -0
  5. package/dist/{index-B2WbNudj.js → index-wKss7188.js} +10 -10
  6. package/dist/index-wKss7188.js.map +1 -0
  7. package/dist/main.js +7 -7
  8. package/dist/{seed.schema.config-mBqth17w.js → seed.schema.config-C0M8Rcti.js} +7 -7
  9. package/dist/seed.schema.config-C0M8Rcti.js.map +1 -0
  10. package/dist/src/AppStateSchema.ts +10 -0
  11. package/dist/src/Attestation.ts +21 -0
  12. package/dist/src/ConfigSchema.ts +15 -0
  13. package/dist/src/ItemProperty.ts +383 -0
  14. package/dist/src/MetadataSchema.ts +28 -0
  15. package/dist/src/ModelSchema.ts +46 -0
  16. package/dist/src/ModelUidSchema.ts +16 -0
  17. package/dist/src/PropertyUidSchema.ts +16 -0
  18. package/dist/src/Schema.ts +17 -0
  19. package/dist/src/SeedSchema.ts +29 -0
  20. package/dist/src/VersionSchema.ts +16 -0
  21. package/dist/src/actors.ts +10 -0
  22. package/dist/src/addModelsToDb.ts +150 -0
  23. package/dist/src/allItems.ts +23 -0
  24. package/dist/src/arweave.ts +37 -0
  25. package/dist/src/browser.app.db.config.ts +27 -0
  26. package/dist/src/browser.seed.db.config.ts +33 -0
  27. package/dist/src/browser.ts +30 -0
  28. package/dist/src/checkStatus.ts +50 -0
  29. package/dist/src/client.ts +85 -0
  30. package/dist/src/configureFs.ts +81 -0
  31. package/dist/src/connectToDb.ts +74 -0
  32. package/dist/src/connectionManager.ts +67 -0
  33. package/dist/src/constants.ts +118 -0
  34. package/dist/src/create.ts +39 -0
  35. package/dist/src/createItem.ts +15 -0
  36. package/dist/src/createItemMachine.ts +37 -0
  37. package/dist/src/createPublishAttempt.ts +16 -0
  38. package/dist/src/createSeeds.ts +24 -0
  39. package/dist/src/createVersion.ts +33 -0
  40. package/dist/src/db.ts +247 -0
  41. package/dist/src/dbMachine.ts +181 -0
  42. package/dist/src/deleteItem.ts +19 -0
  43. package/dist/src/download.ts +289 -0
  44. package/dist/src/drizzle.ts +82 -0
  45. package/dist/src/environment.ts +15 -0
  46. package/dist/src/eventBus.ts +5 -0
  47. package/dist/src/events.ts +14 -0
  48. package/dist/src/fetchDataFromEas.ts +90 -0
  49. package/dist/src/fetchDbData.ts +16 -0
  50. package/dist/src/fetchRelatedItems.ts +179 -0
  51. package/dist/src/fetchSeeds.ts +44 -0
  52. package/dist/src/fetchVersions.ts +41 -0
  53. package/dist/src/files.ts +16 -0
  54. package/dist/src/fragment-masking.ts +87 -0
  55. package/dist/src/fsProxy.ts +36 -0
  56. package/dist/src/getItem.ts +189 -0
  57. package/dist/src/getItemProperties.ts +162 -0
  58. package/dist/src/getItems.ts +75 -0
  59. package/dist/src/getMetadata.ts +40 -0
  60. package/dist/src/getModelSchemas.ts +88 -0
  61. package/dist/src/getSchemaForModel.ts +42 -0
  62. package/dist/src/getSeedData.ts +34 -0
  63. package/dist/src/getVersionData.ts +58 -0
  64. package/dist/src/getVersionsForVersionUids.ts +39 -0
  65. package/dist/src/globalMachine.ts +259 -0
  66. package/dist/src/gql.ts +113 -0
  67. package/dist/src/graphql.ts +3201 -0
  68. package/dist/src/helpers.ts +150 -0
  69. package/dist/src/hydrateExistingItem.ts +137 -0
  70. package/dist/src/hydrateFromDb.ts +254 -0
  71. package/dist/src/hydrateNewItem.ts +34 -0
  72. package/dist/src/index.d.ts +5 -0
  73. package/dist/src/index.ts +21 -0
  74. package/dist/src/init.ts +61 -0
  75. package/dist/src/initialize.ts +127 -0
  76. package/dist/src/internalMachine.ts +220 -0
  77. package/dist/src/item.ts +324 -0
  78. package/dist/src/itemMachineAll.ts +158 -0
  79. package/dist/src/itemMachineSingle.ts +175 -0
  80. package/dist/src/loadAppDb.ts +47 -0
  81. package/dist/src/logger.ts +33 -0
  82. package/dist/src/machine.ts +55 -0
  83. package/dist/src/machines.ts +58 -0
  84. package/dist/src/migrate.ts +288 -0
  85. package/dist/src/model.ts +71 -0
  86. package/dist/src/modelClass.ts +19 -0
  87. package/dist/src/node.app.db.config.ts +40 -0
  88. package/dist/src/prepareDb.ts +34 -0
  89. package/dist/src/preparePublishRequestData.ts +81 -0
  90. package/dist/src/processItems.ts +71 -0
  91. package/dist/src/property.ts +161 -0
  92. package/dist/src/propertyMachine.ts +154 -0
  93. package/dist/src/publish.ts +31 -0
  94. package/dist/src/publishMachine.ts +77 -0
  95. package/dist/src/queries.ts +13 -0
  96. package/dist/src/read.ts +174 -0
  97. package/dist/src/recoverDeletedItem.ts +14 -0
  98. package/dist/src/request.ts +54 -0
  99. package/dist/src/requestAll.ts +157 -0
  100. package/dist/src/resolveRelatedValue.ts +348 -0
  101. package/dist/src/resolveRemoteStorage.ts +87 -0
  102. package/dist/src/save.ts +183 -0
  103. package/dist/src/saveConfig.ts +79 -0
  104. package/dist/src/saveDataToDb.ts +145 -0
  105. package/dist/src/saveMetadata.ts +18 -0
  106. package/dist/src/saveValueToDb.ts +94 -0
  107. package/dist/src/seed.schema.config.ts +25 -0
  108. package/dist/src/seed.ts +37 -0
  109. package/dist/src/seedData.ts +0 -0
  110. package/dist/src/seedProtocol.ts +17 -0
  111. package/dist/src/services.ts +359 -0
  112. package/dist/src/sqlWasmClient.ts +88 -0
  113. package/dist/src/syncDbWithEas.ts +686 -0
  114. package/dist/src/trash.ts +29 -0
  115. package/dist/src/ts-to-proto.ts +101 -0
  116. package/dist/src/types.ts +12 -0
  117. package/dist/src/upload.ts +86 -0
  118. package/dist/src/validate.ts +42 -0
  119. package/dist/src/validateInput.ts +33 -0
  120. package/dist/src/validateItemData.ts +20 -0
  121. package/dist/src/waitForDb.ts +23 -0
  122. package/dist/src/wasm.d.ts +8300 -0
  123. package/dist/src/write.ts +366 -0
  124. package/dist/types/src/browser/db/read/getModelSchemas.d.ts.map +1 -1
  125. package/dist/types/src/browser/item/single/actors/hydrateExistingItem.d.ts +3 -1
  126. package/dist/types/src/browser/item/single/actors/hydrateExistingItem.d.ts.map +1 -1
  127. package/dist/types/src/browser/item/single/actors/saveDataToDb.d.ts +3 -3
  128. package/dist/types/src/browser/item/single/itemMachineSingle.d.ts +3 -3
  129. package/dist/types/src/browser/property/ItemProperty.d.ts +7 -7
  130. package/dist/types/src/browser/property/ItemProperty.d.ts.map +1 -1
  131. package/dist/types/src/browser/property/actors/resolveRemoteStorage.d.ts +3 -3
  132. package/dist/types/src/browser/react/trash.d.ts +1 -1
  133. package/dist/types/src/browser/react/trash.d.ts.map +1 -1
  134. package/dist/types/src/browser/services/db/dbMachine.d.ts +6 -6
  135. package/dist/types/src/browser/services/publish/publishMachine.d.ts +17 -17
  136. package/dist/types/src/types/machines.d.ts +4 -0
  137. package/dist/types/src/types/machines.d.ts.map +1 -1
  138. package/package.json +1 -1
  139. package/dist/index-B2WbNudj.js.map +0 -1
  140. package/dist/index-DWf9Ls94.js.map +0 -1
  141. package/dist/seed.schema.config-mBqth17w.js.map +0 -1
@@ -0,0 +1,181 @@
1
+ import { assign, emit, setup } from 'xstate'
2
+ import {
3
+ DB_CHECK_STATUS_EXISTS,
4
+ DB_CHECK_STATUS_UPDATE_PATHS,
5
+ DB_CREATING_SUCCESS,
6
+ DB_MIGRATING_SUCCESS,
7
+ DB_MIGRATING_WAIT,
8
+ DB_VALIDATING_SUCCESS,
9
+ DB_VALIDATING_WAIT,
10
+ DB_WAITING_FOR_FILES_RECEIVED,
11
+ DbState,
12
+ MachineIds,
13
+ } from '../internal/constants'
14
+ import debug from 'debug'
15
+ import { DbServiceContext } from '@/types'
16
+ import { checkStatus } from '@/browser/services/db/actors/checkStatus'
17
+ import { connectToDb } from '@/browser/services/db/actors/connectToDb'
18
+ import { validate } from '@/browser/services/db/actors/validate'
19
+ import { migrate } from '@/browser/services/db/actors/migrate'
20
+
21
+ const logger = debug('app:services:db:machine')
22
+
23
+ const {
24
+ CHECKING_STATUS,
25
+ VALIDATING,
26
+ WAITING_FOR_FILES,
27
+ CONNECTING_TO_DB,
28
+ MIGRATING,
29
+ } = DbState
30
+
31
+ const dbMachine = setup({
32
+ types: {
33
+ context: {} as Partial<DbServiceContext>,
34
+ input: {} as Partial<DbServiceContext> | undefined,
35
+ },
36
+ actors: {
37
+ checkStatus,
38
+ validate,
39
+ connectToDb,
40
+ migrate,
41
+ },
42
+ }).createMachine({
43
+ id: MachineIds.DB,
44
+ initial: CHECKING_STATUS,
45
+ context: ({ input }) => input as DbServiceContext,
46
+ on: {
47
+ [DB_WAITING_FOR_FILES_RECEIVED]: {
48
+ actions: assign({
49
+ hasFiles: ({ event }) => {
50
+ logger('[db/machine] DB_WAITING_FOR_FILES_RECEIVED event:', event)
51
+ return true
52
+ },
53
+ }),
54
+ },
55
+ updateHasFiles: {
56
+ target: `.${CHECKING_STATUS}`,
57
+ actions: assign({
58
+ hasFiles: ({ context, event }) => {
59
+ logger('[db/machine] updateHasFiles event:', event)
60
+ logger('[db/machine] updateHasFiles context:', context)
61
+ return event.hasFiles
62
+ },
63
+ }),
64
+ },
65
+ },
66
+ // always: {
67
+ // target: `.${CHECKING_STATUS}`,
68
+ // guard: ({ context, event }) => context.hasFiles && event.type === 'updateHasFiles',
69
+ // },
70
+ states: {
71
+ idle: {
72
+ on: {
73
+ start: CHECKING_STATUS,
74
+ },
75
+ meta: {
76
+ displayText: 'DB starting ...',
77
+ percentComplete: 0,
78
+ },
79
+ },
80
+ [CHECKING_STATUS]: {
81
+ on: {
82
+ [DB_CHECK_STATUS_UPDATE_PATHS]: {
83
+ actions: assign({
84
+ pathToDb: ({ event }) => event.pathToDb,
85
+ pathToDir: ({ event }) => event.pathToDir,
86
+ pathToDbDir: ({ event }) => event.pathToDbDir,
87
+ }),
88
+ },
89
+ [DB_CHECK_STATUS_EXISTS]: CONNECTING_TO_DB,
90
+ },
91
+ invoke: {
92
+ src: 'checkStatus',
93
+ input: ({ context, event }) => ({ context, event }),
94
+ },
95
+ meta: {
96
+ displayText: 'Checking DB status',
97
+ percentComplete: 60,
98
+ },
99
+ },
100
+ [CONNECTING_TO_DB]: {
101
+ on: {
102
+ [DB_CREATING_SUCCESS]: {
103
+ target: VALIDATING,
104
+ actions: assign({
105
+ dbId: ({ event }) => event.dbId,
106
+ }),
107
+ },
108
+ },
109
+ invoke: {
110
+ src: 'connectToDb',
111
+ input: ({ context }) => ({ context }),
112
+ },
113
+ meta: {
114
+ displayText: 'Connecting to local DB',
115
+ percentComplete: 70,
116
+ },
117
+ },
118
+ [VALIDATING]: {
119
+ on: {
120
+ [DB_VALIDATING_SUCCESS]: {
121
+ target: MIGRATING,
122
+ // guard: ({ context }) => context.hasFiles,
123
+ },
124
+ [DB_VALIDATING_WAIT]: {
125
+ target: WAITING_FOR_FILES,
126
+ // guard: ({ context }) => !context.hasFiles,
127
+ },
128
+ },
129
+ invoke: {
130
+ src: 'validate',
131
+ input: ({ context }) => ({ context }),
132
+ },
133
+ meta: {
134
+ displayText: 'Validating DB',
135
+ percentComplete: 80,
136
+ },
137
+ },
138
+ // Here we're waiting for migration and schema files to be downloaded
139
+ [WAITING_FOR_FILES]: {
140
+ on: {
141
+ [DB_WAITING_FOR_FILES_RECEIVED]: {
142
+ target: MIGRATING,
143
+ actions: assign({
144
+ hasFiles: true,
145
+ }),
146
+ },
147
+ [DB_MIGRATING_SUCCESS]: 'ready',
148
+ },
149
+ entry: ({ context }) => {
150
+ if (context.hasFiles) {
151
+ emit({ type: DB_WAITING_FOR_FILES_RECEIVED })
152
+ }
153
+ },
154
+ },
155
+ [MIGRATING]: {
156
+ on: {
157
+ [DB_MIGRATING_WAIT]: WAITING_FOR_FILES,
158
+ [DB_MIGRATING_SUCCESS]: {
159
+ target: 'ready',
160
+ },
161
+ },
162
+ invoke: {
163
+ src: 'migrate',
164
+ input: ({ context }) => ({ context }),
165
+ },
166
+ meta: {
167
+ displayText: 'Migrating DB',
168
+ percentComplete: 90,
169
+ },
170
+ },
171
+ ready: {
172
+ target: 'idle',
173
+ meta: {
174
+ displayText: 'Wrapping up the db ...',
175
+ percentComplete: 100,
176
+ },
177
+ },
178
+ },
179
+ })
180
+
181
+ export { dbMachine }
@@ -0,0 +1,19 @@
1
+ import { getAppDb } from '../sqlWasmClient'
2
+ import { seeds } from '@/shared/seedSchema'
3
+ import { eq, or } from 'drizzle-orm'
4
+
5
+ type DeleteItemProps = {
6
+ seedLocalId?: string
7
+ seedUid?: string
8
+ }
9
+ type DeleteItem = (props: DeleteItemProps) => Promise<void>
10
+ export const deleteItem: DeleteItem = async ({ seedLocalId, seedUid }) => {
11
+ const appDb = getAppDb()
12
+
13
+ await appDb
14
+ .update(seeds)
15
+ .set({
16
+ _markedForDeletion: 1,
17
+ })
18
+ .where(or(eq(seeds.localId, seedLocalId), eq(seeds.uid, seedUid)))
19
+ }
@@ -0,0 +1,289 @@
1
+ import { syncDbFiles } from '@/browser/services/internal/helpers'
2
+ import { eventEmitter } from '@/eventBus'
3
+ import { fs } from '@zenfs/core'
4
+ import { ARWEAVE_HOST } from '@/browser/services/internal/constants'
5
+ import { appState } from 'src/shared/seedSchema'
6
+ import { eq } from 'drizzle-orm'
7
+ import { getArweave } from '@/browser/schema/file'
8
+ import { getAddressesFromDb } from '@/shared/helpers/db'
9
+ import { getImageDataType, getMimeType, identifyString } from '@/shared/helpers'
10
+ import { arweaveClient, easClient, queryClient } from '@/browser/helpers'
11
+ import { GET_FILES_METADATA } from '@/browser/schema/file/queries'
12
+ import debug from 'debug'
13
+ import { getAppDb, isAppDbReady } from '@/browser/db/sqlWasmClient'
14
+ import { getGlobalService } from '@/browser/services'
15
+ import { waitFor } from 'xstate'
16
+ import { writeAppState } from '@/browser/db/write'
17
+ import { getMetadata } from '@/browser/db/read/getMetadata'
18
+ import { saveMetadata } from '@/browser/db/write/saveMetadata'
19
+ import { GET_TRANSACTION_TAGS } from '@/browser/arweave/queries'
20
+
21
+ const logger = debug('app:files:download')
22
+
23
+ export const downloadAllFilesRequestHandler = async ({
24
+ endpoints,
25
+ eventId,
26
+ }) => {
27
+ await syncDbFiles(endpoints)
28
+
29
+ eventEmitter.emit('fs.downloadAll.success', { eventId })
30
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints })
31
+ }
32
+
33
+ export const downloadAllFilesBinaryRequestHandler = async () => {
34
+ let addresses: string[] | undefined
35
+
36
+ if (isAppDbReady()) {
37
+ addresses = await getAddressesFromDb()
38
+ }
39
+
40
+ if (!isAppDbReady()) {
41
+ const globalService = getGlobalService()
42
+ const internalService = globalService.getSnapshot().context.internalService
43
+ if (internalService) {
44
+ await waitFor(internalService, (snapshot) => snapshot.value === 'ready')
45
+ addresses = await getAddressesFromDb()
46
+ }
47
+ }
48
+
49
+ if (!addresses || addresses.length === 0) {
50
+ return
51
+ }
52
+
53
+ const { filesMetadata } = await queryClient.fetchQuery({
54
+ queryKey: ['getFilesMetadata', ...addresses],
55
+ queryFn: async () =>
56
+ easClient.request(GET_FILES_METADATA, {
57
+ where: {
58
+ attester: {
59
+ in: addresses,
60
+ },
61
+ schema: {
62
+ is: {
63
+ id: {
64
+ equals:
65
+ '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
66
+ },
67
+ },
68
+ },
69
+ },
70
+ }),
71
+ })
72
+
73
+ if (!(await fs.promises.exists('/files'))) {
74
+ await fs.promises.mkdir('/files', { recursive: true })
75
+ }
76
+
77
+ if (!(await fs.promises.exists('/files/html'))) {
78
+ await fs.promises.mkdir('/files/html', { recursive: true })
79
+ }
80
+
81
+ if (!(await fs.promises.exists('/files/json'))) {
82
+ await fs.promises.mkdir('/files/json', { recursive: true })
83
+ }
84
+
85
+ if (!(await fs.promises.exists('/files/images'))) {
86
+ await fs.promises.mkdir('/files/images', { recursive: true })
87
+ }
88
+
89
+ const appDb = getAppDb()
90
+
91
+ if (!appDb) {
92
+ console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available')
93
+ return []
94
+ }
95
+
96
+ for (const fileMetadata of filesMetadata) {
97
+ const json = JSON.parse(fileMetadata.decodedDataJson)
98
+ const transactionId = json[0].value.value
99
+
100
+ const excludedTransactionsQuery = await appDb
101
+ .select()
102
+ .from(appState)
103
+ .where(eq(appState.key, 'excludedTransactions'))
104
+
105
+ let excludedTransactions = new Set<string>()
106
+
107
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
108
+ const valueString = excludedTransactionsQuery[0].value
109
+ if (valueString) {
110
+ const excludedTransactionsArray = JSON.parse(valueString)
111
+ excludedTransactions = new Set(excludedTransactionsArray)
112
+ }
113
+ }
114
+
115
+ if (excludedTransactions.has(transactionId)) {
116
+ continue
117
+ }
118
+
119
+ const arweave = getArweave()
120
+
121
+ if (!arweave) {
122
+ console.warn(
123
+ '[fetchAll/actors] [fetchAllBinaryData] arweave not available',
124
+ )
125
+ return []
126
+ }
127
+
128
+ try {
129
+ const res = await fetch(
130
+ `https://${ARWEAVE_HOST}/tx/${transactionId}/status`,
131
+ )
132
+
133
+ if (res.status !== 200) {
134
+ logger(
135
+ `[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`,
136
+ )
137
+
138
+ excludedTransactions.add(transactionId)
139
+
140
+ await writeAppState(
141
+ 'excludedTransactions',
142
+ JSON.stringify(Array.from(excludedTransactions)),
143
+ )
144
+
145
+ continue
146
+ }
147
+
148
+ const { tags } = await queryClient.fetchQuery({
149
+ queryKey: ['getTransactionTags', transactionId],
150
+ queryFn: async () =>
151
+ arweaveClient.request(GET_TRANSACTION_TAGS, {
152
+ transactionId,
153
+ }),
154
+ })
155
+
156
+ if (tags && tags.length === 0) {
157
+ for (const { name, value } of tags) {
158
+ if (name === 'Content-SHA-256') {
159
+ const metadataRecord = await getMetadata({
160
+ storageTransactionId: transactionId,
161
+ })
162
+
163
+ if (metadataRecord) {
164
+ await saveMetadata(metadataRecord, {
165
+ contentHash: value,
166
+ })
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ const fetchResponse = await queryClient.fetchQuery({
173
+ queryKey: ['fetchTransaction', transactionId],
174
+ queryFn: async () =>
175
+ fetch(`https://${ARWEAVE_HOST}/raw/${transactionId}`),
176
+ })
177
+
178
+ const dataString = await fetchResponse.text()
179
+
180
+ // const dataString = await arweave.transactions.getData(transactionId, {
181
+ // decode: true,
182
+ // string: true,
183
+ // })
184
+
185
+ if (!dataString) {
186
+ logger(
187
+ `[fetchAll/actors] [fetchAllBinaryData] transaction ${transactionId} data not found`,
188
+ )
189
+ }
190
+
191
+ let contentType = identifyString(dataString)
192
+ if (
193
+ contentType !== 'json' &&
194
+ contentType !== 'base64' &&
195
+ contentType !== 'html'
196
+ ) {
197
+ const possibleImageType = getImageDataType(dataString)
198
+ if (!possibleImageType) {
199
+ logger(
200
+ `[fetchAll/actors] [fetchAllBinaryData] transaction ${transactionId} data not in expected format: ${possibleImageType}`,
201
+ )
202
+ continue
203
+ }
204
+
205
+ contentType = possibleImageType
206
+ }
207
+
208
+ if (contentType === 'url') {
209
+ const url = dataString as string
210
+ const response = await fetch(url)
211
+ if (!response.ok) {
212
+ throw new Error(`Failed to fetch image: ${response.statusText}`)
213
+ }
214
+
215
+ // Get the image as a Blob
216
+ const blob = await response.blob()
217
+ const buffer = await blob.arrayBuffer()
218
+ const bufferUint8Array = new Uint8Array(buffer)
219
+
220
+ // Extract the file extension from the URL
221
+ const extensionMatch = url.match(/\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i)
222
+ if (!extensionMatch) {
223
+ throw new Error(
224
+ 'Unable to determine the file extension from the URL.',
225
+ )
226
+ }
227
+ const fileExtension = extensionMatch[0] // e.g., ".jpg"
228
+
229
+ // Set the file name (you can customize this)
230
+ // const fileNameFromUrl = `${transactionId}${fileExtension}`
231
+
232
+ await fs.promises.writeFile(
233
+ `/files/images/${transactionId}`,
234
+ bufferUint8Array,
235
+ {
236
+ encoding: 'binary',
237
+ },
238
+ )
239
+
240
+ continue
241
+ }
242
+
243
+ const mimeType = getMimeType(dataString as string)
244
+
245
+ let fileName = transactionId
246
+
247
+ if (contentType === 'base64') {
248
+ if (mimeType) {
249
+ fileName += `.${mimeType}`
250
+ }
251
+
252
+ // Remove the Base64 header if it exists (e.g., "data:image/png;base64,")
253
+ const base64Data = dataString.split(',').pop() || ''
254
+
255
+ // Decode the Base64 string to binary
256
+ const binaryString = atob(base64Data)
257
+ const length = binaryString.length
258
+ const binaryData = new Uint8Array(length)
259
+
260
+ for (let i = 0; i < length; i++) {
261
+ binaryData[i] = binaryString.charCodeAt(i)
262
+ }
263
+
264
+ await fs.promises.writeFile(`/files/images/${fileName}`, binaryData, {
265
+ encoding: 'binary',
266
+ })
267
+
268
+ // if (dataUint8Array && dataUint8Array instanceof Uint8Array) {
269
+ // await fs.promises.writeFile(
270
+ // `/files/images/${fileName}`,
271
+ // dataUint8Array,
272
+ // )
273
+ // }
274
+ }
275
+
276
+ if (contentType === 'html') {
277
+ fileName += '.html'
278
+ await fs.promises.writeFile(`/files/html/${fileName}`, dataString)
279
+ }
280
+
281
+ if (contentType === 'json') {
282
+ fileName += '.json'
283
+ await fs.promises.writeFile(`/files/json/${fileName}`, dataString)
284
+ }
285
+ } catch (error) {
286
+ logger(error)
287
+ }
288
+ }
289
+ }
@@ -0,0 +1,82 @@
1
+ import path from 'path'
2
+ import fs from 'fs'
3
+ import pluralize from 'pluralize'
4
+ import { camelCase, snakeCase } from 'lodash-es'
5
+ import * as nunjucks from 'nunjucks'
6
+ import { ILoader } from 'nunjucks'
7
+ import { ModelClassType } from '@/types'
8
+ import { SCHEMA_NJK } from '@/shared/helpers/constants'
9
+ import {
10
+ appGeneratedSchemaDir,
11
+ dotSeedDir,
12
+ templatePath,
13
+ } from '@/node/constants'
14
+ import { getTsImport } from '@/node/helpers'
15
+
16
+ const TemplateLoader: ILoader = {
17
+ getSource: (name: string) => {
18
+ let templateFilePath
19
+ if (name.includes(templatePath)) {
20
+ templateFilePath = name
21
+ } else {
22
+ templateFilePath = path.join(templatePath, path.basename(name))
23
+ }
24
+ const src = fs.readFileSync(templateFilePath, 'utf-8')
25
+
26
+ return {
27
+ path: name,
28
+ src,
29
+ noCache: false,
30
+ }
31
+ },
32
+ }
33
+
34
+ // Configure Nunjucks
35
+ const env = new nunjucks.Environment(TemplateLoader)
36
+
37
+ env.addFilter('camelCase', camelCase)
38
+ env.addFilter('snakeCase', snakeCase)
39
+ env.addFilter('pluralize', pluralize)
40
+
41
+ const generateDrizzleSchemaCode = (
42
+ modelName: string,
43
+ modelClass: ModelClassType,
44
+ ): string => {
45
+ const listProperties = Object.entries(modelClass.schema).filter(
46
+ ([key, propertyDef]) => propertyDef?.dataType === 'List',
47
+ )
48
+
49
+ const filePath = path.join(templatePath, SCHEMA_NJK)
50
+
51
+ const schemaCode = env.render(filePath, {
52
+ modelName,
53
+ modelClass,
54
+ listProperties,
55
+ })
56
+
57
+ return schemaCode
58
+ }
59
+
60
+ export const createDrizzleSchemaFilesFromConfig = async () => {
61
+ const schemaFilePath = path.join(dotSeedDir, 'schema.ts') // Developer created file with model definitions
62
+
63
+ console.log('schemaFilePath:', schemaFilePath)
64
+
65
+ const { models } = await getTsImport<{
66
+ models: Record<string, ModelClassType>
67
+ }>(schemaFilePath)
68
+
69
+ console.log('models:', models)
70
+
71
+ for (const [modelName, modelClass] of Object.entries(models)) {
72
+ const code = generateDrizzleSchemaCode(modelName, modelClass)
73
+
74
+ if (!fs.existsSync(appGeneratedSchemaDir)) {
75
+ fs.mkdirSync(appGeneratedSchemaDir)
76
+ }
77
+
78
+ const filePath = path.join(appGeneratedSchemaDir, `${modelName}Schema.ts`)
79
+
80
+ await fs.promises.writeFile(filePath, code).catch((e) => console.error(e))
81
+ }
82
+ }
@@ -0,0 +1,15 @@
1
+ export const isNode = (): boolean => {
2
+ return (
3
+ typeof process !== 'undefined' &&
4
+ process.versions != null &&
5
+ process.versions.node != null
6
+ )
7
+ }
8
+
9
+ export const isBrowser = (): boolean => {
10
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined'
11
+ }
12
+
13
+ export const isReactNative = (): boolean => {
14
+ return typeof navigator !== 'undefined' && navigator.product === 'ReactNative'
15
+ }
@@ -0,0 +1,5 @@
1
+ import EventEmitter from 'eventemitter3'
2
+
3
+ const eventEmitter = new EventEmitter()
4
+
5
+ export { eventEmitter }
@@ -0,0 +1,14 @@
1
+ import { eventEmitter } from '@/eventBus'
2
+ import debug from 'debug'
3
+
4
+ const logger = debug('app:services:events')
5
+
6
+ const handleServiceSaveState = (event: any) => {
7
+ const { state, serviceId } = event
8
+ logger(`[browser] [service.saveState.request] serviceId: ${serviceId}`)
9
+ localStorage.setItem(`seed_sdk_service_${serviceId}`, JSON.stringify(state))
10
+ }
11
+
12
+ export const setupServicesEventHandlers = () => {
13
+ eventEmitter.addListener('service.saveState.request', handleServiceSaveState)
14
+ }
@@ -0,0 +1,90 @@
1
+ import { EventObject, fromCallback } from 'xstate'
2
+ import { GET_PROPERTIES } from '@/browser/item/queries'
3
+ import { itemMachineSingle } from '@/browser/item/single/itemMachineSingle'
4
+ import { PropertyType } from '@/shared/seedSchema'
5
+ import { easClient, queryClient } from '@/browser/helpers'
6
+ import { Attestation } from '@/browser/gql/graphql'
7
+ import { ModelClassType } from '@/types'
8
+
9
+ export const fetchDataFromEas = fromCallback<
10
+ EventObject,
11
+ typeof itemMachineSingle
12
+ >(({ sendBack, input: { context } }) => {
13
+ const { ModelClass, modelTableName, versionUid } = context
14
+
15
+ const propertiesMetadata = new Map<string, PropertyType>()
16
+
17
+ // EAS is the final source of truth, so we need to see if our Item is
18
+ // already represented there. Then we need to intelligently sync/merge
19
+ // with whatever new data has been created on the device before the sync.
20
+ for (const [propertyName, propertyMetadata] of Object.entries(
21
+ (ModelClass as ModelClassType).schema,
22
+ )) {
23
+ if (propertyMetadata) {
24
+ propertiesMetadata.set(propertyName, propertyMetadata)
25
+ }
26
+ }
27
+
28
+ sendBack({ type: 'updatePropertiesMetadata', propertiesMetadata })
29
+
30
+ if (!versionUid) {
31
+ // In this case this is a local only item, so we don't need to fetch anything
32
+ return
33
+ }
34
+
35
+ const _fetchDataFromEas = async (): Promise<void> => {
36
+ // Fetch Properties by versionUid
37
+ const { itemProperties } = await queryClient.fetchQuery({
38
+ queryKey: ['getProperties', versionUid],
39
+ queryFn: async () =>
40
+ easClient.request(GET_PROPERTIES, {
41
+ where: {
42
+ refUID: {
43
+ in: [versionUid],
44
+ },
45
+ decodedDataJson: {
46
+ not: {
47
+ // The first of many filters to keep bad data out
48
+ contains:
49
+ '"value":"0x0000000000000000000000000000000000000000000000000000000000000020"',
50
+ },
51
+ },
52
+ },
53
+ }),
54
+ })
55
+
56
+ // Filter properties by schemaId
57
+ const selectedPropertiesMap: {
58
+ [schemaId: string]: Attestation[]
59
+ } = {}
60
+ itemProperties.forEach((property) => {
61
+ const existingProperties = selectedPropertiesMap[property.schemaId] || []
62
+ existingProperties.push(property)
63
+ selectedPropertiesMap[property.schemaId] = existingProperties
64
+ })
65
+
66
+ // For each schemaId, sort property Attestations by timeCreated DESC
67
+ Object.keys(selectedPropertiesMap).forEach((schemaId) => {
68
+ const sorted = selectedPropertiesMap[schemaId].sort((a, b) => {
69
+ return a.timeCreated - b.timeCreated
70
+ })
71
+ selectedPropertiesMap[schemaId] = sorted
72
+ })
73
+
74
+ Object.keys(selectedPropertiesMap).forEach((schemaId) => {
75
+ // TODO: Finish this logic
76
+ // console.log('[singleItemActors] [fetchDataFromEas] schemaId', schemaId)
77
+ // sendBack({ type: 'addPropertyAttestation', schemaId })
78
+ })
79
+
80
+ // Attach processed properties to the itemService/itemMachine context
81
+ sendBack({
82
+ type: 'updatedPropertiesBySchemaUid',
83
+ propertiesBySchemaUid: selectedPropertiesMap,
84
+ })
85
+ }
86
+
87
+ _fetchDataFromEas().then(() => {
88
+ sendBack({ type: 'fetchDataFromEasSuccess' })
89
+ })
90
+ })