Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
1c80a1097b | |||
4344dbd111 | |||
bb89564339 | |||
f480be9917 | |||
11bf0d9dbb | |||
c58cc2b0df | |||
87273cbbbd | |||
bebc8b0ede | |||
46e5217fc0 | |||
ebb539e824 | |||
63e3b492e6 | |||
158614c62c | |||
f11114f6dc | |||
f233cb1dcd | |||
866da6f21a | |||
30ac0ddbb4 | |||
4c5105aae7 | |||
1f6e257cb7 | |||
0a79087c59 | |||
432a59bcec | |||
10d7c5d8e8 | |||
30306f3a40 | |||
9a4859f6a0 | |||
099a68d19f | |||
78576b363e | |||
066dac4bdc | |||
e1faf34660 | |||
031f6449bd | |||
4f5282e5cd | |||
d42bf699f7 | |||
a0d3e8b12f | |||
e343caa204 | |||
693a2de3e5 | |||
9ef10edf3d | |||
7fee4d8612 | |||
9fe5a2fcdc | |||
6d28b76601 |
139
.gitlab-ci.yml
139
.gitlab-ci.yml
@ -1,139 +0,0 @@
|
||||
# gitzone ci_default
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
before_script:
|
||||
- npm install -g @shipzone/npmci
|
||||
|
||||
# ====================
|
||||
# security stage
|
||||
# ====================
|
||||
mirror:
|
||||
stage: security
|
||||
script:
|
||||
- npmci git mirror
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --production --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=prod --production
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci command npm install --ignore-scripts
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command npm audit --audit-level=high --only=dev
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
# ====================
|
||||
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci npm prepare
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
# ====================
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- npmci command npm install -g typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
- npmci command npm run buildDocs
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
allow_failure: true
|
80
changelog.md
Normal file
80
changelog.md
Normal file
@ -0,0 +1,80 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-04-12 - 3.0.5 - fix(documentation)
|
||||
Enhance documentation with extensive usage examples, update project metadata, and remove obsolete CI configuration
|
||||
|
||||
- Updated package description and keywords in package.json and npmextra.json to better reflect the library's robust binary data handling capabilities
|
||||
- Revised README with comprehensive guides, detailed code examples, and advanced use cases for conversions, validations, and integrations
|
||||
- Removed outdated .gitlab-ci.yml file to streamline CI configuration
|
||||
- Improved clarity and structure in documentation for both browser and Node.js environments
|
||||
|
||||
## 2024-05-29 - 3.0.4 - misc
|
||||
Updated project description.
|
||||
- Updated the project description to better reflect current features.
|
||||
|
||||
## 2024-04-25 - 3.0.3 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-25 - 3.0.2 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-17 - 3.0.1 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-17 - 3.0.0 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-17 - 2.0.3 - core
|
||||
Breaking change in core module.
|
||||
- BREAKING CHANGE (core): Updated core functionality.
|
||||
|
||||
## 2024-04-17 - 2.0.2 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-17 - 2.0.1 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-17 - 2.0.0 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-04-17 - 1.0.7 - core, config
|
||||
Multiple updates including breaking changes and configuration adjustments.
|
||||
- BREAKING CHANGE (core): Switched to uInt8Extras.
|
||||
- Updated tsconfig.
|
||||
- Updated npmextra.json for githost.
|
||||
|
||||
## 2024-02-29 - 1.0.6 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-02-25 - 1.0.5 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-02-25 - 1.0.4 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2024-02-25 - 1.0.3 - core, org
|
||||
Core fixes and organizational change.
|
||||
- Fixed issues in the core module.
|
||||
- Switched to new organization scheme.
|
||||
|
||||
## 2022-06-15 - 1.0.2 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
## 2022-06-15 - 1.0.1 - core
|
||||
Core fixes applied.
|
||||
- Fixed issues in the core module.
|
||||
|
||||
<!--
|
||||
Note: Routine version bump commits that only updated the version numbers have been omitted for clarity.
|
||||
-->
|
1
license
1
license
@ -1,4 +1,5 @@
|
||||
Copyright (c) 2022 Lossless GmbH (hello@lossless.com)
|
||||
Copyright 2011 Jon Leighton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -2,17 +2,32 @@
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "pushrocks",
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "push.rocks",
|
||||
"gitrepo": "smartbuffer",
|
||||
"description": "handle ArrayBufferLike structures",
|
||||
"npmPackagename": "@pushrocks/smartbuffer",
|
||||
"description": "A robust TypeScript library for managing binary data by converting between Base64 strings and Uint8Array, validating buffer-like objects, and ensuring data purity.",
|
||||
"npmPackagename": "@push.rocks/smartbuffer",
|
||||
"license": "MIT",
|
||||
"projectDomain": "push.rocks"
|
||||
"projectDomain": "push.rocks",
|
||||
"keywords": [
|
||||
"ArrayBuffer",
|
||||
"Uint8Array",
|
||||
"base64 conversion",
|
||||
"binary data handling",
|
||||
"buffer validation",
|
||||
"TypeScript",
|
||||
"data transformation",
|
||||
"ESM",
|
||||
"utilities",
|
||||
"npm"
|
||||
]
|
||||
}
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
},
|
||||
"tsdoc": {
|
||||
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||
}
|
||||
}
|
11165
package-lock.json
generated
11165
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
45
package.json
45
package.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@pushrocks/smartbuffer",
|
||||
"version": "1.0.2",
|
||||
"name": "@push.rocks/smartbuffer",
|
||||
"version": "3.0.5",
|
||||
"private": false,
|
||||
"description": "handle ArrayBufferLike structures",
|
||||
"description": "A robust TypeScript library for managing binary data by converting between Base64 strings and Uint8Array, validating buffer-like objects, and ensuring data purity.",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
@ -10,18 +10,16 @@
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "(tstest test/ --web)",
|
||||
"build": "(tsbuild --web --allowimplicitany)",
|
||||
"buildDocs": "(tsdoc)"
|
||||
"build": "(tsbuild --web --allowimplicitany)"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitzone/tsbuild": "^2.1.25",
|
||||
"@gitzone/tsbundle": "^2.0.5",
|
||||
"@gitzone/tsdoc": "^1.1.10",
|
||||
"@gitzone/tstest": "^1.0.44",
|
||||
"@pushrocks/tapbundle": "^5.0.3",
|
||||
"@types/node": "^17.0.41"
|
||||
"@git.zone/tsbuild": "^2.1.25",
|
||||
"@git.zone/tsbundle": "^2.0.5",
|
||||
"@git.zone/tsrun": "^1.2.46",
|
||||
"@git.zone/tstest": "^1.0.44",
|
||||
"@push.rocks/tapbundle": "^5.0.8",
|
||||
"@types/node": "^20.11.20"
|
||||
},
|
||||
"dependencies": {},
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
],
|
||||
@ -36,5 +34,26 @@
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
]
|
||||
],
|
||||
"keywords": [
|
||||
"ArrayBuffer",
|
||||
"Uint8Array",
|
||||
"base64 conversion",
|
||||
"binary data handling",
|
||||
"buffer validation",
|
||||
"TypeScript",
|
||||
"data transformation",
|
||||
"ESM",
|
||||
"utilities",
|
||||
"npm"
|
||||
],
|
||||
"dependencies": {
|
||||
"uint8array-extras": "^1.1.0"
|
||||
},
|
||||
"homepage": "https://code.foss.global/push.rocks/smartbuffer",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://code.foss.global/push.rocks/smartbuffer.git"
|
||||
},
|
||||
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
||||
}
|
||||
|
9838
pnpm-lock.yaml
generated
Normal file
9838
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
readme.hints.md
Normal file
1
readme.hints.md
Normal file
@ -0,0 +1 @@
|
||||
|
942
readme.md
942
readme.md
@ -1,39 +1,925 @@
|
||||
# @pushrocks/smartbuffer
|
||||
handle ArrayBufferLike structures
|
||||
# @push.rocks/smartbuffer
|
||||
A library for managing ArrayBufferLike structures including conversion between Base64 and Uint8Array, and buffer validation.
|
||||
|
||||
## Availabililty and Links
|
||||
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartbuffer)
|
||||
* [gitlab.com (source)](https://gitlab.com/pushrocks/smartbuffer)
|
||||
* [github.com (source mirror)](https://github.com/pushrocks/smartbuffer)
|
||||
* [docs (typedoc)](https://pushrocks.gitlab.io/smartbuffer/)
|
||||
## Install
|
||||
|
||||
## Status for master
|
||||
To install @push.rocks/smartbuffer, simply run:
|
||||
|
||||
Status Category | Status Badge
|
||||
-- | --
|
||||
GitLab Pipelines | [](https://lossless.cloud)
|
||||
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||
npm | [](https://lossless.cloud)
|
||||
Snyk | [](https://lossless.cloud)
|
||||
TypeScript Support | [](https://lossless.cloud)
|
||||
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||
Code Style | [](https://lossless.cloud)
|
||||
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||
Platform support | [](https://lossless.cloud) [](https://lossless.cloud)
|
||||
```sh
|
||||
npm install @push.rocks/smartbuffer
|
||||
```
|
||||
|
||||
If you are using yarn:
|
||||
|
||||
```sh
|
||||
yarn add @push.rocks/smartbuffer
|
||||
```
|
||||
|
||||
This module is designed for developers who need advanced utilities for handling binary data in TypeScript applications using ECMAScript Modules (ESM). It provides seamless conversion between Base64 strings and Uint8Array representations, ensures buffer-like objects are valid, and extends capabilities with useful operations from the uint8array-extras package.
|
||||
|
||||
## Usage
|
||||
|
||||
use TypeScript for best in class intellisense
|
||||
The following usage guide offers a comprehensive walkthrough of the features provided by @push.rocks/smartbuffer. We will not only show you the basic functions available, but also guide you through advanced techniques, integrating these utilities into complex applications that require reliable binary data manipulation. Every example is written in TypeScript using ESM syntax to ensure modern code quality and compatibility with contemporary development frameworks.
|
||||
|
||||
## Contribution
|
||||
In this guide, we will explore the following topics in detail:
|
||||
|
||||
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||
1. Introduction to Binary Data Handling
|
||||
2. Understanding ArrayBufferLike Structures and Uint8Array
|
||||
3. Overview of @push.rocks/smartbuffer Functions
|
||||
4. Converting Uint8Array Data to Base64
|
||||
5. Converting Base64 Strings to Uint8Array
|
||||
6. Validating Buffer-like Objects in Different Environments
|
||||
7. Ensuring Data Purity: The ensurePureUint8Array Function
|
||||
8. Working with Extended Utilities from uint8array-extras
|
||||
9. Handling Edge Cases and Error Checking
|
||||
10. Integrating smartbuffer into Real-World Applications
|
||||
11. Performance Considerations and Best Practices
|
||||
12. Comprehensive Code Examples and Use Cases
|
||||
13. Debugging and Testing Your Implementation
|
||||
14. Advanced Topics and Future Directions
|
||||
|
||||
For further information read the linked docs at the top of this readme.
|
||||
Below, we present detailed explanations and code examples for each of these topics, with real-world scenarios and sophisticated use cases that should address all possible requirements when working with binary data.
|
||||
|
||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||
---
|
||||
|
||||
[](https://maintainedby.lossless.com)
|
||||
### 1. Introduction to Binary Data Handling
|
||||
|
||||
When building modern applications, especially those that deal with network communication, media processing, or data storage, binary data handling becomes crucial. Binary data in JavaScript is typically managed through the ArrayBuffer interface, and typed arrays, such as Uint8Array, for better performance and memory management. However, direct manipulation of these structures can be error-prone and requires careful management regarding conversions and validations.
|
||||
|
||||
@push.rocks/smartbuffer is a utility library developed to encapsulate many common operations on ArrayBufferLike objects. Whether you’re dealing with Base64 encoding/decoding or simply need to validate if an object is buffer-like, this library simplifies these operations into streamlined functions. This makes your development process smoother and reduces chances for bugs.
|
||||
|
||||
---
|
||||
|
||||
### 2. Understanding ArrayBufferLike Structures and Uint8Array
|
||||
|
||||
Before diving into the utilities, it is essential to understand the primary data structures:
|
||||
- **ArrayBuffer:** A generic, fixed-length binary data buffer. It is the raw data container for typed arrays.
|
||||
- **Uint8Array:** A typed array that represents an array of 8-bit unsigned integers. It offers a convenient way to work with binary data and is often used to interact with ArrayBuffer.
|
||||
|
||||
Operations like converting an image from a server, parsing binary protocols, or even handling cryptographic data require reliable manipulation of these structures. The challenge often lies in converting them into readable formats such as Base64 strings or validating them under various runtime environments.
|
||||
|
||||
---
|
||||
|
||||
### 3. Overview of @push.rocks/smartbuffer Functions
|
||||
|
||||
At its core, @push.rocks/smartbuffer provides several utilities:
|
||||
|
||||
- **uInt8ArrayToBase64(uInt8Array: Uint8Array): string**
|
||||
Converts a Uint8Array to its Base64 encoded string representation.
|
||||
|
||||
- **base64ToUint8Array(base64: string): Uint8Array**
|
||||
Converts a Base64 string back into a Uint8Array, facilitating data transformations between different formats.
|
||||
|
||||
- **isBufferLike(obj: any): obj is ArrayBufferLike | Buffer**
|
||||
Validates if the provided object qualifies as a buffer-like entity. This function checks whether the object has the required byteLength property and, when applicable, additional Node.js Buffer validations.
|
||||
|
||||
- **ensurePureUint8Array(bufferArg: Uint8Array | Buffer): Uint8Array**
|
||||
Returns a new Uint8Array that is a copy of the provided buffer-like object. This function ensures that the returned data is a “pure” Uint8Array, free from any underlying references that might interfere during further operations.
|
||||
|
||||
- **uInt8ArrayExtras (as part of the plugins export)**
|
||||
Offers additional utility methods from the uint8array-extras module. These methods might include extra functionalities for conversion, manipulation, or any niche operations developers require when dealing with typed arrays.
|
||||
|
||||
Let's now delve into each function with full, detailed examples to show how these can be used in real-world applications.
|
||||
|
||||
---
|
||||
|
||||
### 4. Converting Uint8Array Data to Base64
|
||||
|
||||
One of the most frequently encountered requirements in data transformation is encoding binary data into a Base64 string. Base64 encoding is used widely for transmitting binary data over channels that only support textual data formats (e.g., JSON, HTML forms).
|
||||
|
||||
Let’s see a detailed example of how to perform this conversion.
|
||||
|
||||
#### Basic Conversion Example
|
||||
|
||||
In this simple example, we create an instance of Uint8Array with a few sample bytes and convert them into a Base64 string.
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
|
||||
const sampleBytes = new Uint8Array([72, 101, 108, 108, 111]); // Represents the string "Hello"
|
||||
const base64String: string = uInt8ArrayToBase64(sampleBytes);
|
||||
|
||||
console.log('Base64 String:', base64String);
|
||||
```
|
||||
|
||||
In this case, the output is a Base64 encoded representation of the bytes that constitute the word “Hello”. This functionality is especially useful when you need to embed binary data, such as small images or file fragments, directly into JSON or HTML.
|
||||
|
||||
#### Converting Large Data Blocks
|
||||
|
||||
Handling large blocks of data requires consideration for performance. The smartbuffer library is designed to perform these operations efficiently, even when the data length is significant.
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
|
||||
function convertLargeDataBlock(): void {
|
||||
// Create a large Uint8Array. Here we simulate data in the range of 1 MB.
|
||||
const dataLength = 1024 * 1024;
|
||||
const largeData = new Uint8Array(dataLength);
|
||||
|
||||
// Populate with random data
|
||||
for (let i = 0; i < largeData.length; i++) {
|
||||
largeData[i] = Math.floor(Math.random() * 256);
|
||||
}
|
||||
|
||||
const base64Data = uInt8ArrayToBase64(largeData);
|
||||
console.log('Large Data Base64:', base64Data.substring(0, 100) + '...'); // Display only a snippet
|
||||
}
|
||||
|
||||
convertLargeDataBlock();
|
||||
```
|
||||
|
||||
This example demonstrates how to handle large Uint8Array objects with ease. Note that printing the entire Base64 string might not be feasible if you’re dealing with huge data, so consider operating on slices or summaries for logging and debugging purposes.
|
||||
|
||||
#### Handling Errors Gracefully
|
||||
|
||||
When working with binary data, it’s vital to add error handling to capture invalid inputs. Although the conversion utility is straightforward, defensive programming practices are encouraged.
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
|
||||
function safeUint8ArrayToBase64(input: any): void {
|
||||
try {
|
||||
if (!(input instanceof Uint8Array)) {
|
||||
throw new Error('Invalid input: Expected Uint8Array.');
|
||||
}
|
||||
const base64 = uInt8ArrayToBase64(input);
|
||||
console.log('Encoded Base64:', base64);
|
||||
} catch (error) {
|
||||
console.error('Conversion error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing valid input
|
||||
safeUint8ArrayToBase64(new Uint8Array([1, 2, 3, 4]));
|
||||
|
||||
// Testing invalid input
|
||||
safeUint8ArrayToBase64({ notAnArray: true });
|
||||
```
|
||||
|
||||
In this snippet, we perform a type check before processing and catch any exceptions that might arise from an invalid input. This provides a robust safeguard for operators in a production environment.
|
||||
|
||||
---
|
||||
|
||||
### 5. Converting Base64 Strings to Uint8Array
|
||||
|
||||
The reverse operation, converting a Base64 string to a Uint8Array, is just as important. This conversion becomes essential when receiving binary data encoded as strings over networks, or stored in textual storage formats.
|
||||
|
||||
#### Basic Decoding Example
|
||||
|
||||
Here’s a simple example showing how to decode a Base64 string back to a byte array:
|
||||
|
||||
```typescript
|
||||
import { base64ToUint8Array } from '@push.rocks/smartbuffer';
|
||||
|
||||
const sampleBase64 = "SGVsbG8="; // Base64 encoded "Hello"
|
||||
const byteArray: Uint8Array = base64ToUint8Array(sampleBase64);
|
||||
|
||||
console.log('Decoded Uint8Array:', byteArray);
|
||||
```
|
||||
|
||||
This command decodes the Base64 string into a Uint8Array that represents the word “Hello”. The utility offloads all the complexities of mapping each Base64 character back into binary form, ensuring that developers can quickly perform these conversions.
|
||||
|
||||
#### Decoding Complex Data
|
||||
|
||||
Imagine a scenario where you receive a payload containing an image encoded in Base64 from an API. You need to decode it and generate a Blob object to display the image in a browser:
|
||||
|
||||
```typescript
|
||||
import { base64ToUint8Array } from '@push.rocks/smartbuffer';
|
||||
|
||||
async function displayImageFromBase64(base64String: string): Promise<void> {
|
||||
const uint8Array: Uint8Array = base64ToUint8Array(base64String);
|
||||
|
||||
// Create a Blob from the Uint8Array. Adjust the MIME type according to your data.
|
||||
const imageBlob: Blob = new Blob([uint8Array], { type: 'image/png' });
|
||||
|
||||
// Generate a temporary URL for the Blob
|
||||
const imageUrl: string = URL.createObjectURL(imageBlob);
|
||||
|
||||
// Assume there is an image element with ID 'displayImage' in your HTML
|
||||
const imgElement: HTMLImageElement | null = document.getElementById('displayImage') as HTMLImageElement;
|
||||
if (imgElement) {
|
||||
imgElement.src = imageUrl;
|
||||
}
|
||||
|
||||
console.log('Image URL:', imageUrl);
|
||||
}
|
||||
|
||||
const sampleImageBase64 = "iVBORw0KGgoAAAANSUhEUgAA..."; // A truncated Base64 PNG string
|
||||
displayImageFromBase64(sampleImageBase64);
|
||||
```
|
||||
|
||||
This function demonstrates how to convert Base64 data to a format that can be rendered in a web browser. The process includes decoding the Base64 string, wrapping the resulting Uint8Array in a Blob, and then using a URL.createObjectURL to generate a URL that the <img> tag can consume. Such a sequence is common when dealing with image data received from various APIs or databases.
|
||||
|
||||
#### Error Handling in Decoding
|
||||
|
||||
As with encoding, you should always ensure that the Base64 string you receive is properly formatted:
|
||||
|
||||
```typescript
|
||||
import { base64ToUint8Array } from '@push.rocks/smartbuffer';
|
||||
|
||||
function safeBase64ToUint8Array(input: any): void {
|
||||
try {
|
||||
if (typeof input !== 'string') {
|
||||
throw new Error('Invalid input: Expected a string.');
|
||||
}
|
||||
const uint8Array = base64ToUint8Array(input);
|
||||
console.log('Successfully decoded Uint8Array:', uint8Array);
|
||||
} catch (error) {
|
||||
console.error('Decoding error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing with a valid Base64 string
|
||||
safeBase64ToUint8Array("SGVsbG8=");
|
||||
|
||||
// Testing with invalid input
|
||||
safeBase64ToUint8Array(12345);
|
||||
```
|
||||
|
||||
This pattern ensures that your application handles anomalies gracefully and provides useful debug messages, which are essential for maintaining robust data pipelines.
|
||||
|
||||
---
|
||||
|
||||
### 6. Validating Buffer-like Objects
|
||||
|
||||
In JavaScript, data structures are not always guaranteed to conform to ArrayBuffer or typed array standards. Your application might encounter objects that are “buffer-like” (i.e., they have a byteLength property) even if they are not proper ArrayBuffer instances. The isBufferLike function in @push.rocks/smartbuffer is designed to validate these objects.
|
||||
|
||||
#### Recognizing Valid Buffer-like Objects
|
||||
|
||||
The function isBufferLike performs several checks:
|
||||
- It confirms the object has a numeric byteLength property.
|
||||
- On Node.js environments, it checks if the object qualifies as a Buffer using Buffer.isBuffer.
|
||||
|
||||
Below is a simple demonstration:
|
||||
|
||||
```typescript
|
||||
import { isBufferLike } from '@push.rocks/smartbuffer';
|
||||
|
||||
const validBuffer: ArrayBuffer = new ArrayBuffer(16);
|
||||
const validUint8Array: Uint8Array = new Uint8Array(validBuffer);
|
||||
|
||||
console.log('Is ArrayBuffer valid?:', isBufferLike(validBuffer)); // Expected: true
|
||||
console.log('Is Uint8Array valid?:', isBufferLike(validUint8Array)); // Expected: true
|
||||
|
||||
// Simulate invalid object
|
||||
const invalidBuffer = { someProperty: 'Not a buffer' };
|
||||
console.log('Is invalid object buffer-like?:', isBufferLike(invalidBuffer)); // Expected: false
|
||||
```
|
||||
|
||||
#### Cross-Environment Considerations
|
||||
|
||||
When developing for both Node.js and the browser, ensuring that an object is truly buffer-like comes with subtle differences. The function abstracts away these differences, making the following examples work seamlessly across platforms:
|
||||
|
||||
```typescript
|
||||
import { isBufferLike } from '@push.rocks/smartbuffer';
|
||||
|
||||
function processBuffer(input: any): void {
|
||||
if (!isBufferLike(input)) {
|
||||
console.error('Provided input is not a valid buffer-like object.');
|
||||
return;
|
||||
}
|
||||
// Process a valid buffer here safely
|
||||
console.log('Processing valid buffer-like data.');
|
||||
}
|
||||
|
||||
// Testing in multiple scenarios
|
||||
const sampleArrayBuffer = new ArrayBuffer(8);
|
||||
const sampleUint8Array = new Uint8Array(sampleArrayBuffer);
|
||||
processBuffer(sampleArrayBuffer);
|
||||
processBuffer(sampleUint8Array);
|
||||
processBuffer({ random: 123 });
|
||||
```
|
||||
|
||||
This approach ensures you never inadvertently pass an invalid object to functions that require binary data, thus preventing runtime errors and memory issues.
|
||||
|
||||
---
|
||||
|
||||
### 7. Ensuring Data Purity with ensurePureUint8Array
|
||||
|
||||
In many cases, especially when received from servers or buffers provided by external modules, data might not be in a "pure" Uint8Array form. The ensurePureUint8Array function guarantees that you operate on a fresh Uint8Array, ensuring no side effects or shared references can corrupt your data.
|
||||
|
||||
#### Example of Purifying Data
|
||||
|
||||
This utility comes in handy when you're unsure about the input data type:
|
||||
|
||||
```typescript
|
||||
import { ensurePureUint8Array } from '@push.rocks/smartbuffer';
|
||||
|
||||
function processData(buffer: Uint8Array | Buffer): void {
|
||||
// Ensure that we work with a pure Uint8Array to avoid unintended mutations
|
||||
const pureArray = ensurePureUint8Array(buffer);
|
||||
|
||||
// Proceed with operations on pureArray
|
||||
console.log('Data length:', pureArray.length);
|
||||
}
|
||||
|
||||
// Example usage with a Uint8Array
|
||||
const dataUint8 = new Uint8Array([10, 20, 30, 40]);
|
||||
processData(dataUint8);
|
||||
|
||||
// Example usage with a Buffer (in Node.js environments)
|
||||
// Uncomment the following lines if you are testing in a Node.js environment where Buffer is defined.
|
||||
// const nodeBuffer = Buffer.from([50, 60, 70, 80]);
|
||||
// processData(nodeBuffer);
|
||||
```
|
||||
|
||||
This function creates a new Uint8Array and copies the contents from the input buffer. It helps in scenarios where mutating the original buffer might have unintended consequences, or if the input buffer is a Node.js Buffer while your subsequent operations expect a Uint8Array instance.
|
||||
|
||||
#### Discussion of Underlying Mechanics
|
||||
|
||||
The ensurePureUint8Array function works by:
|
||||
1. Determining the length of the input buffer.
|
||||
2. Creating a new Uint8Array with the same length.
|
||||
3. Copying the content over using the set method.
|
||||
4. Returning the new, independent array.
|
||||
|
||||
This process ensures that even if the original buffer is modified later (for example, through shared state between functions), your operations remain isolated and consistent.
|
||||
|
||||
---
|
||||
|
||||
### 8. Working with Extended Utilities from uint8array-extras
|
||||
|
||||
The @push.rocks/smartbuffer module re-exports a collection of extended functions from the uint8array-extras module. These extra utilities might include methods for additional encoding/decoding schemes, byte-level manipulations, or other niche operations which complement the basic functionalities provided.
|
||||
|
||||
#### Importing and Using uInt8ArrayExtras
|
||||
|
||||
After installing the package, you can access the extra utilities as follows:
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayExtras } from '@push.rocks/smartbuffer';
|
||||
|
||||
// Example use of a hypothetical utility method provided by uInt8ArrayExtras.
|
||||
// Assume uint8ArrayExtras provides a method named reverseBytes.
|
||||
const sampleArray = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
// Check if the method exists and perform additional operations:
|
||||
if (uInt8ArrayExtras.reverseBytes) {
|
||||
const reversedArray = uInt8ArrayExtras.reverseBytes(sampleArray);
|
||||
console.log('Reversed Array:', reversedArray);
|
||||
} else {
|
||||
console.warn('The reverseBytes utility is not available.');
|
||||
}
|
||||
|
||||
// Additionally, you can use other string conversion helpers if available.
|
||||
if (uInt8ArrayExtras.someUtilityMethod) {
|
||||
console.log(uInt8ArrayExtras.someUtilityMethod(sampleArray));
|
||||
}
|
||||
```
|
||||
|
||||
While the example uses a hypothetical "reverseBytes" function, it effectively demonstrates how you can integrate additional utilities into your workflow. Always refer to the latest documentation of uint8array-extras for the currently supported function set.
|
||||
|
||||
#### Enhancing Data Manipulation with Extended Utilities
|
||||
|
||||
Developers dealing with highly specialized binary protocols can benefit from advanced operations like slicing, merging different Uint8Arrays, or applying transformations on the fly. For example:
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayExtras } from '@push.rocks/smartbuffer';
|
||||
|
||||
function mergeDataFragments(fragments: Uint8Array[]): Uint8Array {
|
||||
let totalLength = fragments.reduce((sum, frag) => sum + frag.length, 0);
|
||||
const mergedArray = new Uint8Array(totalLength);
|
||||
|
||||
let offset = 0;
|
||||
for (const fragment of fragments) {
|
||||
mergedArray.set(fragment, offset);
|
||||
offset += fragment.length;
|
||||
}
|
||||
return mergedArray;
|
||||
}
|
||||
|
||||
const fragment1 = new Uint8Array([10, 20]);
|
||||
const fragment2 = new Uint8Array([30, 40, 50]);
|
||||
const fragment3 = new Uint8Array([60]);
|
||||
|
||||
const completeData = mergeDataFragments([fragment1, fragment2, fragment3]);
|
||||
console.log('Merged Uint8Array:', completeData);
|
||||
```
|
||||
|
||||
This example, though independent of the uInt8ArrayExtras utilities, shows how you can combine the extended functionalities and custom implementations to manage complex data scenarios efficiently.
|
||||
|
||||
---
|
||||
|
||||
### 9. Handling Edge Cases and Error Checking
|
||||
|
||||
When working with conversions and buffer validations, it is beneficial to understand and plan for edge cases. Incorrect or unexpected input could lead to exceptions, unhandled rejections, or corrupted data flows. Below are detailed examples of error handling and other defensive programming techniques.
|
||||
|
||||
#### Example: Dealing with Null or Undefined Inputs
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayToBase64, base64ToUint8Array, isBufferLike } from '@push.rocks/smartbuffer';
|
||||
|
||||
function processInput(input: any): void {
|
||||
if (input == null) {
|
||||
console.error('Input is null or undefined.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBufferLike(input)) {
|
||||
// Try converting buffer-like object to Base64 if applicable.
|
||||
try {
|
||||
// Assuming input is a valid Uint8Array
|
||||
const base64Encoded = uInt8ArrayToBase64(new Uint8Array(input as ArrayBuffer));
|
||||
console.log('Safe conversion to Base64:', base64Encoded);
|
||||
} catch (e) {
|
||||
console.error('Error during conversion:', e);
|
||||
}
|
||||
} else if (typeof input === 'string') {
|
||||
try {
|
||||
// Process as Base64
|
||||
const data = base64ToUint8Array(input);
|
||||
console.log('Converted Base64 to Uint8Array:', data);
|
||||
} catch (e) {
|
||||
console.error('Error decoding Base64 string:', e);
|
||||
}
|
||||
} else {
|
||||
console.warn('Unhandled type of input:', input);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing with various edge cases
|
||||
processInput(undefined);
|
||||
processInput(null);
|
||||
processInput("InvalidBase64Data***");
|
||||
processInput(new ArrayBuffer(10));
|
||||
```
|
||||
|
||||
In this sample, different types of input are managed carefully. The function checks for null or undefined, verifies if the input is buffer-like, and takes the appropriate conversion path while catching errors.
|
||||
|
||||
#### Example: Robust Type Checking
|
||||
|
||||
For robust data conversion, verifying input types can pre-empt many runtime errors. The following example creates a type guard and leverages it to safely process binary data:
|
||||
|
||||
```typescript
|
||||
import { isBufferLike, uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
|
||||
function safeProcessBuffer(input: unknown): void {
|
||||
if (isBufferLike(input)) {
|
||||
const uint8array = input instanceof Uint8Array ? input : new Uint8Array(input as ArrayBuffer);
|
||||
try {
|
||||
const encoded = uInt8ArrayToBase64(uint8array);
|
||||
console.log('Encoded safely:', encoded);
|
||||
} catch (err) {
|
||||
console.error('Error encoding buffer:', err);
|
||||
}
|
||||
} else {
|
||||
console.error('Input is not buffer-like. Skipping processing.');
|
||||
}
|
||||
}
|
||||
|
||||
safeProcessBuffer(new ArrayBuffer(8));
|
||||
safeProcessBuffer({ byteLength: 8 });
|
||||
```
|
||||
|
||||
This pattern helps ensure that your application’s core logic remains robust and impervious to malformed data. In mission-critical systems, such defensive practices can greatly reduce bugs and production issues.
|
||||
|
||||
---
|
||||
|
||||
### 10. Integrating smartbuffer into Real-World Applications
|
||||
|
||||
Applications that process binary data often incorporate several of the functions we have reviewed. Below are scenarios illustrating how to integrate smartbuffer into complex and real-world systems.
|
||||
|
||||
#### Scenario 1: File Upload and Processing in a Web Application
|
||||
|
||||
Suppose you are building a web application where users can upload images. Once an image is uploaded, you need to:
|
||||
- Read the file as an ArrayBuffer.
|
||||
- Convert it into a Base64 string to store temporarily or transfer via JSON.
|
||||
- Validate and potentially adjust the binary data.
|
||||
- Present the image back to the user via a Blob URL.
|
||||
|
||||
Below is a comprehensive TypeScript example illustrating this process:
|
||||
|
||||
```typescript
|
||||
import { base64ToUint8Array, uInt8ArrayToBase64, isBufferLike, ensurePureUint8Array } from '@push.rocks/smartbuffer';
|
||||
|
||||
async function handleFileUpload(file: File): Promise<void> {
|
||||
// Step 1: Read file as ArrayBuffer
|
||||
const fileBuffer: ArrayBuffer = await file.arrayBuffer();
|
||||
|
||||
// Step 2: Create a Uint8Array from the ArrayBuffer
|
||||
const fileUint8Array = new Uint8Array(fileBuffer);
|
||||
|
||||
// Step 3: Validate the buffer-like object
|
||||
if (!isBufferLike(fileUint8Array)) {
|
||||
console.error('Uploaded file is not a valid buffer-like object.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 4: Convert the Uint8Array to a Base64 string for potential storage/transmission
|
||||
const base64Representation = uInt8ArrayToBase64(fileUint8Array);
|
||||
console.log('Base64 representation of the file:', base64Representation.substring(0, 100) + '...');
|
||||
|
||||
// Step 5: Use ensurePureUint8Array to create a copy we can safely manipulate
|
||||
const pureUint8Array = ensurePureUint8Array(fileUint8Array);
|
||||
|
||||
// Step 6: Create a Blob object from the pure data
|
||||
const imageBlob = new Blob([pureUint8Array], { type: file.type });
|
||||
|
||||
// Step 7: Create a URL for the Blob and set it to an image element for preview
|
||||
const imageUrl = URL.createObjectURL(imageBlob);
|
||||
const imageElement = document.getElementById('previewImage') as HTMLImageElement;
|
||||
if (imageElement) {
|
||||
imageElement.src = imageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Example integration with an input element
|
||||
const fileInputElement = document.getElementById('fileInput') as HTMLInputElement;
|
||||
if (fileInputElement) {
|
||||
fileInputElement.addEventListener('change', (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files.length > 0) {
|
||||
handleFileUpload(target.files[0]).catch((error) => {
|
||||
console.error('Error handling file upload:', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In this integration example, each function from @push.rocks/smartbuffer plays a critical role in ensuring that file data is processed reliably. The data is validated, converted, and then safely reassembled into a format that is both easy to work with and compatible with web standards.
|
||||
|
||||
#### Scenario 2: Network Communication and Data Serialization
|
||||
|
||||
In a server-client application, binary data must often be serialized for network transmission. Using smartbuffer, you can serialize data into Base64 strings and then deserialize it on the other end.
|
||||
|
||||
```typescript
|
||||
import { base64ToUint8Array, uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
|
||||
// Function sending binary data over HTTP as a JSON payload
|
||||
async function sendBinaryData(url: string, binaryData: Uint8Array): Promise<void> {
|
||||
const base64Payload = uInt8ArrayToBase64(binaryData);
|
||||
const jsonPayload = JSON.stringify({ data: base64Payload });
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: jsonPayload,
|
||||
});
|
||||
|
||||
console.log('Response status:', response.status);
|
||||
}
|
||||
|
||||
// Function receiving the JSON payload and converting it back to binary data
|
||||
async function receiveBinaryData(response: Response): Promise<Uint8Array> {
|
||||
const json = await response.json();
|
||||
return base64ToUint8Array(json.data);
|
||||
}
|
||||
|
||||
// Example usage during API communication
|
||||
(async () => {
|
||||
const serverUrl = 'https://api.example.com/upload';
|
||||
const sampleData = new Uint8Array([100, 101, 102, 103, 104]); // Sample binary payload
|
||||
await sendBinaryData(serverUrl, sampleData);
|
||||
})();
|
||||
```
|
||||
|
||||
This snippet outlines how to convert binary data into a Base64 representation, encapsulate it within a JSON payload, and later decode that payload back into a usable Uint8Array. This is particularly useful when binary data must be transmitted via WebSockets or RESTful APIs that expect text-based data.
|
||||
|
||||
#### Scenario 3: Data Processing in Node.js
|
||||
|
||||
In a Node.js environment, you might need to work directly with Node Buffers, but still want to ensure compatibility with operations that expect Uint8Array. The following example demonstrates such interoperability:
|
||||
|
||||
```typescript
|
||||
import { ensurePureUint8Array, isBufferLike, uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
async function processLocalFile(filePath: string): Promise<void> {
|
||||
try {
|
||||
// Reading a file returns a Node.js Buffer
|
||||
const fileBuffer = await readFile(filePath);
|
||||
|
||||
// Validate that fileBuffer is a buffer-like object
|
||||
if (!isBufferLike(fileBuffer)) {
|
||||
throw new Error('The file is not a valid buffer-like object.');
|
||||
}
|
||||
|
||||
// Convert Buffer to a pure Uint8Array to ensure consistency
|
||||
const pureArray = ensurePureUint8Array(fileBuffer);
|
||||
|
||||
// Now convert the pure Uint8Array to a Base64 encoded string
|
||||
const base64Data = uInt8ArrayToBase64(pureArray);
|
||||
console.log('File in Base64 format:', base64Data.substring(0, 100) + '...');
|
||||
} catch (error) {
|
||||
console.error('Error processing file:', error);
|
||||
}
|
||||
}
|
||||
|
||||
processLocalFile('./assets/sample.bin');
|
||||
```
|
||||
|
||||
This code snippet illustrates the interoperability when you work with Node.js Buffers. The use of ensurePureUint8Array ensures that regardless of the underlying Buffer’s characteristics, your data pipeline remains consistent with typed arrays.
|
||||
|
||||
---
|
||||
|
||||
### 11. Performance Considerations and Best Practices
|
||||
|
||||
When processing binary data—especially in performance-critical applications—it is essential to consider both speed and memory overhead. Here are some best practices when using @push.rocks/smartbuffer:
|
||||
|
||||
1. Always validate your inputs using isBufferLike before performing conversions.
|
||||
2. Use ensurePureUint8Array to break any shared references. This prevents side effects if the original data changes unexpectedly.
|
||||
3. For large data blocks, try processing data in chunks to avoid exhausting memory.
|
||||
4. When converting between representations (e.g., Base64 to Uint8Array), prefer stream-based approaches if your runtime supports them.
|
||||
5. Monitor performance when using utility functions from uint8array-extras, as some extended operations might introduce overhead in critical sections of your application.
|
||||
|
||||
#### Memory Management Example
|
||||
|
||||
Consider the scenario where you need to process large binary files. Instead of loading the entire file into memory, you could process it in manageable chunks:
|
||||
|
||||
```typescript
|
||||
import { uInt8ArrayToBase64 } from '@push.rocks/smartbuffer';
|
||||
|
||||
async function processLargeFileInChunks(file: File): Promise<void> {
|
||||
const chunkSize = 1024 * 64; // 64KB per chunk
|
||||
const fileSize = file.size;
|
||||
let offset = 0;
|
||||
|
||||
while (offset < fileSize) {
|
||||
const slice = file.slice(offset, offset + chunkSize);
|
||||
const arrayBuffer = await slice.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
// Process each chunk by converting to Base64 (or any processing logic)
|
||||
const base64Chunk = uInt8ArrayToBase64(uint8Array);
|
||||
console.log(`Processing chunk from offset ${offset}:`, base64Chunk.substring(0, 50) + '...');
|
||||
|
||||
offset += chunkSize;
|
||||
}
|
||||
}
|
||||
|
||||
const fileInput = document.getElementById('largeFileInput') as HTMLInputElement;
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener('change', (event: Event) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files && target.files.length > 0) {
|
||||
processLargeFileInChunks(target.files[0])
|
||||
.catch(err => console.error('Error processing large file:', err));
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
This pattern is useful when dealing with streaming data or very large files, thereby keeping your application responsive.
|
||||
|
||||
---
|
||||
|
||||
### 12. Comprehensive Code Examples and Use Cases
|
||||
|
||||
Below is a complete consolidated example that demonstrates multiple functionalities of @push.rocks/smartbuffer integrated within a single project. The following code snippet simulates a scenario where binary data is received, transformed, validated, and used to generate a visual output on a web page.
|
||||
|
||||
```typescript
|
||||
import {
|
||||
uInt8ArrayToBase64,
|
||||
base64ToUint8Array,
|
||||
isBufferLike,
|
||||
ensurePureUint8Array,
|
||||
uInt8ArrayExtras,
|
||||
} from '@push.rocks/smartbuffer';
|
||||
|
||||
// Simulate receiving binary data from an external service.
|
||||
async function fetchBinaryData(url: string): Promise<Uint8Array> {
|
||||
const response = await fetch(url);
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
return new Uint8Array(arrayBuffer);
|
||||
}
|
||||
|
||||
// Process the binary data:
|
||||
// 1. Validate the data.
|
||||
// 2. Convert to Base64.
|
||||
// 3. Manipulate using extended utilities.
|
||||
// 4. Render image on a webpage.
|
||||
async function processAndRenderImage(url: string): Promise<void> {
|
||||
try {
|
||||
const binaryData = await fetchBinaryData(url);
|
||||
|
||||
if (!isBufferLike(binaryData)) {
|
||||
console.error('The fetched data is not buffer-like.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert binary data to Base64
|
||||
const base64Encoded = uInt8ArrayToBase64(binaryData);
|
||||
console.log('Encoded data (first 100 chars):', base64Encoded.substring(0, 100) + '...');
|
||||
|
||||
// Using the extra utilities (if available, e.g., reversing the byte order)
|
||||
if (uInt8ArrayExtras && typeof uInt8ArrayExtras.reverseBytes === 'function') {
|
||||
const reversed = uInt8ArrayExtras.reverseBytes(binaryData);
|
||||
console.log('Reversed data example:', reversed.slice(0, 10));
|
||||
}
|
||||
|
||||
// Convert the Base64 string back to a Uint8Array
|
||||
const decodedData = base64ToUint8Array(base64Encoded);
|
||||
|
||||
// Ensure we are working with a pure Uint8Array
|
||||
const cleanedData = ensurePureUint8Array(decodedData);
|
||||
|
||||
// Create a Blob from the cleaned data
|
||||
const imageBlob = new Blob([cleanedData], { type: 'image/jpeg' });
|
||||
const imageUrl = URL.createObjectURL(imageBlob);
|
||||
|
||||
// Create an image element dynamically and attach to the DOM
|
||||
const imgElement = document.createElement('img');
|
||||
imgElement.src = imageUrl;
|
||||
imgElement.alt = 'Processed Image';
|
||||
imgElement.style.maxWidth = '100%';
|
||||
document.body.appendChild(imgElement);
|
||||
|
||||
console.log('Image rendered successfully.');
|
||||
} catch (error) {
|
||||
console.error('Error processing and rendering image:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Example usage: Replace the URL below with the path to your binary image data.
|
||||
processAndRenderImage('https://example.com/path/to/binary/image');
|
||||
```
|
||||
|
||||
This end-to-end example illustrates how you might receive binary data, perform all necessary transformations, and integrate with both network and DOM elements. The modular design of @push.rocks/smartbuffer makes it easy to swap out or extend functionalities as required by your application's evolving needs.
|
||||
|
||||
---
|
||||
|
||||
### 13. Debugging and Testing Your Implementation
|
||||
|
||||
A rigorous testing strategy is essential when working with binary data. Utilize unit tests to verify that:
|
||||
- Uint8Array conversions maintain data integrity.
|
||||
- Invalid inputs are correctly rejected.
|
||||
- Edge cases (such as empty arrays or mismatched encodings) are handled gracefully.
|
||||
|
||||
Consider using the testing framework provided by @push.rocks/tapbundle for your unit tests:
|
||||
|
||||
```typescript
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
import {
|
||||
uInt8ArrayToBase64,
|
||||
base64ToUint8Array,
|
||||
isBufferLike,
|
||||
ensurePureUint8Array,
|
||||
} from '@push.rocks/smartbuffer';
|
||||
|
||||
tap.test('Conversion Integrity Test', async () => {
|
||||
const original = new Uint8Array([65, 66, 67, 68]); // Represents "ABCD"
|
||||
const base64Result = uInt8ArrayToBase64(original);
|
||||
const converted = base64ToUint8Array(base64Result);
|
||||
|
||||
// Ensure that the conversion cycle retains all information
|
||||
expect(converted.length).toBe(original.length);
|
||||
for (let i = 0; i < original.length; i++) {
|
||||
expect(converted[i]).toBe(original[i]);
|
||||
}
|
||||
});
|
||||
|
||||
tap.test('Buffer-like Validation Test', async () => {
|
||||
const arrayBuffer = new ArrayBuffer(10);
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
expect(isBufferLike(arrayBuffer)).toBe(true);
|
||||
expect(isBufferLike(uint8Array)).toBe(true);
|
||||
expect(isBufferLike({ random: true })).toBe(false);
|
||||
});
|
||||
|
||||
tap.start();
|
||||
```
|
||||
|
||||
These tests help ensure that your implementations using smartbuffer behave as expected and provide a reliable safety net during development and continuous integration.
|
||||
|
||||
---
|
||||
|
||||
### 14. Advanced Topics and Future Directions
|
||||
|
||||
As you integrate @push.rocks/smartbuffer into your projects, you might uncover advanced scenarios that require additional considerations. Below are several advanced topics and suggestions for extending the functionality within your own environment:
|
||||
|
||||
#### Custom Conversions and Interoperability
|
||||
|
||||
Developers may wish to implement custom conversion routines that go beyond standard Base64 encoding. For example, you might need to support URL-safe Base64 variants or other encoding schemes (e.g., hexadecimal). You can achieve this by combining smartbuffer utilities with additional libraries—enhancing your data pipeline without losing the core benefits of validated conversions and pure typed arrays.
|
||||
|
||||
#### Integration with WebAssembly
|
||||
|
||||
When performance is paramount, especially for data-intensive tasks, consider offloading certain conversion routines to WebAssembly. Using WebAssembly modules alongside smartbuffer can greatly boost performance when processing large volumes of binary data.
|
||||
|
||||
#### Extending uInt8ArrayExtras
|
||||
|
||||
The exported uInt8ArrayExtras module from smartbuffer is a gateway to several advanced typed array operations. Future development might include new methods for handling compression, encryption, or even more complex transformations. Contributing to and extending these utilities can be a path for collaborative development in your team.
|
||||
|
||||
#### Debugging Binary Data
|
||||
|
||||
Tools like hex editors or custom debugging utilities can be integrated into your development workflow. By converting Uint8Arrays into human-readable formats (such as formatted hexadecimal strings), you can enhance your ability to detect subtle errors in data streams. Consider adding helper functions to your project that utilize smartbuffer's conversion methods as a starting point for deeper diagnostics.
|
||||
|
||||
#### Cross-Platform Considerations
|
||||
|
||||
Different runtime environments handle binary data in subtly different ways. While smartbuffer abstracts many of these differences, be mindful when sharing data between web browsers, Node.js backends, or even mobile platforms. Rigorous cross-platform testing is advisable when deploying applications that heavily rely on binary data transformations.
|
||||
|
||||
#### Scalability and Efficiency
|
||||
|
||||
As your application scales, efficiency in data processing becomes critical. Measure performance impacts when converting very large arrays or processing frequent network messages. Profiling your code and leveraging asynchronous operations where necessary can prevent bottlenecks in production systems.
|
||||
|
||||
---
|
||||
|
||||
### Detailed Walkthrough of Advanced Use Cases
|
||||
|
||||
To further extend our discussion, below is an in-depth analysis of a complex use case where multiple functionalities of smartbuffer are integrated into a single workflow.
|
||||
|
||||
Imagine you are designing a real-time collaborative whiteboard application. This web application communicates with a server via WebSockets. Binary data representing drawing actions (e.g., strokes, shapes, colors) are transmitted between clients and the server. For performance and security reasons, the drawing data are encoded in Base64 format for transmission and immediately decoded on the client side to update the drawing canvas.
|
||||
|
||||
#### Step-by-Step Process
|
||||
|
||||
1. The client collects drawing actions which are stored in a sequence of Uint8Arrays.
|
||||
2. Prior to transmission, these Uint8Arrays are converted to a Base64 string using uInt8ArrayToBase64.
|
||||
3. The data is then packaged into a JSON payload and sent over a WebSocket connection.
|
||||
4. Upon receiving the message, the client's application uses base64ToUint8Array to decode the string back to its binary form.
|
||||
5. The decoded data is validated using isBufferLike.
|
||||
6. The drawing actions are then applied to the collaborative canvas.
|
||||
|
||||
##### Client-Side Implementation Example
|
||||
|
||||
```typescript
|
||||
import {
|
||||
uInt8ArrayToBase64,
|
||||
base64ToUint8Array,
|
||||
isBufferLike,
|
||||
ensurePureUint8Array
|
||||
} from '@push.rocks/smartbuffer';
|
||||
|
||||
// Function to prepare drawing data for sending
|
||||
function prepareDrawingData(drawingActions: Uint8Array[]): string {
|
||||
const mergedData = drawingActions.reduce((acc, curr) => {
|
||||
const temp = new Uint8Array(acc.length + curr.length);
|
||||
temp.set(acc, 0);
|
||||
temp.set(curr, acc.length);
|
||||
return temp;
|
||||
}, new Uint8Array());
|
||||
|
||||
return uInt8ArrayToBase64(mergedData);
|
||||
}
|
||||
|
||||
// Function to process received drawing data
|
||||
function processReceivedData(base64Data: string): void {
|
||||
const decodedArray = base64ToUint8Array(base64Data);
|
||||
if (!isBufferLike(decodedArray)) {
|
||||
console.error('Received drawing data is not valid.');
|
||||
return;
|
||||
}
|
||||
const pureArray = ensurePureUint8Array(decodedArray);
|
||||
|
||||
// Interpret the pureArray data as drawing actions
|
||||
// (For demonstration, we simply log the extracted values)
|
||||
console.log('Received drawing actions:', pureArray);
|
||||
|
||||
// In a real scenario, further logic will convert the pureArray into actionable drawing commands
|
||||
}
|
||||
|
||||
// Simulated WebSocket message handling
|
||||
function simulateWebSocket(): void {
|
||||
// Example drawing actions as Uint8Array fragments
|
||||
const action1 = new Uint8Array([1, 50, 100]);
|
||||
const action2 = new Uint8Array([2, 150, 200]);
|
||||
|
||||
// Client encodes drawing actions before sending
|
||||
const encodedMessage = prepareDrawingData([action1, action2]);
|
||||
console.log('Encoded drawing data for transmission:', encodedMessage.substring(0, 100) + '...');
|
||||
|
||||
// Simulate receiving the same message
|
||||
processReceivedData(encodedMessage);
|
||||
}
|
||||
|
||||
simulateWebSocket();
|
||||
```
|
||||
|
||||
#### Discussion
|
||||
|
||||
- In this detailed example, we see how the merging of Uint8Array fragments is handled seamlessly.
|
||||
- The encoded message, a Base64 string, ensures that the data transmitted over the WebSocket is text-safe.
|
||||
- On reception, a series of validations and transformations convert the message back into actionable data.
|
||||
- This modular design allows for easy replacement or extension of each step, enabling future improvements such as compression or encryption.
|
||||
|
||||
---
|
||||
|
||||
### Summing Up the Extensive Usage Details
|
||||
|
||||
The comprehensive examples described above demonstrate the many capabilities of @push.rocks/smartbuffer. They range from simple data conversions to intricate workflows involving network data transmission and real-time application updates. Each function provided by the module plays a specific role in ensuring that binary data is handled efficiently, accurately, and securely.
|
||||
|
||||
By adopting these utilities, you can focus your development efforts on business logic and application features rather than the intricacies of binary data manipulation. The module’s robust error handling, logging, and defensive design patterns help mitigate common pitfalls related to low-level data processing.
|
||||
|
||||
We encourage developers to integrate these techniques and adjust them according to their unique requirements. Whether you are processing image uploads, handling real-time data from a collaborative app, or simply managing buffer validations, @push.rocks/smartbuffer offers a versatile toolkit that promises reliability and performance across various environments.
|
||||
|
||||
Throughout this detailed guide, we have explored every critical aspect of working with ArrayBufferLike structures—from encoding to validation, handling large data sets, interoperating between different runtime environments, and even integrating helper functionalities that push the boundaries of typical binary data handling in TypeScript.
|
||||
|
||||
As you incorporate these practices into your applications, you will find that adhering to robust conversion patterns and thorough validation not only improves the reliability of your codebase but also simplifies maintenance and future feature expansion.
|
||||
|
||||
Happy coding and exploring the many advanced aspects of binary data manipulation with @push.rocks/smartbuffer!
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
21
test/test.both.ts
Normal file
21
test/test.both.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { expect, expectAsync, tap } from '@push.rocks/tapbundle';
|
||||
import * as smartbuffer from '../ts/index.js';
|
||||
|
||||
tap.test('first test', async () => {
|
||||
console.log(smartbuffer);
|
||||
});
|
||||
|
||||
tap.test('should recognize different buffer like objects', async () => {
|
||||
// const testBuffer = Buffer.from('test');
|
||||
const testArrayBuffer = new ArrayBuffer(4);
|
||||
const testUint8Array = new Uint8Array(testArrayBuffer);
|
||||
testUint8Array[0] = 116;
|
||||
testUint8Array[1] = 101;
|
||||
testUint8Array[2] = 115;
|
||||
testUint8Array[3] = 116;
|
||||
// expect(smartbuffer.isBufferLike(testBuffer)).toBeTrue();
|
||||
expect(smartbuffer.isBufferLike(testArrayBuffer)).toBeTrue();
|
||||
expect(smartbuffer.isBufferLike(testUint8Array)).toBeTrue();
|
||||
});
|
||||
|
||||
tap.start();
|
@ -1,8 +0,0 @@
|
||||
import { expect, expectAsync, tap } from '@pushrocks/tapbundle';
|
||||
import * as smartbuffer from '../ts/index.js';
|
||||
|
||||
tap.test('first test', async () => {
|
||||
console.log(smartbuffer);
|
||||
});
|
||||
|
||||
tap.start();
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@pushrocks/smartbuffer',
|
||||
version: '1.0.2',
|
||||
description: 'handle ArrayBufferLike structures'
|
||||
name: '@push.rocks/smartbuffer',
|
||||
version: '3.0.5',
|
||||
description: 'A robust TypeScript library for managing binary data by converting between Base64 strings and Uint8Array, validating buffer-like objects, and ensuring data purity.'
|
||||
}
|
||||
|
37
ts/index.ts
37
ts/index.ts
@ -1,3 +1,38 @@
|
||||
import * as plugins from './smartbuffer.plugins.js';
|
||||
|
||||
export let demoExport = 'Hi there! :) This is an exported string';
|
||||
export const uInt8ArrayExtras = plugins.uInt8ArrayExtras;
|
||||
|
||||
export function uInt8ArrayToBase64(uInt8Array: Uint8Array): string {
|
||||
return plugins.uInt8ArrayExtras.uint8ArrayToBase64(uInt8Array);
|
||||
}
|
||||
|
||||
export function base64ToUint8Array(base64: string): Uint8Array {
|
||||
return plugins.uInt8ArrayExtras.base64ToUint8Array(base64);
|
||||
}
|
||||
|
||||
export const isUint8Array = (obj: any): obj is Uint8Array => {
|
||||
return plugins.uInt8ArrayExtras.isUint8Array(obj);
|
||||
};
|
||||
|
||||
export function isBufferLike(obj: any): obj is ArrayBufferLike | Buffer {
|
||||
// Check for ArrayBufferLike objects in any environment
|
||||
if (obj && typeof obj.byteLength === 'number') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Additional check specific to Node.js environment for Buffer objects
|
||||
if (typeof Buffer !== 'undefined' && Buffer.isBuffer) {
|
||||
return Buffer.isBuffer(obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function ensurePureUint8Array(bufferArg: Uint8Array | Buffer): Uint8Array {
|
||||
// Create a new Uint8Array with the same length as the buffer
|
||||
const uint8Array: Uint8Array = new Uint8Array(bufferArg.length);
|
||||
|
||||
// Copy the contents of the Buffer to the new Uint8Array
|
||||
uint8Array.set(bufferArg);
|
||||
return uint8Array;
|
||||
}
|
||||
|
@ -1,2 +1,5 @@
|
||||
const removeme = {};
|
||||
export { removeme };
|
||||
import * as uInt8ArrayExtras from 'uint8array-extras';
|
||||
|
||||
export {
|
||||
uInt8ArrayExtras,
|
||||
}
|
@ -3,7 +3,12 @@
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "nodenext"
|
||||
}
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user