26-6-9 스팀 개발 소식 dsteem 개선과 출시

in AVLE 일상4 hours ago

일전에 올렸던 dsteem의 개선소식이 올라왔습니다. 저도 프로그램을 만들어 올리면서 dsteem이 너무 오래되어서 고생했던 경험이 있었습니다. 그런데 이제 @blaze.apps 가 일전에 올린 내용 중 일부 버그를 수정해서 다시 올렸습니다.

https://steemit.com/steem-dev/@blaze.apps/dsteem-release-0-12-2-on-npmjs-blazeapps-dsteem

사용용례는 아래와 같습니다.
https://blazeapps007.github.io/dsteem/

지금처럼 어려운 상황에서 지속적으로 작업을 하고 있는 개발자들이 있어서 스팀의 미래는 밝다고 하겠습니다.

아래는 dsteem의 용도에 대한 설명과 포스트를 한글로 번역한 것입니다.


1. dsteem이란 무엇이며 어떤 용도로 사용되나요?

dsteem스팀(Steem) 블록체인과 상호작용하기 위해 사용하는 자바스크립트/타입스크립트(JavaScript/TypeScript) 라이브러리입니다.

주로 웹 개발자나 앱 개발자들이 스팀 블록체인을 기반으로 한 서비스(DApp, 탈중앙화 애플리케이션)를 만들 때 사용하며, 구체적으로 다음과 같은 용도로 쓰입니다.

  • 블록체인 데이터 조회 (Client.database): 스팀 블록체인에 저장된 블록 정보, 특정 사용자의 프로필, 작성된 포스팅 글, 댓글, 잔고(STEEM, SBD 등) 데이터를 실시간으로 읽어옵니다.
  • 트랜잭션 생성 및 전송 (Client.broadcast): 사용자가 스팀잇에 글을 쓰거나(comment), 다른 사람에게 보팅을 하거나(vote), 토큰을 송금(transfer)할 때, 이 동작을 블록체인이 이해할 수 있는 트랜잭션 형태로 만들고 서명하여 블록체인 네트워크에 전송(브로드캐스트)합니다.
  • 암호화 및 키 관리 (PrivateKey): 사용자의 포스팅 키나 액티브 키 같은 암호화 키를 안전하게 다루고, 트랜잭션에 디지털 서명을 할 수 있도록 도와줍니다.

이번 업데이트(@blazeapps/dsteem)의 의의:
기존 오리지널 dsteem 라이브러리는 2019년(v0.11.3) 이후로 업데이트가 멈춰 있어서 최신 개발 환경(Node.js 최신 버전, React Native, Vite 등)과 호환되지 않고 보안 취약점이 있었습니다. 개발자 blaze.apps기존의 기능과 사용법(API)은 100% 똑같이 유지하면서, 내부 코드와 보안 취약점을 완전히 최신 상태로 뜯어고쳐 새롭게 출시한 것이 바로 이 @blazeapps/dsteem 패키지입니다.


2. 본문 한글 번역

npmjs에 dsteem 0.12.2 출시 @blazeapps/dsteem

blaze.apps (인증된 개발자) - Steem Dev에서 14시간 전 (수정됨)

어제 올린 브라우저 테스트 하네스(Harness) 포스팅에 이어 피드백을 공유합니다. 현대화된 dsteem 라이브러리가 npm에 @blazeapps/[email protected] 버전으로 정식 게시되었습니다.

이 글은 페이즈 0(Phase 0) 기획 문서부터 오늘의 npm 배포까지, 지난 11일간 진행된 전체 시리즈를 마무리하는 글입니다. 총 12개의 포스팅, 8개의 개발 단계(Phase), 3번의 마일스톤 업데이트, 1개의 패키지 출시, 그리고 테스트 하네스가 잡아내지 못한 버그를 실제 엑스포(Expo) 사용자가 발견한 덕분에 당일 진행된 2번의 패치까지 포함되어 있습니다. 소프트웨어가 실제로 어떻게 출시되는지에 대한 솔직한 기록입니다.

지금 이용 가능

npm install @blazeapps/dsteem

