@adobe/aio-lib-db 0.1.0-alpha.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.
@@ -0,0 +1,425 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ const { apiPost } = require("../../utils/apiRequest")
13
+
14
+ /**
15
+ * Make a post request to the App Builder Database Service collection API and return the result
16
+ *
17
+ * @param {DbBase} db
18
+ * @param {string} collectionName
19
+ * @param {string} endpoint
20
+ * @param {Object=} params
21
+ * @param {Object=} options
22
+ * @param {AxiosInstance=} axiosClient
23
+ * @returns {Promise<*>}
24
+ * @throws {DbError}
25
+ */
26
+ async function postCollectionApi(db, collectionName, endpoint, params = {}, options = {}, axiosClient = undefined) {
27
+ if (!axiosClient) {
28
+ axiosClient = db.axiosClient
29
+ }
30
+ return await apiPost(db, axiosClient, `collection/${collectionName}/${endpoint}`, params, options)
31
+ }
32
+
33
+ /**
34
+ * Insert a single document into the collection
35
+ *
36
+ * @param {DbBase} db
37
+ * @param {string} collectionName
38
+ * @param {Object} document
39
+ * @param {Object=} options
40
+ * @returns {Promise<Object>}
41
+ * @throws {DbError}
42
+ */
43
+ async function insertOne(db, collectionName, document, options = {}) {
44
+ return await postCollectionApi(db, collectionName, 'insertOne', { document: document }, options)
45
+ }
46
+
47
+ /**
48
+ * Inserts multiple documents into the collection
49
+ *
50
+ * @param {DbBase} db
51
+ * @param {string} collectionName
52
+ * @param {Object[]} documents
53
+ * @param {Object=} options
54
+ * @returns {Promise<Object>}
55
+ * @throws {DbError}
56
+ */
57
+ async function insertMany(db, collectionName, documents, options = {}) {
58
+ return await postCollectionApi(db, collectionName, 'insertMany', { documents: documents }, options)
59
+ }
60
+
61
+ /**
62
+ * Retrieve the first document that matches the filter
63
+ *
64
+ * @param {DbBase} db
65
+ * @param {string} collectionName
66
+ * @param {Object} filter
67
+ * @param {Object=} options
68
+ * @returns {Promise<Object>}
69
+ * @throws {DbError}
70
+ */
71
+ async function findOne(db, collectionName, filter, options = {}) {
72
+ return await postCollectionApi(db, collectionName, 'findOne', { filter: filter }, options)
73
+ }
74
+
75
+ /**
76
+ * Update and return the first document that matches the filter
77
+ *
78
+ * @param {DbBase} db
79
+ * @param {string} collectionName
80
+ * @param {Object} filter
81
+ * @param {Object} update
82
+ * @param {Object=} options
83
+ * @returns {Promise<Object>}
84
+ * @throws {DbError}
85
+ */
86
+ async function findOneAndUpdate(db, collectionName, filter, update, options = {}) {
87
+ return await postCollectionApi(db, collectionName, 'findOneAndUpdate', { filter: filter, update: update }, options)
88
+ }
89
+
90
+ /**
91
+ * Replace and return the first document that matches the filter
92
+ *
93
+ * @param {DbBase} db
94
+ * @param {string} collectionName
95
+ * @param {Object} filter
96
+ * @param {Object} replacement
97
+ * @param {Object=} options
98
+ * @returns {Promise<Object>}
99
+ * @throws {DbError}
100
+ */
101
+ async function findOneAndReplace(db, collectionName, filter, replacement, options = {}) {
102
+ return await postCollectionApi(
103
+ db,
104
+ collectionName,
105
+ 'findOneAndReplace',
106
+ { filter: filter, replacement: replacement },
107
+ options
108
+ )
109
+ }
110
+
111
+ /**
112
+ * Delete and return the first document that matches the filter
113
+ *
114
+ * @param {DbBase} db
115
+ * @param {string} collectionName
116
+ * @param {Object} filter
117
+ * @param {Object=} options
118
+ * @returns {Promise<Object>}
119
+ * @throws {DbError}
120
+ */
121
+ async function findOneAndDelete(db, collectionName, filter, options = {}) {
122
+ return await postCollectionApi(db, collectionName, 'findOneAndDelete', { filter: filter }, options)
123
+ }
124
+
125
+ /**
126
+ * Finds the first batch of documents that match the filter and return them as an array.
127
+ * Does not allow retrieving more than one batch of results.
128
+ *
129
+ * @param {DbBase} db
130
+ * @param {string} collectionName
131
+ * @param {Object=} filter
132
+ * @param {Object=} options
133
+ * @returns {Object[]}
134
+ * @throws {DbError}
135
+ */
136
+ async function findArray(db, collectionName, filter, options = {}) {
137
+ return await postCollectionApi(db, collectionName, 'findArray', { filter: filter }, options)
138
+ }
139
+
140
+ /**
141
+ * Update the first document that matches the filter
142
+ *
143
+ * @param {DbBase} db
144
+ * @param {string} collectionName
145
+ * @param {Object} filter
146
+ * @param {Object} update
147
+ * @param {Object=} options
148
+ * @returns {Promise<Object>}
149
+ * @throws {DbError}
150
+ */
151
+ async function updateOne(db, collectionName, filter, update, options = {}) {
152
+ return await postCollectionApi(db, collectionName, 'updateOne', { filter: filter, update: update }, options)
153
+ }
154
+
155
+ /**
156
+ * Updates all documents that match the filter
157
+ *
158
+ * @param {DbBase} db
159
+ * @param {string} collectionName
160
+ * @param {Object} filter
161
+ * @param {Object} update
162
+ * @param {Object=} options
163
+ * @returns {Promise<Object>}
164
+ * @throws {DbError}
165
+ */
166
+ async function updateMany(db, collectionName, filter, update, options = {}) {
167
+ return await postCollectionApi(db, collectionName, 'updateMany', { filter: filter, update: update }, options)
168
+ }
169
+
170
+ /**
171
+ * Replace the first document that matches the filter
172
+ *
173
+ * @param {DbBase} db
174
+ * @param {string} collectionName
175
+ * @param {Object} filter
176
+ * @param {Object} replacement
177
+ * @param {Object=} options
178
+ * @returns {Promise<Object>}
179
+ * @throws {DbError}
180
+ */
181
+ async function replaceOne(db, collectionName, filter, replacement, options = {}) {
182
+ return await postCollectionApi(
183
+ db,
184
+ collectionName,
185
+ 'replaceOne',
186
+ { filter: filter, replacement: replacement },
187
+ options
188
+ )
189
+ }
190
+
191
+ /**
192
+ * Delete the first document that matches the filter
193
+ *
194
+ * @param {DbBase} db
195
+ * @param {string} collectionName
196
+ * @param {Object} filter
197
+ * @param {Object=} options
198
+ * @returns {Promise<Object>}
199
+ * @throws {DbError}
200
+ */
201
+ async function deleteOne(db, collectionName, filter, options = {}) {
202
+ return await postCollectionApi(db, collectionName, 'deleteOne', { filter: filter }, options)
203
+ }
204
+
205
+ /**
206
+ * Deletes all documents that match the filter
207
+ *
208
+ * @param {DbBase} db
209
+ * @param {string} collectionName
210
+ * @param {Object} filter
211
+ * @param {Object=} options
212
+ * @returns {Promise<Object>}
213
+ * @throws {DbError}
214
+ */
215
+ async function deleteMany(db, collectionName, filter, options = {}) {
216
+ return await postCollectionApi(db, collectionName, 'deleteMany', { filter: filter }, options)
217
+ }
218
+
219
+ /**
220
+ * Execute multiple insert/update/delete commands in one operation
221
+ *
222
+ * @param {DbBase} db
223
+ * @param {string} collectionName
224
+ * @param {Object[]} operations
225
+ * @param {Object=} options
226
+ * @returns {Promise<Object>}
227
+ * @throws {DbError}
228
+ */
229
+ async function bulkWrite(db, collectionName, operations, options = {}) {
230
+ return await postCollectionApi(db, collectionName, 'bulkWrite', { operations: operations }, options)
231
+ }
232
+
233
+ /**
234
+ * Find all documents that match the filter
235
+ *
236
+ * @param {DbBase} db
237
+ * @param {AxiosInstance} axiosClient
238
+ * @param {string} collectionName
239
+ * @param {Object=} filter
240
+ * @param {Object=} options
241
+ * @returns {Promise<Object>}
242
+ * @throws {DbError}
243
+ */
244
+ async function find(db, axiosClient, collectionName, filter = {}, options = {}) {
245
+ return await postCollectionApi(db, collectionName, 'find', { filter: filter }, options, axiosClient)
246
+ }
247
+
248
+ /**
249
+ * Executes an aggregation pipeline over the documents in a collection
250
+ *
251
+ * @param {DbBase} db
252
+ * @param {AxiosInstance} axiosClient
253
+ * @param {string} collectionName
254
+ * @param {Object[]=} pipeline
255
+ * @param {Object=} options
256
+ * @returns {Promise<Object>}
257
+ * @throws {DbError}
258
+ */
259
+ async function aggregate(db, axiosClient, collectionName, pipeline = [], options = {}) {
260
+ return await postCollectionApi(db, collectionName, 'aggregate', { pipeline: pipeline }, options, axiosClient)
261
+ }
262
+
263
+ /**
264
+ * Get more results from a cursor
265
+ *
266
+ * @param {DbBase} db
267
+ * @param {AxiosInstance} axiosClient
268
+ * @param {string} collectionName
269
+ * @param {(import('bson').Long|number)} cursorId
270
+ * @param {Object=} options
271
+ * @return {Promise<*>}
272
+ */
273
+ async function getMore(db, axiosClient, collectionName, cursorId, options = {}) {
274
+ return await postCollectionApi(db, collectionName, 'getMore', { cursorId: cursorId }, options, axiosClient)
275
+ }
276
+
277
+ /**
278
+ * Get the list of indexes from the collection
279
+ *
280
+ * @param {DbBase} db
281
+ * @param {string} collectionName
282
+ * @returns {Promise<Object[]>}
283
+ * @throws {DbError}
284
+ */
285
+ async function getIndexes(db, collectionName) {
286
+ return await postCollectionApi(db, collectionName, 'getIndexes')
287
+ }
288
+
289
+ /**
290
+ * Create an index with the provided specification
291
+ *
292
+ * @param {DbBase} db
293
+ * @param {string} collectionName
294
+ * @param {Object} specification
295
+ * @param {Object=} options
296
+ * @returns {Promise<Object>}
297
+ * @throws {DbError}
298
+ */
299
+ async function createIndex(db, collectionName, specification, options = {}) {
300
+ return await postCollectionApi(db, collectionName, 'createIndex', { specification: specification }, options)
301
+ }
302
+
303
+ /**
304
+ * Drop the index with the provided name
305
+ *
306
+ * @param {DbBase} db
307
+ * @param {string} collectionName
308
+ * @param {string} index
309
+ * @param {Object=} options
310
+ * @returns {Promise<Object>}
311
+ * @throws {DbError}
312
+ */
313
+ async function dropIndex(db, collectionName, index, options = {}) {
314
+ return await postCollectionApi(db, collectionName, 'dropIndex', { index: index }, options)
315
+ }
316
+
317
+ /**
318
+ * Find all distinct values for a field, optionally applying a filter
319
+ *
320
+ * @param {DbBase} db
321
+ * @param {string} collectionName
322
+ * @param {(Object|string)} field
323
+ * @param {Object=} filter
324
+ * @param {Object=} options
325
+ * @returns {Promise<*[]>}
326
+ * @throws {DbError}
327
+ */
328
+ async function distinct(db, collectionName, field, filter = {}, options = {}) {
329
+ return await postCollectionApi(db, collectionName, 'distinct', { field: field, filter: filter }, options)
330
+ }
331
+
332
+ /**
333
+ * Count the number of documents in a collection, optionally applying a filter
334
+ *
335
+ * @param {DbBase} db
336
+ * @param {string} collectionName
337
+ * @param {Object=} filter
338
+ * @param {Object=} options
339
+ * @returns {Promise<number>}
340
+ * @throws {DbError}
341
+ */
342
+ async function countDocuments(db, collectionName, filter = {}, options = {}) {
343
+ return await postCollectionApi(db, collectionName, 'countDocuments', { filter: filter }, options)
344
+ }
345
+
346
+ /**
347
+ * Estimates the number of documents in a collection based on collection metadata
348
+ *
349
+ * @param {DbBase} db
350
+ * @param {string} collectionName
351
+ * @param {Object=} options
352
+ * @returns {Promise<number>}
353
+ * @throws {DbError}
354
+ */
355
+ async function estimatedDocumentCount(db, collectionName, options = {}) {
356
+ return await postCollectionApi(db, collectionName, 'estimatedDocumentCount', {}, options)
357
+ }
358
+
359
+ /**
360
+ * Drop this collection from the database
361
+ *
362
+ * @param {DbBase} db
363
+ * @param {string} collectionName
364
+ * @param {Object=} options
365
+ * @returns {Promise<void>}
366
+ * @throws {DbError}
367
+ */
368
+ async function drop(db, collectionName, options = {}) {
369
+ await postCollectionApi(db, collectionName, 'drop', undefined, options)
370
+ }
371
+
372
+ /**
373
+ * Rename this collection
374
+ *
375
+ * @param {DbBase} db
376
+ * @param {string} collectionName
377
+ * @param {string} newCollectionName
378
+ * @param {Object=} options
379
+ * @returns {Promise<void>}
380
+ * @throws {DbError}
381
+ */
382
+ async function renameCollection(db, collectionName, newCollectionName, options = {}) {
383
+ await postCollectionApi(db, collectionName, 'renameCollection', { name: newCollectionName }, options)
384
+ }
385
+
386
+ /**
387
+ * Get collection statistics
388
+ *
389
+ * @param {DbBase} db
390
+ * @param {string} collectionName
391
+ * @param {Object=} options
392
+ * @returns {Promise<Object>}
393
+ * @throws {DbError}
394
+ */
395
+ async function stats(db, collectionName, options = {}) {
396
+ return await postCollectionApi(db, collectionName, 'stats', undefined, options)
397
+ }
398
+
399
+ module.exports = {
400
+ insertOneApi: insertOne,
401
+ insertManyApi: insertMany,
402
+ findOneApi: findOne,
403
+ findOneAndUpdateApi: findOneAndUpdate,
404
+ findOneAndReplaceApi: findOneAndReplace,
405
+ findOneAndDeleteApi: findOneAndDelete,
406
+ findArrayApi: findArray,
407
+ updateOneApi: updateOne,
408
+ updateManyApi: updateMany,
409
+ replaceOneApi: replaceOne,
410
+ deleteOneApi: deleteOne,
411
+ deleteManyApi: deleteMany,
412
+ bulkWriteApi: bulkWrite,
413
+ findApi: find,
414
+ aggregateApi: aggregate,
415
+ getMoreApi: getMore,
416
+ getIndexesApi: getIndexes,
417
+ createIndexApi: createIndex,
418
+ dropIndexApi: dropIndex,
419
+ distinctApi: distinct,
420
+ countDocumentsApi: countDocuments,
421
+ estimatedDocumentCountApi: estimatedDocumentCount,
422
+ dropApi: drop,
423
+ renameCollectionApi: renameCollection,
424
+ statsApi: stats
425
+ }
package/lib/api/db.js ADDED
@@ -0,0 +1,90 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ const { apiPost, apiGet } = require("../../utils/apiRequest")
13
+
14
+ /**
15
+ * Make a post request to the App Builder Database Service db API and return the result
16
+ *
17
+ * @param {DbBase} db
18
+ * @param {AxiosInstance} axiosClient
19
+ * @param {string} endpoint
20
+ * @param {Object=} params
21
+ * @param {Object=} options
22
+ * @returns {Promise<*>}
23
+ * @throws {DbError}
24
+ */
25
+ async function postDbApi(db, axiosClient, endpoint, params = {}, options = {}) {
26
+ return await apiPost(db, axiosClient, `db/${endpoint}`, params, options)
27
+ }
28
+
29
+ /**
30
+ * Make a get request to the App Builder Database Service db API and return the result
31
+ *
32
+ * @param {DbBase} db
33
+ * @param {string} endpoint
34
+ * @returns {Promise<*>}
35
+ * @throws {DbError}
36
+ */
37
+ async function getDbApi(db, endpoint) {
38
+ return await apiGet(db, db.axiosClient, `db/${endpoint}`)
39
+ }
40
+
41
+ /**
42
+ * Submit a request to provision a new database for the current runtime namespace
43
+ *
44
+ * @param {DbBase} db
45
+ * @returns {Promise<Object>}
46
+ * @throws {DbError}
47
+ */
48
+ async function provisionRequest(db) {
49
+ return await postDbApi(db, db.axiosClient, 'provision/request')
50
+ }
51
+
52
+ /**
53
+ * Gets the provisioning status for the current runtime namespace
54
+ *
55
+ * @param {DbBase} db
56
+ * @returns {Promise<Object>}
57
+ * @throws {DbError}
58
+ */
59
+ async function provisionStatus(db) {
60
+ return await postDbApi(db, db.axiosClient, 'provision/status')
61
+ }
62
+
63
+ /**
64
+ * Checks connectivity with the App Builder Database Service
65
+ *
66
+ * @param {DbBase} db
67
+ * @returns {Promise<Object>}
68
+ * @throws {DbError}
69
+ */
70
+ async function ping(db) {
71
+ return await getDbApi(db, 'ping')
72
+ }
73
+
74
+ /**
75
+ * Delete the tenant database for the current runtime namespace
76
+ *
77
+ * @param {DbBase} db
78
+ * @returns {Promise<Object>}
79
+ * @throws {DbError}
80
+ */
81
+ async function deleteDatabase(db) {
82
+ return await postDbApi(db, db.axiosClient, 'delete')
83
+ }
84
+
85
+ module.exports = {
86
+ provisionRequestApi: provisionRequest,
87
+ provisionStatusApi: provisionStatus,
88
+ pingApi: ping,
89
+ deleteDatabaseApi: deleteDatabase
90
+ }
@@ -0,0 +1,44 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ require('dotenv/config')
13
+
14
+ const RUNTIME_HEADER = 'x-runtime-namespace'
15
+ const REQUEST_ID_HEADER = 'x-request-id'
16
+
17
+ const CURSOR_INIT_ERR_MESSAGE = 'Cursor has already been initialized, cannot modify request.'
18
+
19
+ const PROD_ENV = 'prod'
20
+ const STAGE_ENV = 'stage'
21
+
22
+ const ALLOWED_REGIONS = {
23
+ // First region in an environment's array is the default
24
+ [PROD_ENV]: ['amer', 'emea', 'apac'],
25
+ [STAGE_ENV]: ['amer', 'amer2']
26
+ }
27
+
28
+ // For stage we use the public endpoints for interacting with Production I/O runtime as connecting
29
+ // cross envs is not allowed in MCT.
30
+ const STAGE_ENDPOINT = 'https://storage-database-<region>.stg.app-builder.adp.adobe.io'
31
+ const PROD_ENDPOINT_RUNTIME = 'https://storage-database-<region>.app-builder.int.adp.adobe.io'
32
+ const PROD_ENDPOINT_EXTERNAL = 'https://storage-database-<region>.app-builder.adp.adobe.io'
33
+
34
+ module.exports = {
35
+ RUNTIME_HEADER,
36
+ REQUEST_ID_HEADER,
37
+ CURSOR_INIT_ERR_MESSAGE,
38
+ PROD_ENV,
39
+ STAGE_ENV,
40
+ ALLOWED_REGIONS,
41
+ STAGE_ENDPOINT,
42
+ PROD_ENDPOINT_RUNTIME,
43
+ PROD_ENDPOINT_EXTERNAL
44
+ }
package/lib/init.js ADDED
@@ -0,0 +1,35 @@
1
+ /*
2
+ Copyright 2025 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+ const DbBase = require('./DbBase')
13
+ require('dotenv/config')
14
+
15
+ /* *********************************** helpers & init() *********************************** */
16
+
17
+ /**
18
+ * Initializes and returns the ADP Storage Database SDK.
19
+ *
20
+ * To use the SDK you must either provide your OpenWhisk credentials in `config.ow` or in the environment variables
21
+ * `__OW_NAMESPACE` and `__OW_API_KEY`.
22
+ *
23
+ * @param {Object=} [config] used to init the sdk
24
+ * @param {('amer'|'apac'|'emea')=} [config.region] optional region to use, default: `amer`
25
+ * @param {Object=} [config.ow] Set those if you want to use ootb credentials to access the database service
26
+ * @param {string=} [config.ow.namespace]
27
+ * @param {string=} [config.ow.auth]
28
+ * @returns {Promise<DbBase>} A DbBase instance
29
+ */
30
+ async function init (config = {}) {
31
+ const { auth: apikey, namespace } = (config.ow ?? {})
32
+ return DbBase.init({ apikey, namespace, region: config.region })
33
+ }
34
+
35
+ module.exports = { init }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@adobe/aio-lib-db",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "An abstraction on top of Document DB storage",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "jest --passWithNoTests"
8
+ },
9
+ "exports": {
10
+ ".": "./index.js"
11
+ },
12
+ "author": "Adobe Inc.",
13
+ "license": "Apache-2.0",
14
+ "maintainers": [
15
+ "Adobe Inc."
16
+ ],
17
+ "contributors": [],
18
+ "dependencies": {
19
+ "@adobe/aio-lib-env": "^3.0.1",
20
+ "axios": "^1.8.4",
21
+ "bson": "^6.10.3",
22
+ "dotenv": "^17.0.0",
23
+ "http-cookie-agent": "^7.0.1",
24
+ "tough-cookie": "^5.1.2"
25
+ },
26
+ "devDependencies": {
27
+ "jest": "^30.0.0",
28
+ "uuid": "^11.1.0"
29
+ },
30
+ "keywords": [
31
+ "adobe",
32
+ "aio",
33
+ "database",
34
+ "document-db",
35
+ "mongodb",
36
+ "runtime",
37
+ "adobe-io",
38
+ "serverless"
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/adobe/aio-lib-db.git"
43
+ },
44
+ "bugs": "https://github.com/adobe/aio-lib-db/issues",
45
+ "homepage": "https://github.com/adobe/aio-lib-db#readme",
46
+ "funding": {
47
+ "type": "individual",
48
+ "url": "https://github.com/sponsors/adobe"
49
+ },
50
+ "engines": {
51
+ "node": ">=20"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ }
56
+ }