@storecraft/sdk 0.1.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/storage.js CHANGED
@@ -4,7 +4,7 @@ import { fetchOnlyApiResponseWithAuth } from './utils.api.fetch.js'
4
4
 
5
5
  /**
6
6
  *
7
- * `Storecraft` storage service.
7
+ * @description `Storecraft` storage service.
8
8
  *
9
9
  * Supports:
10
10
  * - direct `downloads` / `uploads`
@@ -16,7 +16,7 @@ export default class Storage {
16
16
 
17
17
  /**
18
18
  * @type {{
19
- * features: import('@storecraft/core/v-storage').StorageFeatures
19
+ * features: import('@storecraft/core/storage').StorageFeatures
20
20
  * }}
21
21
  */
22
22
  #cache = {
@@ -32,11 +32,11 @@ export default class Storage {
32
32
 
33
33
  /**
34
34
  *
35
- * Retrieve the `features` of `storage`, which informs:
35
+ * @description Retrieve the `features` of `storage`, which informs:
36
36
  * - Does `storage` supports `pre-signed` urls for `download` / `upload`
37
37
  *
38
38
  *
39
- * @returns {Promise<import('@storecraft/core/v-storage').StorageFeatures>}
39
+ * @returns {Promise<import('@storecraft/core/storage').StorageFeatures>}
40
40
  */
41
41
  features = async () => {
42
42
  if(this.#cache.features)
@@ -71,14 +71,14 @@ export default class Storage {
71
71
  }
72
72
 
73
73
  /**
74
- * Get a blob from `storage` driver with `presigned` urls
74
+ * @description Get a blob from `storage` driver with `presigned` urls
75
75
  *
76
76
  * @param {string} key file path key,
77
77
  * examples `image.png`, `collections/thumb.jpeg`
78
78
  *
79
79
  * @return {Promise<Blob>}
80
80
  *
81
- * @throws {import('@storecraft/core/v-api').error}
81
+ * @throws {import('@storecraft/core/api').error}
82
82
  */
83
83
  getBlobSigned = async (key) => {
84
84
 
@@ -98,7 +98,7 @@ export default class Storage {
98
98
 
99
99
  // `presigned` url instructions
100
100
  if(ctype === 'application/json') {
101
- /** @type {import('@storecraft/core/v-storage').StorageSignedOperation} */
101
+ /** @type {import('@storecraft/core/storage').StorageSignedOperation} */
102
102
  const presigned_req = await r.json();
103
103
 
104
104
  const presigned_res = await fetch(
@@ -116,14 +116,14 @@ export default class Storage {
116
116
  }
117
117
 
118
118
  /**
119
- * Get a blob from `storage` driver, straight download. (Not recommended)
119
+ * @description Get a blob from `storage` driver, straight download. (Not recommended)
120
120
  *
121
121
  * @param {string} key file path key,
122
122
  * examples `image.png`, `collections/thumb.jpeg`
123
123
  *
124
124
  * @return {Promise<Blob>}
125
125
  *
126
- * @throws {import('@storecraft/core/v-api').error}
126
+ * @throws {import('@storecraft/core/api').error}
127
127
  */
128
128
  getBlobUnsigned = async (key) => {
129
129
 
@@ -145,14 +145,14 @@ export default class Storage {
145
145
  }
146
146
 
147
147
  /**
148
- * Get a blob from `storage` driver.
148
+ * @description Get a blob from `storage` driver.
149
149
  *
150
150
  * @param {string} key file path key,
151
151
  * examples `image.png`, `collections/thumb.jpeg`
152
152
  *
153
153
  * @return {Promise<Blob>}
154
154
  *
155
- * @throws {import('@storecraft/core/v-api').error}
155
+ * @throws {import('@storecraft/core/api').error}
156
156
  */
157
157
  getBlob = async (key) => {
158
158
 
@@ -177,7 +177,7 @@ export default class Storage {
177
177
  this.getBlob(path).then(blob => URL.createObjectURL(blob));
178
178
 
179
179
  /**
180
- * get file source by inspecting the url:
180
+ * @description get file source by inspecting the url:
181
181
  *
182
182
  * - If it starts with `storage://`, then use `backend`
183
183
  * storage service, to download and convert it to encoded
@@ -214,7 +214,7 @@ export default class Storage {
214
214
 
215
215
 
216
216
  /**
217
- * Put a blob into `storage` driver with `presigned` urls
217
+ * @description Put a blob into `storage` driver with `presigned` urls
218
218
  *
219
219
  * @param {string} key file path key,
220
220
  * examples `image.png`, `collections/thumb.jpeg`
@@ -238,7 +238,7 @@ export default class Storage {
238
238
 
239
239
  // `presigned` url instructions
240
240
  if(ctype === 'application/json') {
241
- /** @type {import('@storecraft/core/v-storage').StorageSignedOperation} */
241
+ /** @type {import('@storecraft/core/storage').StorageSignedOperation} */
242
242
  const presigned_req = await r.json();
243
243
  const presigned_res = await fetch(
244
244
  presigned_req.url,
@@ -256,7 +256,7 @@ export default class Storage {
256
256
  }
257
257
 
258
258
  /**
259
- * Put a blob into `storage` driver with direct `upload` (Not Recommended)
259
+ * @description Put a blob into `storage` driver with direct `upload` (Not Recommended)
260
260
  *
261
261
  * @param {string} key file path key,
262
262
  * examples `image.png`, `collections/thumb.jpeg`
@@ -286,7 +286,7 @@ export default class Storage {
286
286
  }
287
287
 
288
288
  /**
289
- * Put bytes into `storage` driver.
289
+ * @description Put bytes into `storage` driver.
290
290
  *
291
291
  * @param {string} key file path key,
292
292
  * examples `image.png`, `collections/thumb.jpeg`
@@ -294,7 +294,7 @@ export default class Storage {
294
294
  *
295
295
  * @return {Promise<boolean>}
296
296
  *
297
- * @throws {import('@storecraft/core/v-api').error}
297
+ * @throws {import('@storecraft/core/api').error}
298
298
  */
299
299
  putBytes = async (key, data) => {
300
300
 
@@ -307,7 +307,7 @@ export default class Storage {
307
307
  }
308
308
 
309
309
  /**
310
- * Delete a `file` by key
310
+ * @description Delete a `file` by key
311
311
  *
312
312
  * @param {string} key file path key,
313
313
  * examples `image.png`, `collections/thumb.jpeg`
@@ -1,12 +1,12 @@
1
1
  import { StorecraftSDK } from '../index.js'
2
- import { collection_base } from './utils.api.fetch.js';
2
+ import { collection_base, fetchApiWithAuth } from './utils.api.fetch.js';
3
3
 
4
4
  /**
5
- * Base `storefronts` **CRUD**
5
+ * @description Base `storefronts` **CRUD**
6
6
  *
7
7
  * @extends {collection_base<
8
- * import('@storecraft/core/v-api').StorefrontTypeUpsert,
9
- * import('@storecraft/core/v-api').StorefrontType>
8
+ * import('@storecraft/core/api').StorefrontTypeUpsert,
9
+ * import('@storecraft/core/api').StorefrontType>
10
10
  * }
11
11
  */
12
12
  export default class Storefronts extends collection_base {
@@ -20,94 +20,23 @@ export default class Storefronts extends collection_base {
20
20
  }
21
21
 
22
22
  /**
23
+ * @description Export a storefront into the `storage`. This is
24
+ * beneficial for `collections`, that hardly change and therefore can be
25
+ * efficiently stored in a cost-effective `storage` and **CDN** network.
23
26
  *
24
- * @param {StorefrontData} sf_data
27
+ * @param {import('@storecraft/core/database').HandleOrId} handle_or_id
25
28
  */
26
- publish = async (sf_data) => {
27
- sf_data = {...sf_data}
28
- try {
29
- // Gather products
30
- let products = await Promise.all(
31
- sf_data.products.map(
32
- async id => await this.context.products.get(id)
33
- )
34
- )
35
- sf_data.products = delete_keys('search', 'createdAt')(
36
- products.map(p => p[2])
37
- )
38
- } catch(e) {
39
- throw 'products export error: ' + String(e)
40
- }
29
+ publish = async (handle_or_id) => {
41
30
 
42
- /**
43
- * @param {Handle[]} sf_data_entry
44
- * @param {string} collectionId
45
- * @param {(any) => any} filter_fn
46
- */
47
- const collect = async (sf_data_entry, collectionId, filter_fn=_=>true) => {
48
- try {
49
- // Gather collections
50
- const has_all = sf_data_entry?.some(c => c==='ALL')
51
- let items = []
52
- if(has_all) {
53
- items = await this.context[collectionId].list()
54
- items = items.map(c => c[1]).filter(filter_fn)
55
- }
56
- else {
57
- items = sf_data_entry?.map(
58
- async id => {
59
- const [_, __, coll] = await this.context[collectionId].get(id)
60
- return coll
61
- }
62
- )
63
- items = await Promise.all(items ?? [])
64
- }
65
- items = delete_keys('search')(items)
66
- return items
67
- } catch(e) {
68
- throw `${collectionId} export error: ` + String(e)
31
+ const result = await fetchApiWithAuth(
32
+ this.sdk,
33
+ `storefronts/${handle_or_id}/export`,
34
+ {
35
+ method: 'post'
69
36
  }
70
- }
37
+ );
71
38
 
72
- sf_data.collections = await collect(
73
- sf_data.collections, 'collections',
74
- c => c?.active || c?.active===undefined
75
- )
76
- sf_data.shipping_methods = await collect(
77
- sf_data.shipping_methods, 'shipping_methods',
78
- c => c?.active || c?.active===undefined
79
- )
80
- sf_data.posts = await collect(
81
- sf_data.posts, 'posts'
82
- )
83
- sf_data.discounts = await collect(
84
- sf_data.discounts, 'discounts',
85
- dis => dis.application.id===DiscountApplicationEnum.Auto.id && dis.enabled
86
- )
87
-
88
- try {
89
- // Upload to bucket
90
- const [url, ref] = await this.context.storage.uploadBytes(
91
- `storefronts/${sf_data.handle}.json`,
92
- pako.gzip(JSON.stringify(sf_data)),
93
- {
94
- contentType: 'application/json',
95
- contentEncoding: 'gzip',
96
- // cacheControl: `no-cache`
97
- cacheControl: `public, max-age=${60*60*1}, must-revalidate`
98
- }
99
- )
100
- await this.update(
101
- sf_data.handle,
102
- { _published: url }
103
- )
104
-
105
- // console.log(url, ref);
106
- } catch(e) {
107
- throw 'Upload export error: ' + String(e)
108
- }
109
-
110
- console.log('sf_data ', sf_data);
39
+ return result
111
40
  }
112
41
 
113
42
  }
package/src/tags.js CHANGED
@@ -2,11 +2,11 @@ import { StorecraftSDK } from '../index.js'
2
2
  import { collection_base } from './utils.api.fetch.js';
3
3
 
4
4
  /**
5
- * Base `tags` **CRUD**
5
+ * @description Base `tags` **CRUD**
6
6
  *
7
7
  * @extends {collection_base<
8
- * import('@storecraft/core/v-api').TagTypeUpsert,
9
- * import('@storecraft/core/v-api').TagType>
8
+ * import('@storecraft/core/api').TagTypeUpsert,
9
+ * import('@storecraft/core/api').TagType>
10
10
  * }
11
11
  */
12
12
  export default class Tags extends collection_base {
package/src/templates.js CHANGED
@@ -2,11 +2,11 @@ import { StorecraftSDK } from '../index.js'
2
2
  import { collection_base } from './utils.api.fetch.js';
3
3
 
4
4
  /**
5
- * Base `templates` **CRUD**
5
+ * @description Base `templates` **CRUD**
6
6
  *
7
7
  * @extends {collection_base<
8
- * import('@storecraft/core/v-api').TemplateTypeUpsert,
9
- * import('@storecraft/core/v-api').TemplateType>
8
+ * import('@storecraft/core/api').TemplateTypeUpsert,
9
+ * import('@storecraft/core/api').TemplateType>
10
10
  * }
11
11
  */
12
12
  export default class Templates extends collection_base {
@@ -1,7 +1,7 @@
1
1
 
2
2
  import {
3
3
  api_query_to_searchparams
4
- } from '@storecraft/core/v-api/utils.query.js';
4
+ } from '@storecraft/core/api/utils.query.js';
5
5
  import { assert } from './utils.functional.js';
6
6
 
7
7
 
@@ -21,6 +21,7 @@ export const url = (config, path) => {
21
21
 
22
22
 
23
23
  /**
24
+ * @description
24
25
  * - Prepends `backend` endpoint.
25
26
  * - Fetches with `authentication` middleware.
26
27
  * - Refreshed `auth` if needed.
@@ -61,6 +62,7 @@ export const fetchOnlyApiResponseWithAuth = async (sdk, path, init={}) => {
61
62
 
62
63
 
63
64
  /**
65
+ * @description
64
66
  * - Prepends `backend` endpoint.
65
67
  * - Fetches with `authentication` middleware.
66
68
  * - Refreshed `auth` if needed.
@@ -74,7 +76,7 @@ export const fetchOnlyApiResponseWithAuth = async (sdk, path, init={}) => {
74
76
  * @param {RequestInit} [init] request `init` type
75
77
  *
76
78
  *
77
- * @throws {import('@storecraft/core/v-api').error}
79
+ * @throws {import('@storecraft/core/api').error}
78
80
  *
79
81
  * @returns {Promise<R>}
80
82
  */
@@ -181,7 +183,7 @@ export async function remove(sdk, resource, handle_or_id) {
181
183
  *
182
184
  * @param {import('../index.js').StorecraftSDK} sdk
183
185
  * @param {string} resource base path of resource
184
- * @param {import('@storecraft/core/v-api').ApiQuery} [query]
186
+ * @param {import('@storecraft/core/api').ApiQuery} [query]
185
187
  *
186
188
  *
187
189
  * @returns {Promise<G[]>}
@@ -201,8 +203,7 @@ export async function list(sdk, resource, query={}) {
201
203
 
202
204
 
203
205
  /**
204
- * A simple resource base `class` with `CRUD` helpers
205
- *
206
+ * @description A simple resource base `class` with `CRUD` helpers
206
207
  *
207
208
  * @template {any} U upsert type
208
209
  * @template {any} G get type
@@ -261,7 +262,7 @@ export class collection_base {
261
262
 
262
263
  /**
263
264
  *
264
- * @param {import('@storecraft/core/v-api').ApiQuery} query Query object
265
+ * @param {import('@storecraft/core/api').ApiQuery} query Query object
265
266
  *
266
267
  *
267
268
  * @returns {Promise<G[]>}
package/types.d.ts CHANGED
@@ -1 +1 @@
1
- export * from './index.js'
1
+ export * from './index.js';
package/src/bots.js DELETED
@@ -1,113 +0,0 @@
1
- import { StorecraftSDK } from '../index.js'
2
-
3
- export const SECOND = 1000
4
- export const MINUTE = SECOND*60
5
-
6
-
7
- /**
8
- * @typedef {object} BotMetaData
9
- * @property {number} updatedAt
10
- *
11
- */
12
-
13
- const NAME = 'bots'
14
-
15
- export default class Bots {
16
-
17
- /**
18
- * @param {StorecraftSDK} context
19
- */
20
- constructor(context) {
21
- this.context = context
22
- this.db = context.db
23
- }
24
-
25
- init = async () => {
26
- // this.activitySpy()
27
- this.activityBot()
28
- setInterval(
29
- this.activityBot,
30
- MINUTE*10
31
- )
32
- }
33
-
34
- activityBot = async () => {
35
- // console.trace()
36
- try {
37
- const db = this.db.firebaseDB
38
- const result = await runTransaction(
39
- this.db.firebaseDB,
40
- async t => {
41
- const now = Date.now()
42
- const ref = doc(db, NAME, 'shelf-activity-bot')
43
- const m = await t.get(ref)
44
- const updatedAt = m.data()?.updatedAt ?? 0
45
-
46
- const q = {
47
- where: [
48
- ['updatedAt', '>', updatedAt]
49
- ]
50
- }
51
-
52
- const cols = ['collections', 'products', 'users', 'tags', 'discounts']
53
- const results = cols.map(
54
- async c => [c, await this.db.col(c).count(q)]
55
- )
56
-
57
- t.set(
58
- m.ref,
59
- {
60
- updatedAt: now
61
- }
62
- )
63
-
64
- return await Promise.all(results)
65
-
66
- },
67
- {
68
- maxAttempts: 1
69
- }
70
- )
71
-
72
- let filtered = result.filter(
73
- it => it[1]
74
- )
75
-
76
- if(filtered.length==0)
77
- return
78
-
79
- const search = filtered.map(it => it[0])
80
- const messages = filtered.map(
81
- it => {
82
- const [c, count] = it
83
- return `\n* 🚀 **${count}** \`${c}\` were updated`
84
- }
85
- );
86
-
87
- const message = ["**Latest Activity updates**", ...messages].join(' ')
88
- /**@type {NotificationData} */
89
- const noti = {
90
- message,
91
- search,
92
- author: 'shelf-activity-bot 🤖',
93
- updatedAt: Date.now()
94
- }
95
-
96
- // console.log(messages)
97
- // console.log(message)
98
-
99
- await this.context.notifications.add(
100
- noti
101
- )
102
-
103
- } catch (e) {
104
- // failed because another the document updated from another client
105
- // this is ok
106
- console.log(e)
107
- }
108
-
109
-
110
-
111
- }
112
-
113
- }