한 줄 마이그레이션 방법: 기존 코드에서 from 'dsteem'으로 되어 있는 모든 부분을 from '@blazeapps/dsteem'으로 바꾸기만 하면 됩니다. 공개 API는 기존 v0.11.3 버전과 바이트 단위까지 동일합니다. (클래스, 메서드, 반환 타입 모두 같음) npm에 있는 기존 [email protected]은 그대로 유지되며, 이번 배포는 새로운 스코프(scope) 아래에서 독립적으로 진행된 클린 배포입니다.

  • 지원 대상: Node.js 22 이상, 모던 브라우저 (번들러 사용 또는 <script> 직접 삽입), React Native / Expo SDK 50–55 (v0.12.2부터 Metro 번들러 지원 — Buffer 및 Node 내장 모듈이 패키지 내부에 인라인되어 있어 사용자가 별도로 global.Buffer 심(shim)을 설정할 필요가 없습니다).

v0.12.0 → v0.12.1 → v0.12.2 — 두 번의 패치, 하나의 진짜 버그

첫 배포 후 몇 시간 만에 Expo를 사용하는 유저에게서 다음과 같은 에러 리포트가 들어왔습니다.

_blazeappsDsteem.Client is not a constructor

  • 원인: package.json"browser" 조건이 모듈 시스템 내보내기(export)가 없는 IIFE 번들을 가리키고 있었습니다. IIFE는 <script src="">로 직접 불러와 var dsteem = ... 형태로 쓰기 위한 것입니다. 하지만 Metro 번들러가 이를 모듈로 오인해 가져오면서 Client 대신 undefined를 노출했던 것입니다.

v0.12.1 버전에서는 브라우저/리액트 네이티브 환경의 경로를 IIFE 대신 Node CommonJS 빌드(dist/index.cjs)로 변경했습니다. 이로써 "not a constructor" 에러는 해결되었지만, 더 깊은 곳에 있던 버그가 드러났습니다.

Requiring unknown module "buffer"

Node CJS 빌드는 esbuild의 동적 __require() 심을 통해 Node 내장 모듈을 외부에서 가져옵니다. 이는 Node 환경에서는 정상 작동하지만, Metro 번들러 환경에서는 작동하지 않습니다. Metro는 간접적인 require 문을 정적으로 분석하지 못하므로 buffer를 번들링하지 못하고 런타임에서 에러가 터지게 됩니다. 당시 진단 결과는 다음과 같았습니다.

$ grep -oE '__require[0-9]?\("(buffer|stream|util|assert)"\)' dist/index.cjs
__require("assert")
__require("buffer")
__require("stream")
__require("util")

dist/index.mjs도 마찬가지였습니다. 리액트 네이티브(RN) 엔트리에 시한폭탄 4개가 숨어 있었던 셈입니다. 반면 IIFE 번들에는 이런 누수가 전혀 없었습니다(esbuild-plugin-polyfill-node를 통해 완전히 폴리필되었기 때문). 하지만 IIFE는 모듈 형태로 가져와 쓸 수 없었습니다. 결론적으로, 폴리필은 되어 있지만 번들러가 쓸 수 없는 번들과, 모듈 형태이지만 폴리필이 안 된 번들만 있었던 것이죠. 둘 다 RN에서는 쓸 수 없었습니다.

v0.12.2 버전이 진짜 해결책입니다. 우리는 tsup의 세 번째 빌드 타겟을 추가했습니다. IIFE와 동일한 소스(src/index-browser.ts) 및 폴리필 플러그인을 사용하되, IIFE 대신 ESM + CJS 모듈 형태로 출력하도록 했습니다. 새로운 파일인 dist/index.browser.{mjs,cjs}는 다음과 같은 특징을 가집니다.

  1. 모든 Node 내장 모듈(buffer, stream, util, assert, process, crypto 등)이 번들 안에 직접 인라인(포함)되었습니다. (검색 결과 매칭되는 __require문 없음 확인)
  2. 실제 명명된 내보내기(Named Export)를 지원합니다. (.mjs에서는 export { Client, ... }, .cjs에서는 exports.Client = Client;)
  3. Node 빌드와 동일한 22개의 명명된 내보내기를 가지므로, 번들러가 어떤 엔트리를 선택하든 공개 API 표면은 완전히 동일합니다.

