Compare commits

...

22 Commits

Author SHA1 Message Date
df0a439def 3.0.14 2024-06-11 17:20:49 +02:00
7245b49c31 fix(core): update 2024-06-11 17:20:48 +02:00
4b70edb947 finish trash 2024-06-10 16:47:20 +02:00
9629a04da6 3.0.13 2024-06-09 16:32:33 +02:00
963463d40d fix(core): update 2024-06-09 16:32:32 +02:00
ce58b99fc7 3.0.12 2024-06-09 16:02:34 +02:00
591c99736d fix(core): update 2024-06-09 16:02:33 +02:00
559e3da47b 3.0.11 2024-06-08 19:13:25 +02:00
a7ac870e05 fix(core): update 2024-06-08 19:13:24 +02:00
d48c5e229a 3.0.10 2024-06-03 21:35:08 +02:00
b9c384dd08 fix(core): update 2024-06-03 21:35:08 +02:00
91c04b2364 update description 2024-05-29 14:11:54 +02:00
b5dcc131e2 3.0.9 2024-05-27 17:34:27 +02:00
cb0ab2c9db fix(core): update 2024-05-27 17:34:26 +02:00
2a17ee542e 3.0.8 2024-05-27 14:34:13 +02:00
95e9d2f0ff fix(core): update 2024-05-27 14:34:12 +02:00
1a71c76da3 3.0.7 2024-05-27 12:56:26 +02:00
e924511147 fix(s3 paths): pathing differences now correctly handled in a reducePath method. 2024-05-27 12:56:25 +02:00
645ebbdd4d 3.0.6 2024-05-21 18:47:00 +02:00
168148b2c9 fix(core): update 2024-05-21 18:46:59 +02:00
1293fc4ca6 3.0.5 2024-05-21 18:42:55 +02:00
b040120813 fix(core): update 2024-05-21 18:42:55 +02:00
15 changed files with 623 additions and 213 deletions

View File

@ -8,25 +8,28 @@
"githost": "code.foss.global", "githost": "code.foss.global",
"gitscope": "push.rocks", "gitscope": "push.rocks",
"gitrepo": "smartbucket", "gitrepo": "smartbucket",
"description": "A TypeScript library that offers simple, cloud-independent object storage with features like bucket creation, file management, and directory management.", "description": "A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.",
"npmPackagename": "@push.rocks/smartbucket", "npmPackagename": "@push.rocks/smartbucket",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
"TypeScript",
"cloud storage", "cloud storage",
"object storage", "object storage",
"TypeScript", "bucket creation",
"S3",
"minio",
"file management", "file management",
"directory management", "directory management",
"bucket creation",
"data streaming", "data streaming",
"multi-cloud", "multi-cloud",
"API", "API",
"unified storage", "unified storage",
"S3",
"minio",
"file locking",
"metadata",
"buffer handling", "buffer handling",
"access key", "access key",
"secret key" "secret key",
"cloud agnostic"
] ]
} }
}, },

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "@push.rocks/smartbucket", "name": "@push.rocks/smartbucket",
"version": "3.0.4", "version": "3.0.14",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@push.rocks/smartbucket", "name": "@push.rocks/smartbucket",
"version": "3.0.4", "version": "3.0.14",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^5.0.18",

View File

@ -1,7 +1,7 @@
{ {
"name": "@push.rocks/smartbucket", "name": "@push.rocks/smartbucket",
"version": "3.0.4", "version": "3.0.14",
"description": "A TypeScript library that offers simple, cloud-independent object storage with features like bucket creation, file management, and directory management.", "description": "A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
"type": "module", "type": "module",
@ -19,12 +19,14 @@
"@push.rocks/tapbundle": "^5.0.23" "@push.rocks/tapbundle": "^5.0.23"
}, },
"dependencies": { "dependencies": {
"@push.rocks/smartmime": "^2.0.0", "@push.rocks/smartmime": "^2.0.2",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.3", "@push.rocks/smartpromise": "^4.0.3",
"@push.rocks/smartrx": "^3.0.7", "@push.rocks/smartrx": "^3.0.7",
"@push.rocks/smartstream": "^3.0.38", "@push.rocks/smartstream": "^3.0.44",
"@tsclass/tsclass": "^4.0.54", "@push.rocks/smartstring": "^4.0.15",
"@push.rocks/smartunique": "^3.0.9",
"@tsclass/tsclass": "^4.0.55",
"minio": "^8.0.0" "minio": "^8.0.0"
}, },
"private": false, "private": false,
@ -44,20 +46,28 @@
"last 1 chrome versions" "last 1 chrome versions"
], ],
"keywords": [ "keywords": [
"TypeScript",
"cloud storage", "cloud storage",
"object storage", "object storage",
"TypeScript", "bucket creation",
"S3",
"minio",
"file management", "file management",
"directory management", "directory management",
"bucket creation",
"data streaming", "data streaming",
"multi-cloud", "multi-cloud",
"API", "API",
"unified storage", "unified storage",
"S3",
"minio",
"file locking",
"metadata",
"buffer handling", "buffer handling",
"access key", "access key",
"secret key" "secret key",
] "cloud agnostic"
],
"homepage": "https://code.foss.global/push.rocks/smartbucket",
"repository": {
"type": "git",
"url": "https://code.foss.global/push.rocks/smartbucket.git"
}
} }

81
pnpm-lock.yaml generated
View File