이제 package.json의 exports 맵은 react-nativebrowser 환경을 폴리필된 모듈 빌드인 dist/index.browser.mjs로 라우팅합니다. Node 환경용 엔트리(dist/index.{cjs,mjs})는 변경 없이 가볍게 유지됩니다(~230 KB). IIFE 번들 역시 직접 CDN으로 쓸 수 있게 유지됩니다.

환경별 해석 방식 요약 테이블

환경 (Consumer)참조하는 파일특징
Node importdist/index.mjs용량이 작음 (229 KB), Node 고유의 내장 buffer/stream 등 사용
Node requiredist/index.cjs위와 동일, CommonJS 호출자용
React Native (Metro)dist/index.browser.mjs모든 Node 내장 모듈이 인라인되어 "unknown module buffer" 에러 해결
브라우저 번들러 (Webpack/Vite/Rollup)dist/index.browser.mjs위와 동일 — 어떤 브라우저 번들러 환경에서도 작동
직접 / unpkgdist/dsteem.browser.global.jsIIFE 포맷, 기존과 동일

교훈: 출시 후 1시간 만에 실제 RN 앱에 적용해 테스트한 결과는, 8일간의 내부 테스트와 브라우저 테스트 하네스가 잡아내지 못한 것을 찾아냈습니다. 테스트 하네스는 일반 브라우저에서의 동작만 검증할 뿐, Metro 번들러의 모듈 해석 경로 나 간접 __require() 호출 방식까지는 테스트하지 못하기 때문입니다. 하루 간격으로 발생한 두 번의 실패와 한 명의 실제 유저가 큰 차이를 만들었습니다. v0.12.1은 선의로 급히 배포된 불완전한 패치였고, v0.12.2에 이르러서야 진짜 버그가 수정되었습니다.


여정의 요약 (한눈에 보기)

날짜단계 (Phase)변경 내용
Day 1 (05-30)Phase 0기획 및 기술 결정 확정 + 초기 암호화 고정 픽스처(fixtures) 확보
Day 2 (05-31)Phase 1GitHub Actions CI 워크플로우 도입 (기존 CircleCI + Travis 대체)
Day 3 (06-01)Phase 2tslint → ESLint 9 플랫 설정 + typescript-eslint 8 전환
Day 4 (06-02)Phase 3TypeScript 3.1 → 5.6 업그레이드 + 엄격 모드(strict mode) 적용
Day 5 (06-03)Phase 4심각한 취약점이 있던 native [email protected]@noble/curves + @noble/hashes로 교체
Day 6 (06-04)Phase 5구형 빌드 도구들을 tsup으로 단일화, ESM/CJS 듀얼 지원, 의존성 패키지 606개 삭제
Day 7 (06-05)Phase 6mocha 5 → 11, nyc → c8 도입(테스트 커버리지 70% 제한), Karma+Sauce → Playwright 헤드리스 브라우저 테스트 도입
Day 8 (06-06)Phase 7typedoc 0.13 → 0.28 업그레이드 및 문서 재생성
Day 9 (06-07)Milestone8개 단계의 모든 코드를 브랜치에 푸시, Node 22, 24 및 Playwright CI 통과
Day 9 (06-07)UpdateGitHub Pages에 typedoc 문서 사이트 배포
Day 10 (06-08)Update문서와 함께 브라우저 테스트 하네스 배포 (47개 오퍼레이션 × 10개 탭)
Day 11 (06-08)Release@blazeapps/[email protected] 출시 → 당일 패치 0.12.1 거쳐 0.12.2(리액트 네이티브 진짜 수정본) 최종 완료

가장 중요했던 단 하나의 결정은 "공개 API를 기존과 완벽히 똑같이 유지한다"는 것이었습니다. 덕분에 각 단계를 독립적으로 배포할 수 있었고, 마이그레이션은 한 줄짜리 이름 바꾸기가 되었으며, 기존 v0.11.3의 암호화 픽스처를 회귀 테스트의 강력한 관문으로 사용할 수 있었습니다.


실제로 npm에 배포된 내용

$ npm pack --dry-run
@blazeapps/[email protected]
1.7 kB    LICENSE
9.1 kB    README.md
2.3 kB    package.json
359.4 kB  dist/dsteem.browser.global.js    (IIFE — <script>/unpkg용)
737.4 kB  dist/index.browser.cjs           (폴리필된 CJS — 브라우저/RN CJS 번들러용)
736.9 kB  dist/index.browser.mjs           (폴리필된 ESM — 브라우저/RN/Metro 최신 경로용)
229.9 kB  dist/index.cjs                   (Node CJS — 외부에 의존하는 빌드)
228.9 kB  dist/index.mjs                   (Node ESM — 외부에 의존하는 빌드)
92.0 kB   dist/index.d.ts                  (타입 정의 파일)
92.0 kB   dist/index.d.mts                 (타입 정의 파일, 듀얼 패키지용)
+ 각 파일별 소스맵(source maps) 포함
─────────────────────────
파일 15개, 압축 시 1.8 MB, 압축 해제 시 9.2 MB

그 외에 src/, test/ 등 불필요한 파일은 전혀 포함되지 않았습니다. package.json"files": ["dist"] 설정이 정확히 작동하고 있습니다.

왜 용량이 커졌을까요? v0.12.1은 795.7 KB였으나, v0.12.2는 1.8 MB입니다. 추가된 대략 1MB의 용량은 두 개의 새로운 index.browser.* 파일에 내장된 폴리필 그래프(buffer, stream, util 등) 때문입니다. 이는 의도된 트레이드오프(타협)입니다. 번들러를 쓰는 사용자들은 호스트 측의 추가 설정 없이 설치 즉시 작동하는 독립적인 모듈을 얻게 되며, Node 사용자는 여전히 230 KB의 가벼운 빌드를 이용할 수 있습니다.


핵심 수치 변화

지표v0.11.3 (2019년 11월)v0.12.2 (2026년 6월)변경점
최저 Node 버전Node 8 시절Node 22 LTS 이상+14 메이저 버전 업
TypeScript3.1.65.6.3+4 메이저 버전 업
브라우저 번들782 KB351 KB (IIFE) + 737 KB (폴리필 모듈)IIFE 기준 -55%, 모듈 방식 신설
암호화 백엔드native [email protected] (심각한 CVE 취약점 있음)@noble/curves + @noble/hashes (검증된 순수 JS)취약점 제거, 네이티브 빌드 불필요
린터 (Lint)tslint (2019년 단종)ESLint 9 플랫 설정경고 0, 에러 0
테스트 러너mocha 5mocha 11+6 메이저 버전 업
테스트 커버리지nycc8 (CI에서 70% 라인 게이트 강제)교체 완료
브라우저 테스트Karma + Sauce LabsPlaywright 헤드리스 (Chromium/Firefox/WebKit)교체 완료
CI 시스템CircleCI + TravisGitHub Actions 매트릭스교체 완료
빌드 도구browserify + tsify + babelify 등 복잡한 도구들tsup (esbuild 기반)단일 도구로 통합
node_modules 항목 수기준점기준점 대비 -606개 패키지대폭 감소
오래된 폴리필 삭제core-js@2, regenerator-runtime 등 존재전부 제거2019년 이후 방치된 코드 청소
모듈 포맷CJS 전용ESM + CJS + 폴리필 ESM/CJS + IIFE 모두 지원대폭 확장
React Native / Expo지원 안 됨 (Metro 해킹 필요)폴리필 모듈 빌드로 기본 지원v0.12.2 신규 지원
프로덕션 npm 오디트높은 위험도 1개 (secp256k1)취약점 0개깨끗함
공개 API기준점100% 동일 (클래스, 메서드, 반환 타입 보존)유지됨
수동 작업 커버리지없음테스트 하네스 내 47개 오퍼레이션 × 10개 탭추가됨

마이그레이션 방법

1. Node.js 및 일반 브라우저 번들러 환경

  • 1단계: package.json을 수정합니다.

  • "dsteem": "^0.11.3"

  • "@blazeapps/dsteem": "^0.12.2"