@ -9,8 +9,8 @@ importers:
.: .:
dependencies: dependencies:
'@push.rocks/smartmime': '@push.rocks/smartmime':
specifier: ^2.0.0 specifier: ^2.0.2
version: 2.0.0 version: 2.0.2
'@push.rocks/smartpath': '@push.rocks/smartpath':
specifier: ^5.0.18 specifier: ^5.0.18
version: 5.0.18 version: 5.0.18
@ -21,11 +21,17 @@ importers:
specifier: ^3.0.7 specifier: ^3.0.7
version: 3.0.7 version: 3.0.7
'@push.rocks/smartstream': '@push.rocks/smartstream':
specifier: ^3.0.38 specifier: ^3.0.44
version: 3.0.38 version: 3.0.44
'@push.rocks/smartstring':
specifier: ^4.0.15
version: 4.0.15
'@push.rocks/smartunique':
specifier: ^3.0.9
version: 3.0.9
'@tsclass/tsclass': '@tsclass/tsclass':
specifier: ^4.0.54 specifier: ^4.0.55
version: 4.0.54 version: 4.0.55
minio: minio:
specifier: ^8.0.0 specifier: ^8.0.0
version: 8.0.0 version: 8.0.0
@ -35,10 +41,10 @@ importers:
version: 2.1.80 version: 2.1.80
'@git.zone/tsrun': '@git.zone/tsrun':
specifier: ^1.2.46 specifier: ^1.2.46
version: 1.2.46(@types/node@20.12.12) version: 1.2.46(@types/node@20.14.2)
'@git.zone/tstest': '@git.zone/tstest':
specifier: ^1.0.90 specifier: ^1.0.90
version: 1.0.90(@types/node@20.12.12) version: 1.0.90(@types/node@20.14.2)
'@push.rocks/qenv': '@push.rocks/qenv':
specifier: ^6.0.5 specifier: ^6.0.5
version: 6.0.5 version: 6.0.5
@ -412,8 +418,8 @@ packages:
'@push.rocks/smartmime@1.0.6': '@push.rocks/smartmime@1.0.6':
resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==} resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==}
'@push.rocks/smartmime@2.0.0': '@push.rocks/smartmime@2.0.2':
resolution: {integrity: sha512-yNEYrQzWjxwinCT8djw9eFumpCIvIQQS9KXWLH0LT9COlFoaP/ruk7pogrGYKCo20tFITJyO6NmMCa24402rvA==} resolution: {integrity: sha512-aXH1sFD73q9cEwPdeSeN7Zxd2aoVt9wE97ILFCW5gORylvm85Hgfq7SYkqykjQzEL8IDJKJF3G78+xcL2rALTg==}
'@push.rocks/smartnetwork@3.0.2': '@push.rocks/smartnetwork@3.0.2':
resolution: {integrity: sha512-s6CNGzQ1n/d/6cOKXbxeW6/tO//dr1woLqI01g7XhqTriw0nsm2G2kWaZh2J0VOguGNWBgQVCIpR0LjdRNWb3g==} resolution: {integrity: sha512-s6CNGzQ1n/d/6cOKXbxeW6/tO//dr1woLqI01g7XhqTriw0nsm2G2kWaZh2J0VOguGNWBgQVCIpR0LjdRNWb3g==}
@ -467,8 +473,8 @@ packages:
'@push.rocks/smartstream@2.0.8': '@push.rocks/smartstream@2.0.8':
resolution: {integrity: sha512-GlF/9cCkvBHwKa3DK4DO5wjfSgqkj6gAS4TrY9uD5NMHu9RQv4WiNrElTYj7iCEpnZgUnLO3tzw1JA3NRIMnnA==} resolution: {integrity: sha512-GlF/9cCkvBHwKa3DK4DO5wjfSgqkj6gAS4TrY9uD5NMHu9RQv4WiNrElTYj7iCEpnZgUnLO3tzw1JA3NRIMnnA==}
'@push.rocks/smartstream@3.0.38': '@push.rocks/smartstream@3.0.44':
resolution: {integrity: sha512-Sk9esPURWXldS0ZvgClCtrEyvELjvFnbQgUAelwoXWMfM8pXuB9BX1tE+Z1iBkB9Xyw2p1d9jYelO6waSXg0BQ==} resolution: {integrity: sha512-BZwSUmhVD/CEzRdG/e2UachlyNjshiknqBnwHzIFPIjVKC66UgWX5lYCs2LOwJtuUEpfL1vTMOAYUFNcmPjW9A==}
'@push.rocks/smartstring@4.0.15': '@push.rocks/smartstring@4.0.15':
resolution: {integrity: sha512-NTNeOjWyg+aHtBTiQEyXamr7oTvYZ3wS1fudHo9ua7CLrykpK+i+RxFyJaLg1zB5x9xQF3NLEQecB14HPFX8Cg==} resolution: {integrity: sha512-NTNeOjWyg+aHtBTiQEyXamr7oTvYZ3wS1fudHo9ua7CLrykpK+i+RxFyJaLg1zB5x9xQF3NLEQecB14HPFX8Cg==}
@ -621,8 +627,8 @@ packages:
'@tsclass/tsclass@3.0.48': '@tsclass/tsclass@3.0.48':
resolution: {integrity: sha512-hC65UvDlp9qvsl6OcIZXz0JNiWZ0gyzsTzbXpg215sGxopgbkOLCr6E0s4qCTnweYm95gt2AdY95uP7M7kExaQ==} resolution: {integrity: sha512-hC65UvDlp9qvsl6OcIZXz0JNiWZ0gyzsTzbXpg215sGxopgbkOLCr6E0s4qCTnweYm95gt2AdY95uP7M7kExaQ==}
'@tsclass/tsclass@4.0.54': '@tsclass/tsclass@4.0.55':
resolution: {integrity: sha512-v+Xc7M0BKNT79/kx7S5Jsc17zj+acUuMDxJtKbQgdU4H8ke3aHAHJr2KicXJeXDTcn41ZEbwJPQ1cc+bjy8bZw==} resolution: {integrity: sha512-zg774JF90/3/rJ7xk4LyGgxcUzxdKIQcwtBVxez4LhvegESxvHiFmX42WL105iBpE53ISJ8sctLWlwG1JQZdlA==}
'@tsconfig/node10@1.0.11': '@tsconfig/node10@1.0.11':
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
@ -765,6 +771,9 @@ packages:
'@types/node@20.12.12': '@types/node@20.12.12':
resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==}
'@types/node@20.14.2':
resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==}
'@types/parse5@6.0.3': '@types/parse5@6.0.3':
resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==}
@ -2821,8 +2830,8 @@ packages:
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
engines: {node: '>=12.20'} engines: {node: '>=12.20'}
type-fest@4.18.2: type-fest@4.20.0:
resolution: {integrity: sha512-+suCYpfJLAe4OXS6+PPXjW3urOS4IoP9waSiLuXfLgqZODKw/aWwASvzqE886wA0kQgGy0mIWyhd87VpqIy6Xg==} resolution: {integrity: sha512-MBh+PHUHHisjXf4tlx0CFWoMdjx8zCMLJHOjnV1prABYZFHqtFOyauCIK2/7w4oIfwkF8iNhLtnJEfVY2vn3iw==}
engines: {node: '>=16'} engines: {node: '>=16'}
type-is@1.6.18: type-is@1.6.18:
@ -3127,12 +3136,12 @@ snapshots:
'@push.rocks/smartrequest': 2.0.22 '@push.rocks/smartrequest': 2.0.22
'@push.rocks/smartrx': 3.0.7 '@push.rocks/smartrx': 3.0.7
'@push.rocks/smartsitemap': 2.0.3 '@push.rocks/smartsitemap': 2.0.3
'@push.rocks/smartstream': 3.0.38 '@push.rocks/smartstream': 3.0.44
'@push.rocks/smarttime': 4.0.6 '@push.rocks/smarttime': 4.0.6
'@push.rocks/taskbuffer': 3.1.7 '@push.rocks/taskbuffer': 3.1.7
'@push.rocks/webrequest': 3.0.37 '@push.rocks/webrequest': 3.0.37
'@push.rocks/webstore': 2.0.17 '@push.rocks/webstore': 2.0.17
'@tsclass/tsclass': 4.0.54 '@tsclass/tsclass': 4.0.55
'@types/express': 4.17.21 '@types/express': 4.17.21
body-parser: 1.20.2 body-parser: 1.20.2
cors: 2.8.5 cors: 2.8.5
@ -3333,22 +3342,22 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@git.zone/tsrun@1.2.46(@types/node@20.12.12)': '@git.zone/tsrun@1.2.46(@types/node@20.14.2)':
dependencies: dependencies:
'@push.rocks/smartfile': 10.0.41 '@push.rocks/smartfile': 10.0.41
'@push.rocks/smartshell': 3.0.5 '@push.rocks/smartshell': 3.0.5
ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.1.6) ts-node: 10.9.2(@types/node@20.14.2)(typescript@5.1.6)
typescript: 5.1.6 typescript: 5.1.6
transitivePeerDependencies: transitivePeerDependencies:
- '@swc/core' - '@swc/core'
- '@swc/wasm' - '@swc/wasm'
- '@types/node' - '@types/node'
'@git.zone/tstest@1.0.90(@types/node@20.12.12)': '@git.zone/tstest@1.0.90(@types/node@20.14.2)':
dependencies: dependencies:
'@api.global/typedserver': 3.0.37 '@api.global/typedserver': 3.0.37
'@git.zone/tsbundle': 2.0.15 '@git.zone/tsbundle': 2.0.15
'@git.zone/tsrun': 1.2.46(@types/node@20.12.12) '@git.zone/tsrun': 1.2.46(@types/node@20.14.2)
'@push.rocks/consolecolor': 2.0.2 '@push.rocks/consolecolor': 2.0.2
'@push.rocks/smartbrowser': 2.0.6 '@push.rocks/smartbrowser': 2.0.6
'@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartdelay': 3.0.5
@ -3597,7 +3606,7 @@ snapshots:
'@push.rocks/smartpath': 5.0.18 '@push.rocks/smartpath': 5.0.18
'@push.rocks/smartpromise': 4.0.3 '@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartrequest': 2.0.22 '@push.rocks/smartrequest': 2.0.22
'@push.rocks/smartstream': 3.0.38 '@push.rocks/smartstream': 3.0.44
'@types/fs-extra': 11.0.4 '@types/fs-extra': 11.0.4
'@types/glob': 8.1.0 '@types/glob': 8.1.0
'@types/js-yaml': 4.0.9 '@types/js-yaml': 4.0.9
@ -3664,7 +3673,7 @@ snapshots:
'@types/mime-types': 2.1.4 '@types/mime-types': 2.1.4
mime-types: 2.1.35 mime-types: 2.1.35
'@push.rocks/smartmime@2.0.0': '@push.rocks/smartmime@2.0.2':
dependencies: dependencies:
'@types/mime-types': 2.1.4 '@types/mime-types': 2.1.4
file-type: 19.0.0 file-type: 19.0.0
@ -3711,7 +3720,7 @@ snapshots:
'@push.rocks/smartpromise': 4.0.3 '@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartpuppeteer': 2.0.2 '@push.rocks/smartpuppeteer': 2.0.2
'@push.rocks/smartunique': 3.0.9 '@push.rocks/smartunique': 3.0.9
'@tsclass/tsclass': 4.0.54 '@tsclass/tsclass': 4.0.55
'@types/express': 4.17.21 '@types/express': 4.17.21
express: 4.19.2 express: 4.19.2
pdf-lib: 1.17.1 pdf-lib: 1.17.1
@ -3769,7 +3778,7 @@ snapshots:
'@push.rocks/smartxml': 1.0.8 '@push.rocks/smartxml': 1.0.8
'@push.rocks/smartyaml': 2.0.5 '@push.rocks/smartyaml': 2.0.5
'@push.rocks/webrequest': 3.0.37 '@push.rocks/webrequest': 3.0.37
'@tsclass/tsclass': 4.0.54 '@tsclass/tsclass': 4.0.55
'@push.rocks/smartsocket@2.0.27': '@push.rocks/smartsocket@2.0.27':
dependencies: dependencies:
@ -3821,12 +3830,12 @@ snapshots:
from2: 2.3.0 from2: 2.3.0
through2: 4.0.2 through2: 4.0.2
'@push.rocks/smartstream@3.0.38': '@push.rocks/smartstream@3.0.44':
dependencies: dependencies:
'@push.rocks/lik': 6.0.15 '@push.rocks/lik': 6.0.15
'@push.rocks/smartenv': 5.0.12
'@push.rocks/smartpromise': 4.0.3 '@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartrx': 3.0.7 '@push.rocks/smartrx': 3.0.7
'@push.rocks/webstream': 1.0.8
'@push.rocks/smartstring@4.0.15': '@push.rocks/smartstring@4.0.15':
dependencies: dependencies:
@ -3903,7 +3912,7 @@ snapshots:
dependencies: dependencies:
'@pushrocks/smartdelay': 3.0.1 '@pushrocks/smartdelay': 3.0.1
'@pushrocks/smartpromise': 4.0.2 '@pushrocks/smartpromise': 4.0.2
'@tsclass/tsclass': 4.0.54 '@tsclass/tsclass': 4.0.55
'@push.rocks/webstore@2.0.17': '@push.rocks/webstore@2.0.17':
dependencies: dependencies:
@ -4083,9 +4092,9 @@ snapshots:
dependencies: dependencies:
type-fest: 2.19.0 type-fest: 2.19.0
'@tsclass/tsclass@4.0.54': '@tsclass/tsclass@4.0.55':
dependencies: dependencies:
type-fest: 4.18.2 type-fest: 4.20.0
'@tsconfig/node10@1.0.11': {} '@tsconfig/node10@1.0.11': {}
@ -4250,6 +4259,10 @@ snapshots:
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
'@types/node@20.14.2':
dependencies:
undici-types: 5.26.5
'@types/parse5@6.0.3': {} '@types/parse5@6.0.3': {}
'@types/ping@0.4.4': {} '@types/ping@0.4.4': {}
@ -6666,14 +6679,14 @@ snapshots:
trough@2.2.0: {} trough@2.2.0: {}
ts-node@10.9.2(@types/node@20.12.12)(typescript@5.1.6): ts-node@10.9.2(@types/node@20.14.2)(typescript@5.1.6):
dependencies: dependencies:
'@cspotcode/source-map-support': 0.8.1 '@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.11 '@tsconfig/node10': 1.0.11
'@tsconfig/node12': 1.0.11 '@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3 '@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4 '@tsconfig/node16': 1.0.4
'@types/node': 20.12.12 '@types/node': 20.14.2
acorn: 8.11.3 acorn: 8.11.3
acorn-walk: 8.3.2 acorn-walk: 8.3.2
arg: 4.1.3 arg: 4.1.3
@ -6700,7 +6713,7 @@ snapshots:
type-fest@2.19.0: {} type-fest@2.19.0: {}
type-fest@4.18.2: {} type-fest@4.20.0: {}
type-is@1.6.18: type-is@1.6.18:
dependencies: dependencies:

View File

@ -1,9 +1,10 @@
# @push.rocks/smartbucket # @push.rocks/smartbucket
A TypeScript library for simple cloud independent object storage with support for buckets, directories, and files.
A TypeScript library for cloud-independent object storage, providing features like bucket creation, file and directory management, and data streaming.
## Install ## Install
To install `@push.rocks/smartbucket`, you need to have Node.js and npm (Node Package Manager) installed on your system. If you have them installed, you can add `@push.rocks/smartbucket` to your project by running the following command in your project's root directory: To install `@push.rocks/smartbucket`, you need to have Node.js and npm (Node Package Manager) installed. If they are installed, you can add `@push.rocks/smartbucket` to your project by running the following command in your project's root directory:
```bash ```bash
npm install @push.rocks/smartbucket --save npm install @push.rocks/smartbucket --save
@ -13,7 +14,7 @@ This command will download and install `@push.rocks/smartbucket` along with its
## Usage ## Usage
`@push.rocks/smartbucket` is a TypeScript module designed to provide simple cloud-independent object storage functionality. It wraps various cloud storage providers such as AWS S3, Google Cloud Storage, and others, offering a unified API to manage storage buckets and objects within those buckets. `@push.rocks/smartbucket` is a TypeScript module designed to provide simple cloud-independent object storage functionality. It wraps various cloud storage providers such as AWS S3, Google Cloud Storage, and others, offering a unified API to manage storage buckets and objects within those buckets.
In this guide, we will delve into the usage of SmartBucket, covering its full range of features from setting up the library to advanced usage scenarios. In this guide, we will delve into the usage of SmartBucket, covering its full range of features from setting up the library to advanced usage scenarios.
@ -48,7 +49,7 @@ const mySmartBucket = new SmartBucket({
accessKey: "yourAccessKey", accessKey: "yourAccessKey",
accessSecret: "yourSecretKey", accessSecret: "yourSecretKey",
endpoint: "yourEndpointURL", endpoint: "yourEndpointURL",
port: 443, // Default is 443, could be customized for specific endpoint port: 443, // Default is 443, can be customized for specific endpoint
useSsl: true // Defaults to true useSsl: true // Defaults to true
}); });
``` ```
@ -189,7 +190,7 @@ async function writeFileStream(bucketName: string, filePath: string, readableStr
// Create a readable stream from a string // Create a readable stream from a string
const readable = new Readable(); const readable = new Readable();
readable.push('Hello world streamed as a file!'); readable.push('Hello world streamed as a file!');
readable.push(null); // Indicates end of the stream readable.push(null); // End of stream
// Use the function // Use the function
writeFileStream("exampleBucket", "path/to/streamedObject.txt", readable); writeFileStream("exampleBucket", "path/to/streamedObject.txt", readable);
@ -197,7 +198,9 @@ writeFileStream("exampleBucket", "path/to/streamedObject.txt", readable);
### Working with Directories ### Working with Directories
`@push.rocks/smartbucket` abstracts directories within buckets for easier object management. You can create, list, and delete directories using the `Directory` class. `@push.rocks/smartbucket` offers abstractions for directories within buckets for easier object management. You can create, list, and delete directories using the `Directory` class.
To list the contents of a directory:
```typescript ```typescript
async function listDirectoryContents(bucketName: string, directoryPath: string) { async function listDirectoryContents(bucketName: string, directoryPath: string) {
@ -205,6 +208,7 @@ async function listDirectoryContents(bucketName: string, directoryPath: string)
if (myBucket) { if (myBucket) {
const baseDirectory: Directory = await myBucket.getBaseDirectory(); const baseDirectory: Directory = await myBucket.getBaseDirectory();
const targetDirectory: Directory = await baseDirectory.getSubDirectoryByName(directoryPath); const targetDirectory: Directory = await baseDirectory.getSubDirectoryByName(directoryPath);
console.log('Listing directories:'); console.log('Listing directories:');
const directories = await targetDirectory.listDirectories(); const directories = await targetDirectory.listDirectories();
directories.forEach(dir => { directories.forEach(dir => {
@ -250,11 +254,11 @@ createFileInDirectory("exampleBucket", "some/directory", "newfile.txt", "Hello,
#### Bucket Policies #### Bucket Policies
Manage bucket policies to control access permissions. This feature is dependent on the policies provided by the storage service (e.g., AWS S3, MinIO). Manage bucket policies to control access permissions. This feature depends on the policies provided by the storage service (e.g., AWS S3, MinIO).
#### Object Metadata #### Object Metadata
You can retrieve and modify object metadata. Metadata can be useful for storing additional information about an object. Retrieve and modify object metadata. Metadata can be useful for storing additional information about an object.
To retrieve metadata: To retrieve metadata:

View File

@ -45,7 +45,7 @@ tap.test('should get data in bucket', async () => {
}); });
const fileStringStream = await myBucket.fastGetStream({ const fileStringStream = await myBucket.fastGetStream({
path: 'hithere/socool.txt', path: 'hithere/socool.txt',
}); }, 'nodestream');
console.log(fileString); console.log(fileString);
}); });
@ -79,7 +79,7 @@ tap.test('prepare for directory style tests', async () => {
contents: 'dir3/dir4/file1.txt content', contents: 'dir3/dir4/file1.txt content',
}); });
await myBucket.fastPut({ await myBucket.fastPut({
path: 'file1.txt', path: '/file1.txt',
contents: 'file1 content', contents: 'file1 content',
}); });
}); });

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartbucket', name: '@push.rocks/smartbucket',
version: '3.0.4', version: '3.0.14',
description: 'A TypeScript library that offers simple, cloud-independent object storage with features like bucket creation, file management, and directory management.' description: 'A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.'
} }