* **2단계:** 모든 import 문을 업데이트합니다.
  ```javascript
- import { Client, PrivateKey } from 'dsteem'
+ import { Client, PrivateKey } from '@blazeapps/dsteem'

- const { Client } = require('dsteem')
+ const { Client } = require('@blazeapps/dsteem')

  • 3단계: 런타임 환경이 Node.js 22 LTS 이상인지 확인합니다. 끝입니다! 기존의 Client.database.*, PrivateKey.fromLogin 등 모든 기능이 똑같이 작동합니다.

2. React Native / Expo 환경

RN의 자바스크립트 런타임(Hermes/JSC)에는 @noble/curves가 필요로 하는 웹 크립토의 getRandomValues 함수가 없습니다. v0.12.2 버전에서는 Buffer를 포함한 다른 것들은 다 내장되어 있으므로, 오직 단 하나의 폴리필만 추가로 설치해 주면 됩니다.

npm install @blazeapps/dsteem react-native-get-random-values

앱의 가장 최상위 엔트리 파일(index.js 또는 App.tsx)에서, @blazeapps/dsteem을 불러오기 전 최상단에 아래 코드를 넣으세요.

import 'react-native-get-random-values'

그 외 다른 곳에서는 평소처럼 쓰시면 됩니다.

import { Client, PrivateKey } from '@blazeapps/dsteem'
const client = new Client('https://api.steemit.com')

업그레이드 후 Metro 캐시를 한 번 지워주세요. (npx expo start --clear) 다른 특수한 설정은 필요 없습니다.

(만약 v0.12.1을 쓰고 계셨다면, 기존에 추가했던 import {Buffer} from 'buffer'global.Buffer = Buffer 코드는 v0.12.2에서 필요 없어졌으므로 지우셔도 됩니다.)


보안적 성과

이번 작업의 가장 중요한 이유들입니다.

  • 고위험군 보안 권고 대상이었던 [email protected]를 제거했습니다. 대신 ethers나 viem 라이브러리에서 사용하는, 검증되고 순수한 자바스크립트 라이브러리인 @noble/curves@noble/hashes로 교체했습니다.
  • 네이티브 빌드(C++ 기반 컴파일) 과정이 사라졌습니다. 더 이상 node-gyp나 플랫폼별 설치 오류 때문에 고생할 필요가 없습니다.
  • 지원이 중단된 오래된 패키지(tslint, core-js@2 등)를 완전히 제거했습니다. 프로덕션 환경에서 npm audit을 실행하면 취약점이 0개로 나옵니다.

앞으로의 계획

이것으로 v0.12 릴리즈 사이클이 마무리되었으며, 패키지는 v0.12.2에서 안정화되었습니다. 다음 업데이트는 일정 기준이 아닌 이슈 기반으로 진행됩니다.

  • 버그 리포트 대응: 기존 v0.11.x 버전과 다르게 동작하는 부분이 있다면 최우선 순위(P0) 버그로 지정하고 빠르게 패치할 것입니다.
  • 장기 CI 운영: 향후 CI 환경에서 미니 Expo 환경을 구축해 Metro 타겟 빌드까지 자동으로 검증하는 레이어를 추가할 예정입니다. (v0.12.3 예정)
  • 기존의 구형 [email protected] 패키지는 npm에 그대로 유지되므로, 명시적으로 패키지명을 바꾸기 전까지는 기존 앱들이 영향받지 않습니다.

도와주시는 방법

  • 실제 앱에 npm install @blazeapps/dsteem을 적용하고 마이그레이션해 보세요.
  • Expo / React Native 환경에서 테스트해 보고 버그가 있다면 제보해 주세요.
  • GitHub 리포지토리에 별(Star)을 눌러 다른 사람들도 쉽게 찾을 수 있도록 도와주세요.

감사의 말:
Johan Nordberg가 만든 오리지널 dsteem (2017–2019)에 감사를 표합니다. 이번 작업은 그의 설계를 대체하는 것이 아니라 내부 기반을 현대화한 것입니다. 그의 훌륭한 아키텍처 결정은 고스란히 보존되었습니다. 또한 이 작업은 Claude AI의 지원을 받아 개발되었습니다. 스팀 생태계 발전을 위해 제 증인(Witness) 계정인 blaze.apps에 투표해 주시면 감사하겠습니다.

Sort:  

This post has been upvoted by @italygame witness curation trail


If you like our work and want to support us, please consider to approve our witness




CLICK HERE 👇

Come and visit Italy Community



Coin Marketplace

STEEM 0.04
TRX 0.33
JST 0.080
BTC 62814.07
ETH 1666.58
USDT 1.00
SBD 0.42