View File

@ -1,7 +1,16 @@
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
import * as helpers from './helpers.js';
import * as interfaces from './interfaces.js';
import { SmartBucket } from './classes.smartbucket.js'; import { SmartBucket } from './classes.smartbucket.js';
import { Directory } from './classes.directory.js'; import { Directory } from './classes.directory.js';
import { File } from './classes.file.js';
import { Trash } from './classes.trash.js';
/**
* The bucket class exposes the basc functionality of a bucket.
* The functions of the bucket alone are enough to
* operate in s3 basic fashion on blobs of data.
*/
export class Bucket { export class Bucket {
public static async getBucketByName(smartbucketRef: SmartBucket, bucketNameArg: string) { public static async getBucketByName(smartbucketRef: SmartBucket, bucketNameArg: string) {
const buckets = await smartbucketRef.minioClient.listBuckets(); const buckets = await smartbucketRef.minioClient.listBuckets();
@ -38,10 +47,29 @@ export class Bucket {
/** /**
* gets the base directory of the bucket * gets the base directory of the bucket
*/ */
public async getBaseDirectory() { public async getBaseDirectory(): Promise<Directory> {
return new Directory(this, null, ''); return new Directory(this, null, '');
} }
/**
* gets the trash directory
*/
public async getTrash(): Promise<Trash> {
const trash = new Trash(this);
return trash;
}
public async getDirectoryFromPath(
pathDescriptorArg: interfaces.IPathDecriptor
): Promise<Directory> {
if (!pathDescriptorArg.path && !pathDescriptorArg.directory) {
return this.getBaseDirectory();
}
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptorArg);
const baseDirectory = await this.getBaseDirectory();
return await baseDirectory.getSubDirectoryByName(checkPath);
}
// =============== // ===============
// Fast Operations // Fast Operations
// =============== // ===============
@ -49,46 +77,61 @@ export class Bucket {
/** /**
* store file * store file
*/ */
public async fastPut(optionsArg: { public async fastPut(optionsArg: interfaces.IPathDecriptor & {
path: string;
contents: string | Buffer; contents: string | Buffer;
overwrite?: boolean; overwrite?: boolean;
}): Promise<void> { }): Promise<File> {
try { try {
const reducedPath = await helpers.reducePathDescriptorToPath(optionsArg);
// Check if the object already exists // Check if the object already exists
const exists = await this.fastExists({ path: optionsArg.path }); const exists = await this.fastExists({ path: reducedPath });
if (exists && !optionsArg.overwrite) { if (exists && !optionsArg.overwrite) {
console.error(`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'.`); console.error(`Object already exists at path '${reducedPath}' in bucket '${this.name}'.`);
return; return;
} else if (exists && optionsArg.overwrite) { } else if (exists && optionsArg.overwrite) {
console.log(`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`); console.log(
`Overwriting existing object at path '${reducedPath}' in bucket '${this.name}'.`
);
} else { } else {
console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`); console.log(`Creating new object at path '${reducedPath}' in bucket '${this.name}'.`);
} }
// Proceed with putting the object // Proceed with putting the object
const streamIntake = new plugins.smartstream.StreamIntake(); const streamIntake = new plugins.smartstream.StreamIntake();
const putPromise = this.smartbucketRef.minioClient.putObject(this.name, optionsArg.path, streamIntake); const putPromise = this.smartbucketRef.minioClient.putObject(
this.name,
reducedPath,
streamIntake
);
streamIntake.pushData(optionsArg.contents); streamIntake.pushData(optionsArg.contents);
streamIntake.signalEnd(); streamIntake.signalEnd();
await putPromise; await putPromise;
console.log(`Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`); console.log(`Object '${reducedPath}' has been successfully stored in bucket '${this.name}'.`);
const parsedPath = plugins.path.parse(reducedPath);
return new File({
directoryRefArg: await this.getDirectoryFromPath({
path: parsedPath.dir,
}),
fileName: parsedPath.base,
});
} catch (error) { } catch (error) {
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error); console.error(
`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`,
error
);
throw error; throw error;
} }
} }
/** /**
* get file * get file
*/ */
public async fastGet(optionsArg: Parameters<typeof this.fastGetStream>[0]): Promise<Buffer> { public async fastGet(optionsArg: { path: string }): Promise<Buffer> {
const done = plugins.smartpromise.defer(); const done = plugins.smartpromise.defer();
let completeFile: Buffer; let completeFile: Buffer;
const replaySubject = await this.fastGetStream(optionsArg); const replaySubject = await this.fastGetReplaySubject(optionsArg);
const subscription = replaySubject.subscribe({ const subscription = replaySubject.subscribe({
next: (chunk) => { next: (chunk) => {
if (completeFile) { if (completeFile) {
@ -109,7 +152,13 @@ export class Bucket {
return completeFile; return completeFile;
} }
public async fastGetStream(optionsArg: { /**
* good when time to first byte is important
* and multiple subscribers are expected
* @param optionsArg
* @returns
*/
public async fastGetReplaySubject(optionsArg: {
path: string; path: string;
}): Promise<plugins.smartrx.rxjs.ReplaySubject<Buffer>> { }): Promise<plugins.smartrx.rxjs.ReplaySubject<Buffer>> {
const fileStream = await this.smartbucketRef.minioClient const fileStream = await this.smartbucketRef.minioClient
@ -124,78 +173,121 @@ export class Bucket {
finalFunction: async (cb) => { finalFunction: async (cb) => {
replaySubject.complete(); replaySubject.complete();
return; return;
} },
}); });
if (!fileStream) { if (!fileStream) {
return null; return null;
} }
const smartstream = new plugins.smartstream.StreamWrapper([ const smartstream = new plugins.smartstream.StreamWrapper([fileStream, duplexStream]);
fileStream,
duplexStream,
]);
smartstream.run(); smartstream.run();
return replaySubject; return replaySubject;
} }
public fastGetStream(
optionsArg: {
path: string;
},
typeArg: 'webstream'
): Promise<ReadableStream>;
public async fastGetStream(
optionsArg: {
path: string;
},
typeArg: 'nodestream'
): Promise<plugins.stream.Readable>;
/**
* fastGetStream
* @param optionsArg
* @returns
*/
public async fastGetStream(
optionsArg: { path: string },
typeArg: 'webstream' | 'nodestream' = 'nodestream'
): Promise<ReadableStream | plugins.stream.Readable> {
const fileStream = await this.smartbucketRef.minioClient
.getObject(this.name, optionsArg.path)
.catch((e) => console.log(e));
const duplexStream = new plugins.smartstream.SmartDuplex<Buffer, Buffer>({
writeFunction: async (chunk) => {
return chunk;
},
finalFunction: async (cb) => {
return null;
},
});
if (!fileStream) {
return null;
}
const smartstream = new plugins.smartstream.StreamWrapper([fileStream, duplexStream]);
smartstream.run();
if (typeArg === 'nodestream') {
return duplexStream;
}
if (typeArg === 'webstream') {
return (await duplexStream.getWebStreams()).readable;
}
}
/** /**
* store file as stream * store file as stream
*/ */
public async fastPutStream(optionsArg: { public async fastPutStream(optionsArg: {
path: string; path: string;
dataStream: plugins.stream.Readable; readableStream: plugins.stream.Readable | ReadableStream;
nativeMetadata?: { [key: string]: string }; nativeMetadata?: { [key: string]: string };
overwrite?: boolean; overwrite?: boolean;
}): Promise<void> { }): Promise<void> {
try { try {
// Check if the object already exists // Check if the object already exists
const exists = await this.fastExists({ path: optionsArg.path }); const exists = await this.fastExists({ path: optionsArg.path });
if (exists && !optionsArg.overwrite) { if (exists && !optionsArg.overwrite) {
console.error(`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'.`); console.error(
`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'.`
);
return; return;
} else if (exists && optionsArg.overwrite) { } else if (exists && optionsArg.overwrite) {
console.log(`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`); console.log(
`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`
);
} else { } else {
console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`); console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`);
} }
const streamIntake = await plugins.smartstream.StreamIntake.fromStream<Uint8Array>(
optionsArg.readableStream
);
// Proceed with putting the object // Proceed with putting the object
await this.smartbucketRef.minioClient.putObject( await this.smartbucketRef.minioClient.putObject(
this.name, this.name,
optionsArg.path, optionsArg.path,
optionsArg.dataStream, streamIntake,
null, null,
...(optionsArg.nativeMetadata null // TODO: Add support for custom metadata once proper support is in minio.
? (() => { );
const returnObject: any = {};
return returnObject; console.log(
})() `Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`
: {})
); );
console.log(`Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`);
} catch (error) { } catch (error) {
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error); console.error(
`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`,
error
);
throw error; throw error;
} }
} }
public async copyObject(optionsArg: { public async fastCopy(optionsArg: {
/** sourcePath: string;
* the destinationPath?: string;
*/
objectKey: string;
/**
* in case you want to copy to another bucket specify it here
*/
targetBucket?: Bucket; targetBucket?: Bucket;
targetBucketKey?: string;
/**
* metadata will be merged with existing metadata
*/
nativeMetadata?: { [key: string]: string }; nativeMetadata?: { [key: string]: string };
deleteExistingNativeMetadata?: boolean; deleteExistingNativeMetadata?: boolean;
}): Promise<void> { }): Promise<void> {
@ -205,7 +297,7 @@ export class Bucket {
// Retrieve current object information to use in copy conditions // Retrieve current object information to use in copy conditions
const currentObjInfo = await this.smartbucketRef.minioClient.statObject( const currentObjInfo = await this.smartbucketRef.minioClient.statObject(
targetBucketName, targetBucketName,
optionsArg.objectKey optionsArg.sourcePath
); );
// Setting up copy conditions // Setting up copy conditions
@ -221,8 +313,8 @@ export class Bucket {
// TODO: check on issue here: https://github.com/minio/minio-js/issues/1286 // TODO: check on issue here: https://github.com/minio/minio-js/issues/1286
await this.smartbucketRef.minioClient.copyObject( await this.smartbucketRef.minioClient.copyObject(
this.name, this.name,
optionsArg.objectKey, optionsArg.sourcePath,
`/${targetBucketName}/${optionsArg.objectKey}`, `/${targetBucketName}/${optionsArg.destinationPath || optionsArg.sourcePath}`,
copyConditions copyConditions
); );
} catch (err) { } catch (err) {
@ -231,23 +323,66 @@ export class Bucket {
} }
} }
/**
* Move object from one path to another within the same bucket or to another bucket
*/
public async fastMove(optionsArg: {
sourcePath: string;
destinationPath: string;
targetBucket?: Bucket;
overwrite?: boolean;
}): Promise<void> {
try {
// Check if the destination object already exists
const destinationBucket = optionsArg.targetBucket || this;
const exists = await destinationBucket.fastExists({ path: optionsArg.destinationPath });
if (exists && !optionsArg.overwrite) {
console.error(
`Object already exists at destination path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`
);
return;
} else if (exists && optionsArg.overwrite) {
console.log(
`Overwriting existing object at destination path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`
);
} else {
console.log(
`Moving object to path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`
);
}
// Proceed with copying the object to the new path
await this.fastCopy(optionsArg);
// Remove the original object after successful copy
await this.fastRemove({ path: optionsArg.sourcePath });
console.log(
`Object '${optionsArg.sourcePath}' has been successfully moved to '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`
);
} catch (error) {
console.error(
`Error moving object from '${optionsArg.sourcePath}' to '${optionsArg.destinationPath}':`,
error
);
throw error;
}
}
/** /**
* removeObject * removeObject
*/ */
public async fastRemove(optionsArg: { public async fastRemove(optionsArg: { path: string }) {
path: string;
}) {
await this.smartbucketRef.minioClient.removeObject(this.name, optionsArg.path); await this.smartbucketRef.minioClient.removeObject(this.name, optionsArg.path);
} }
/** /**
* check wether file exists * check wether file exists
* @param optionsArg * @param optionsArg
* @returns * @returns
*/ */
public async fastExists(optionsArg: { public async fastExists(optionsArg: { path: string }): Promise<boolean> {
path: string;
}): Promise<boolean> {
try { try {
await this.smartbucketRef.minioClient.statObject(this.name, optionsArg.path); await this.smartbucketRef.minioClient.statObject(this.name, optionsArg.path);
console.log(`Object '${optionsArg.path}' exists in bucket '${this.name}'.`); console.log(`Object '${optionsArg.path}' exists in bucket '${this.name}'.`);
@ -263,9 +398,63 @@ export class Bucket {
} }
} }
public async fastStat(optionsArg: { /**
path: string; * deletes this bucket
}) { */
return this.smartbucketRef.minioClient.statObject(this.name, optionsArg.path); public async delete() {
await this.smartbucketRef.minioClient.removeBucket(this.name);
}
public async fastStat(pathDescriptor: interfaces.IPathDecriptor) {
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
return this.smartbucketRef.minioClient.statObject(this.name, checkPath);
}
public async isDirectory(pathDescriptor: interfaces.IPathDecriptor): Promise<boolean> {
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
// lets check if the checkPath is a directory
const stream = this.smartbucketRef.minioClient.listObjectsV2(this.name, checkPath, true);
const done = plugins.smartpromise.defer<boolean>();
stream.on('data', (dataArg) => {
stream.destroy(); // Stop the stream early if we find at least one object
if (dataArg.prefix.startsWith(checkPath + '/')) {
done.resolve(true);
}
});
stream.on('end', () => {
done.resolve(false);
});
stream.on('error', (err) => {
done.reject(err);
});
return done.promise;
}
public async isFile(pathDescriptor: interfaces.IPathDecriptor): Promise<boolean> {
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
// lets check if the checkPath is a directory
const stream = this.smartbucketRef.minioClient.listObjectsV2(this.name, checkPath, true);
const done = plugins.smartpromise.defer<boolean>();
stream.on('data', (dataArg) => {
stream.destroy(); // Stop the stream early if we find at least one object
if (dataArg.prefix === checkPath) {
done.resolve(true);
}
});
stream.on('end', () => {
done.resolve(false);
});
stream.on('error', (err) => {
done.reject(err);
});
return done.promise;
} }
} }

View File

@ -2,6 +2,8 @@ import * as plugins from './plugins.js';
import { Bucket } from './classes.bucket.js'; import { Bucket } from './classes.bucket.js';
import { File } from './classes.file.js'; import { File } from './classes.file.js';
import * as helpers from './helpers.js';
export class Directory { export class Directory {
public bucketRef: Bucket; public bucketRef: Bucket;
public parentDirectoryRef: Directory; public parentDirectoryRef: Directory;
@ -65,24 +67,37 @@ export class Directory {
public async getFile(optionsArg: { public async getFile(optionsArg: {
name: string; name: string;
createWithContents?: string | Buffer; createWithContents?: string | Buffer;
getFromTrash?: boolean;
}): Promise<File> { }): Promise<File> {
const pathDescriptor = {
directory: this,
path: optionsArg.name,
};
// check wether the file exists // check wether the file exists
const exists = await this.bucketRef.fastExists({ const exists = await this.bucketRef.fastExists({
path: this.getBasePath() + optionsArg.name, path: await helpers.reducePathDescriptorToPath(pathDescriptor),
}); });
if (!exists && optionsArg.getFromTrash) {
const trash = await this.bucketRef.getTrash();
const trashedFile = await trash.getTrashedFileByOriginalName(
pathDescriptor
)
return trashedFile;
}
if (!exists && !optionsArg.createWithContents) { if (!exists && !optionsArg.createWithContents) {
return null; return null;
} }
if (!exists && optionsArg.createWithContents) { if (!exists && optionsArg.createWithContents) {
await this.fastPut({ await File.create({
path: optionsArg.name, directory: this,
name: optionsArg.name,
contents: optionsArg.createWithContents, contents: optionsArg.createWithContents,
}); });
} }
return new File({ return new File({
directoryRefArg: this, directoryRefArg: this,
fileName: optionsArg.name, fileName: optionsArg.name,
}) });
} }
/** /**
@ -120,7 +135,7 @@ export class Directory {
}, },
finalFunction: async (tools) => { finalFunction: async (tools) => {
done.resolve(); done.resolve();
} },
}); });
fileNameStream.pipe(duplexStream); fileNameStream.pipe(duplexStream);
await done.promise; await done.promise;
@ -159,7 +174,7 @@ export class Directory {
}, },
finalFunction: async (tools) => { finalFunction: async (tools) => {
done.resolve(); done.resolve();
} },
}); });
completeDirStream.pipe(duplexStream); completeDirStream.pipe(duplexStream);
await done.promise; await done.promise;
@ -234,14 +249,56 @@ export class Directory {
return result; return result;
} }
public async fastGetStream(pathArg: string): Promise<plugins.smartrx.rxjs.ReplaySubject<Buffer>> { public fastGetStream(
const path = plugins.path.join(this.getBasePath(), pathArg); optionsArg: {
const result = await this.bucketRef.fastGetStream({ path: string;
path, },
}); typeArg: 'webstream'
): Promise<ReadableStream>;
public async fastGetStream(
optionsArg: {
path: string;
},
typeArg: 'nodestream'
): Promise<plugins.stream.Readable>;
/**
* fastGetStream
* @param optionsArg
* @returns
*/
public async fastGetStream(
optionsArg: { path: string },
typeArg: 'webstream' | 'nodestream'
): Promise<ReadableStream | plugins.stream.Readable> {
const path = plugins.path.join(this.getBasePath(), optionsArg.path);
const result = await this.bucketRef.fastGetStream(
{
path,
},
typeArg as any
);
return result; return result;
} }
/**
* fast put stream
*/
public async fastPutStream(optionsArg: {
path: string;
stream: plugins.stream.Readable;
}): Promise<void> {
const path = plugins.path.join(this.getBasePath(), optionsArg.path);
await this.bucketRef.fastPutStream({
path,
readableStream: optionsArg.stream,
});
}
/**
* removes a file within the directory
* @param optionsArg
*/
public async fastRemove(optionsArg: { path: string }) { public async fastRemove(optionsArg: { path: string }) {
const path = plugins.path.join(this.getBasePath(), optionsArg.path); const path = plugins.path.join(this.getBasePath(), optionsArg.path);
await this.bucketRef.fastRemove({ await this.bucketRef.fastRemove({

View File

@ -1,8 +1,9 @@
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
import * as helpers from './helpers.js';
import * as interfaces from './interfaces.js';
import { Directory } from './classes.directory.js'; import { Directory } from './classes.directory.js';
import { MetaData } from './classes.metadata.js'; import { MetaData } from './classes.metadata.js';
/** /**
* represents a file in a directory * represents a file in a directory
*/ */
@ -31,7 +32,12 @@ export class File {
directoryRefArg: optionsArg.directory, directoryRefArg: optionsArg.directory,
fileName: optionsArg.name, fileName: optionsArg.name,
}); });
if (contents instanceof plugins.stream.Readable) {} else { if (contents instanceof plugins.stream.Readable) {
await optionsArg.directory.fastPutStream({
path: optionsArg.name,
stream: contents,
});
} else {
await optionsArg.directory.fastPut({ await optionsArg.directory.fastPut({
path: optionsArg.name, path: optionsArg.name,
contents: contents, contents: contents,
@ -46,7 +52,7 @@ export class File {
public getBasePath(): string { public getBasePath(): string {
return plugins.path.join(this.parentDirectoryRef.getBasePath(), this.name); return plugins.path.join(this.parentDirectoryRef.getBasePath(), this.name);
}; }
constructor(optionsArg: { directoryRefArg: Directory; fileName: string }) { constructor(optionsArg: { directoryRefArg: Directory; fileName: string }) {
this.parentDirectoryRef = optionsArg.directoryRefArg; this.parentDirectoryRef = optionsArg.directoryRefArg;
@ -65,35 +71,61 @@ export class File {
return resultBuffer; return resultBuffer;
} }
public async getReadStream() { public async getReadStream(typeArg: 'webstream'): Promise<ReadableStream>;
const readStream = this.parentDirectoryRef.bucketRef.fastGetStream({ public async getReadStream(typeArg: 'nodestream'): Promise<plugins.stream.Readable>;
path: this.getBasePath(), public async getReadStream(
}); typeArg: 'nodestream' | 'webstream'
): Promise<ReadableStream | plugins.stream.Readable> {
const readStream = this.parentDirectoryRef.bucketRef.fastGetStream(
{
path: this.getBasePath(),
},
typeArg as any
);
return readStream;
} }
/** /**
* removes this file * deletes this file
* for using recycling mechanics use .delete()
*/ */
public async remove() { public async delete(optionsArg?: {
await this.parentDirectoryRef.bucketRef.fastRemove({ mode: 'trash' | 'permanent';
path: this.getBasePath(), }) {
});
if (!this.name.endsWith('.metadata')) { optionsArg = {
... {
mode: 'permanent',
},
...optionsArg,
}
if (optionsArg.mode === 'permanent') {
await this.parentDirectoryRef.bucketRef.fastRemove({ await this.parentDirectoryRef.bucketRef.fastRemove({
path: this.getBasePath() + '.metadata', path: this.getBasePath(),
});
if (!this.name.endsWith('.metadata')) {
const metadata = await this.getMetaData();
await metadata.metadataFile.delete(optionsArg);
}
} else if (optionsArg.mode === 'trash') {
const metadata = await this.getMetaData();
await metadata.storeCustomMetaData({
key: 'recycle',
value: {
deletedAt: Date.now(),
originalPath: this.getBasePath(),
},
});
const trash = await this.parentDirectoryRef.bucketRef.getTrash();
await this.move({
directory: await trash.getTrashDir(),
path: await trash.getTrashKeyByOriginalBasePath(this.getBasePath()),
}); });
} }
await this.parentDirectoryRef.listFiles(); await this.parentDirectoryRef.listFiles();
} }
/**
* deletes the file with recycling mechanics
*/
public async delete() {
await this.remove();
}
/** /**
* allows locking the file * allows locking the file
* @param optionsArg * @param optionsArg
@ -102,7 +134,7 @@ export class File {
const metadata = await this.getMetaData(); const metadata = await this.getMetaData();
await metadata.setLock({ await metadata.setLock({
lock: 'locked', lock: 'locked',
expires: new Date(Date.now() + (optionsArg?.timeoutMillis || 1000)), expires: Date.now() + (optionsArg?.timeoutMillis || 1000),
}); });
} }
@ -116,17 +148,23 @@ export class File {
*/ */
force?: boolean; force?: boolean;
}) { }) {
const metadata = await this.getMetaData();
await metadata.removeLock({
force: optionsArg?.force,
});
} }
public async updateWithContents(optionsArg: { public async updateWithContents(optionsArg: {
contents: Buffer | string | plugins.stream.Readable; contents: Buffer | string | plugins.stream.Readable | ReadableStream;
encoding?: 'utf8' | 'binary'; encoding?: 'utf8' | 'binary';
}) { }) {
if (optionsArg.contents instanceof plugins.stream.Readable) { if (
optionsArg.contents instanceof plugins.stream.Readable ||
optionsArg.contents instanceof ReadableStream
) {
await this.parentDirectoryRef.bucketRef.fastPutStream({ await this.parentDirectoryRef.bucketRef.fastPutStream({
path: this.getBasePath(), path: this.getBasePath(),
dataStream: optionsArg.contents, readableStream: optionsArg.contents,
}); });
} else if (Buffer.isBuffer(optionsArg.contents)) { } else if (Buffer.isBuffer(optionsArg.contents)) {
await this.parentDirectoryRef.bucketRef.fastPut({ await this.parentDirectoryRef.bucketRef.fastPut({
@ -141,14 +179,55 @@ export class File {
} }
} }
/**
* moves the file to another directory
*/
public async move(pathDescriptorArg: interfaces.IPathDecriptor) {
let moveToPath = '';
const isDirectory = await this.parentDirectoryRef.bucketRef.isDirectory(pathDescriptorArg);
if (isDirectory) {
moveToPath = await helpers.reducePathDescriptorToPath({
...pathDescriptorArg,
path: plugins.path.join(pathDescriptorArg.path, this.name),
});
}
// lets move the file
await this.parentDirectoryRef.bucketRef.fastMove({
sourcePath: this.getBasePath(),
destinationPath: moveToPath,
});
// lets move the metadatafile
const metadata = await this.getMetaData();
await metadata.metadataFile.move(pathDescriptorArg);
}
/** /**
* allows updating the metadata of a file * allows updating the metadata of a file
* @param updatedMetadata * @param updatedMetadata
*/ */
public async getMetaData() { public async getMetaData() {
if (this.name.endsWith('.metadata')) {
throw new Error('metadata files cannot have metadata');
}
const metadata = await MetaData.createForFile({ const metadata = await MetaData.createForFile({
file: this, file: this,
}); });
return metadata; return metadata;
} }
/**
* gets the contents as json
*/
public async getJsonData() {
const json = await this.getContentsAsString();
const parsed = await JSON.parse(json);
return parsed;
}
public async writeJsonData(dataArg: any) {
await this.updateWithContents({
contents: JSON.stringify(dataArg),
});
}
} }

View File

@ -4,9 +4,7 @@ import { File } from './classes.file.js';
export class MetaData { export class MetaData {
// static // static
public static async createForFile(optionsArg: { public static async createForFile(optionsArg: { file: File }) {
file: File;
}) {
const metaData = new MetaData(); const metaData = new MetaData();
metaData.fileRef = optionsArg.file; metaData.fileRef = optionsArg.file;
@ -29,16 +27,16 @@ export class MetaData {
* the file that the metadata is for * the file that the metadata is for
*/ */
fileRef: File; fileRef: File;
public async getFileType(optionsArg?: { public async getFileType(optionsArg?: {
useFileExtension?: boolean; useFileExtension?: boolean;
useMagicBytes?: boolean; useMagicBytes?: boolean;
}): Promise<string> { }): Promise<string> {
if (optionsArg && optionsArg.useFileExtension || optionsArg.useFileExtension === undefined) { if ((optionsArg && optionsArg.useFileExtension) || optionsArg.useFileExtension === undefined) {
return plugins.path.extname(this.fileRef.name); return plugins.path.extname(this.fileRef.name);
} }
}; }
/** /**
* gets the size of the fileRef * gets the size of the fileRef
*/ */
@ -47,59 +45,56 @@ export class MetaData {
path: this.fileRef.getBasePath(), path: this.fileRef.getBasePath(),
}); });
return stat.size; return stat.size;
}; }
private prefixCustomMetaData = 'custom_'; private prefixCustomMetaData = 'custom_';
public async storeCustomMetaData<T = any>(optionsArg: { public async storeCustomMetaData<T = any>(optionsArg: { key: string; value: T }) {
key: string; const data = await this.metadataFile.getContentsAsString();
value: T; data[this.prefixCustomMetaData + optionsArg.key] = optionsArg.value;
}) { await this.metadataFile.writeJsonData(data);
const json = await this.metadataFile.getContentsAsString();
const parsed = await JSON.parse(json);
parsed[this.prefixCustomMetaData + optionsArg.key] = optionsArg.value;
await this.metadataFile.updateWithContents({
contents: JSON.stringify(parsed),
});
} }
public async getCustomMetaData<T = any>(optionsArg: { public async getCustomMetaData<T = any>(optionsArg: { key: string }): Promise<T> {
key: string; const data = await this.metadataFile.getJsonData();
}): Promise<T> { return data[this.prefixCustomMetaData + optionsArg.key];
const json = await this.metadataFile.getContentsAsString();
const parsed = await JSON.parse(json);
return parsed[this.prefixCustomMetaData + optionsArg.key];
} }
public async deleteCustomMetaData(optionsArg: { public async deleteCustomMetaData(optionsArg: { key: string }) {
key: string; const data = await this.metadataFile.getJsonData();
}) { delete data[this.prefixCustomMetaData + optionsArg.key];
const json = await this.metadataFile.getContentsAsString(); await this.metadataFile.writeJsonData(data);
const parsed = await JSON.parse(json);
delete parsed[this.prefixCustomMetaData + optionsArg.key];
await this.metadataFile.updateWithContents({
contents: JSON.stringify(parsed),
});
} }
/** /**
* set a lock on the ref file * set a lock on the ref file
* @param optionsArg * @param optionsArg
*/ */
public async setLock(optionsArg: { public async setLock(optionsArg: { lock: string; expires: number }) {
lock: string; const data = await this.metadataFile.getJsonData();
expires: Date; data.lock = optionsArg.lock;
}) { data.lockExpires = optionsArg.expires;
await this.metadataFile.writeJsonData(data);
} }
/** /**
* remove the lock on the ref file * remove the lock on the ref file
* @param optionsArg * @param optionsArg
*/ */
public async removeLock(optionsArg: { public async removeLock(optionsArg: { force: boolean }) {
force: boolean; const data = await this.metadataFile.getJsonData();
}) { delete data.lock;
delete data.lockExpires;
await this.metadataFile.writeJsonData(data);
} }
}
public async checkLocked(): Promise<boolean> {
const data = await this.metadataFile.getJsonData();
return data.lock && data.lockExpires > Date.now();
}
public async getLockInfo(): Promise<{ lock: string; expires: number }> {
const data = await this.metadataFile.getJsonData();
return { lock: data.lock, expires: data.lockExpires };
}
}

30
ts/classes.trash.ts Normal file
View File

@ -0,0 +1,30 @@
import * as plugins from './plugins.js';
import * as interfaces from './interfaces.js';
import * as helpers from './helpers.js';
import type { Bucket } from './classes.bucket.js';
import type { Directory } from './classes.directory.js';
import type { File } from './classes.file.js';
export class Trash {
public bucketRef: Bucket;
constructor(bucketRefArg: Bucket) {
this.bucketRef = bucketRefArg;
}
public async getTrashDir() {
return this.bucketRef.getDirectoryFromPath({ path: '.trash' });
}
public async getTrashedFileByOriginalName(pathDescriptor: interfaces.IPathDecriptor): Promise<File> {
const trashDir = await this.getTrashDir();
const originalPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
const trashKey = await this.getTrashKeyByOriginalBasePath(originalPath);
return trashDir.getFile({ name: trashKey });
}
public async getTrashKeyByOriginalBasePath (originalPath: string): Promise<string> {
return plugins.smartstring.base64.encode(originalPath);
}
}

22
ts/helpers.ts Normal file
View File

@ -0,0 +1,22 @@
import * as plugins from './plugins.js';
import * as interfaces from './interfaces.js';
export const reducePathDescriptorToPath = async (pathDescriptorArg: interfaces.IPathDecriptor): Promise<string> => {
let returnPath = ``
if (pathDescriptorArg.directory) {
if (pathDescriptorArg.path && plugins.path.isAbsolute(pathDescriptorArg.path)) {
console.warn('Directory is being ignored when path is absolute.');
returnPath = pathDescriptorArg.path;
} else if (pathDescriptorArg.path) {
returnPath = plugins.path.join(pathDescriptorArg.directory.getBasePath(), pathDescriptorArg.path);
}
} else if (pathDescriptorArg.path) {
returnPath = pathDescriptorArg.path;
} else {
throw new Error('You must specify either a path or a directory.');
}
if (returnPath.startsWith('/')) {
returnPath = returnPath.substring(1);
}
return returnPath;
}

6
ts/interfaces.ts Normal file
View File

@ -0,0 +1,6 @@
import type { Directory } from "./classes.directory.js";
export interface IPathDecriptor {
path?: string;
directory?: Directory;
}

View File

@ -10,8 +10,10 @@ import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise'; import * as smartpromise from '@push.rocks/smartpromise';
import * as smartrx from '@push.rocks/smartrx'; import * as smartrx from '@push.rocks/smartrx';
import * as smartstream from '@push.rocks/smartstream'; import * as smartstream from '@push.rocks/smartstream';
import * as smartstring from '@push.rocks/smartstring';
import * as smartunique from '@push.rocks/smartunique';
export { smartmime, smartpath, smartpromise, smartrx, smartstream }; export { smartmime, smartpath, smartpromise, smartrx, smartstream, smartstring, smartunique };
// @tsclass // @tsclass
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';