@sbuilder/cli
v0.4.0
Published
Scaffold, run and deploy an app for the Store Builder platform.
Maintainers
Readme
@sbuilder/cli
sb — tạo khung, chạy và triển khai một app cho nền tảng Store Builder.
🇬🇧 English version: README.md
sb init [tên] [--port 3000] tạo khung một app chạy được, đăng ký được, và mở
ngay trong trang quản trị của merchant
sb login đăng nhập qua trình duyệt; lưu một credential tự
gia hạn
sb logout đăng xuất máy này và xoá credential đó
sb dev tải code của một island lên bản DRAFT mỗi lần bạn
lưu file. Đọc sb.json; cần sb login (hoặc SB_TOKEN).
sb deploy [--submit] đẩy toàn bộ payload của version theo đúng thứ tự
phụ thuộc. --submit thì gửi luôn đi duyệt.
sb code pull [--site <id>] [--dir <path>] [--force]
kéo các file Code Dock của một site về ./code
sb code push [--site <id>] [--dir <path>] [--force] [--dry-run] [--delete]
gửi các chỗ sửa ở máy ngược lại; từ chối file đã
đổi trong Code Dock kể từ lần pull, trừ khi --forceCần Node 20 trở lên. Viết bằng TypeScript, publish ở dạng đã biên dịch — bản cài về không có dependency nào và không phải build gì cả.
Mục lục
- Nó là gì, và không phải là gì
- Cài đặt
- Đường đi năm phút
sb initsb.jsonsb login/sb logoutsb devsb deploysb code- Biến môi trường
- CI
- Các từ chối, và ý nghĩa của chúng
- Những gì nó cố tình KHÔNG làm
- Xử lý sự cố
- Giấy phép
Nó là gì, và không phải là gì
sb là một lối đi nhanh hơn qua cùng một vùng đất, không phải một vùng đất
khác. Mọi thứ nó làm đều là một HTTP request mà bạn hoàn toàn có thể tự gửi
bằng curl. Không có gì trên nền tảng này chỉ tiếp cận được qua CLI, và CLI
không giấu bạn request nào cả.
Cái nó bỏ bớt cho bạn là phần cơ học: viết bộ khung app đã biết nói OAuth, đi tìm endpoint upload island sau mỗi lần lưu file, và đẩy payload của một version qua năm cánh cửa riêng biệt theo đúng một thứ tự mà nền tảng chấp nhận.
Tài liệu tham chiếu đầy đủ được chính bản triển khai Store Builder của bạn phục
vụ tại /cli-docs, cùng với /app-docs (xây dựng app) và
/block-docs (blocks và islands). Trang đó là tài liệu chạy được — các
lệnh trên trang được trích ra từ chính bytes của nó và chạy thật với binary trong
CI, nên nó không thể mô tả một flag mà CLI từ chối. File README này bị ràng buộc
bởi cùng một tiêu chuẩn, qua tests/readme.test.ts.
Cài đặt
Không phải cài gì:
npx @sbuilder/cli --helpHoặc đặt hẳn vào PATH:
npm install -g @sbuilder/cli
sb --helpNode 20 trở lên. Package ship ở dạng đã biên dịch, nên một bản cài đặt không có dependency nào và không phải build gì.
Bộ khung mà sb init sinh ra cũng cố tình như vậy: không dependency, không
build, ESM thuần — vì đó mới là code bạn thật sự chạy.
Bạn đang phát triển chính CLI này chứ không phải dùng nó? CONTRIBUTING.md.
Đường đi năm phút
Toàn bộ vòng lặp, từ đầu đến cuối. Bước 2 và 3 là phần của bạn — xem /app-docs
— còn lại mỗi bước là một câu lệnh.
# 1. Một app chạy được trên máy bạn
sb init my-app --port 4000
cd my-app
cp .env.example .env # điền SB_CLIENT_ID và SB_CLIENT_SECRET
npm start- Tạo app trong tổ chức của bạn, ghi lại
clientId/clientSecretmà nền tảng trả về. Secret chỉ hiện một lần duy nhất. - Tạo một version DRAFT trỏ vào URL local — embed URL
http://localhost:4000/embed, redirect URIhttp://localhost:4000/oauth/callback. Không cần tunnel: một version draft được phép trỏ vàohttp://localhostvà một install sandbox được phép nhúng nó, nên toàn bộ vòng lặp phát triển chạy ngay trên máy bạn. Tunnel chỉ cần khi bạn muốn kiểm tra các URL public trước lúc gửi duyệt.
# 4. Đăng nhập một lần (in ra một mã để bạn gõ trong trình duyệt)
sb login
# 5. Viết sb.json bằng các id vừa có (xem bên dưới), rồi:
sb dev # sửa island, lưu, refresh
# 6. Đẩy toàn bộ payload, và gửi đi duyệt
sb deploy --submitsb init — tạo khung một app chạy được
sb init my-app
sb init my-app --port 4000Ghi một app chạy được vào ./my-app và in ra việc cần làm tiếp theo. Nó không
gọi mạng một lần nào — đây là công cụ tạo khung, không phải bước đăng ký. Việc
tạo app và tạo version vẫn là của bạn.
Nó ghi ra những gì
Năm file, và không gì khác:
| File | Là gì |
| --- | --- |
| server.js | Toàn bộ app: phần đổi token ở /oauth/callback và trang /embed được nhúng, gói trong một file, không dependency |
| package.json | npm start chạy server.js. Không dependencies, không devDependencies — lần npm install đầu tiên không nên là thứ đầu tiên hỏng |
| .env.example | SB_CLIENT_ID, SB_CLIENT_SECRET, SB_API, SB_REDIRECT_URI và PORT |
| README.md | Đúng những bước tiếp theo mà lệnh đã in, phòng khi terminal đã cuộn mất |
| .gitignore | node_modules và .env |
Cố tình không có blocks, không có islands, không có app data. Mỗi thứ đó là một tính năng thật với hướng dẫn riêng, và không thứ nào cần thiết để lần đầu nhìn thấy app hiện ra trong trang quản trị của một merchant.
Về cái tên
Tham số được chuẩn hoá thành thứ npm chấp nhận làm tên package: viết thường, mọi
chuỗi ký tự ngoài a-z 0-9 . _ - bị gộp thành một dấu -, và cắt bỏ -_. ở đầu
và cuối.
| Bạn gõ | Bạn nhận được |
| --- | --- |
| sb init my-app | ./my-app |
| sb init "My App!" | ./my-app |
| sb init | ./my-app |
Nó từ chối những gì
Không bao giờ ghi đè, và không bao giờ ghi nửa vời. Toàn bộ tập file được đối chiếu với thư mục đích trước khi ghi bất cứ thứ gì; chỉ cần một file trùng là từ chối tất cả và nêu tên thứ bị trùng:
/path/to/my-app already contains package.json, server.js — refusing to overwrite.
Pick an empty directory, or move those files aside.Một bộ khung dở dang còn tệ hơn là không có, vì nó để lại một thư mục trông như
đã khởi tạo mà thực ra chưa. Còn một thư mục đã tồn tại sẵn thì hoàn toàn ổn
— chạy sb init trong một bản git clone mới tinh là chuyện bình thường, từ
chối chỉ vì có .git là từ chối đúng trường hợp phổ biến nhất.
Flags
| Flag | Mặc định | Tác dụng |
| --- | --- | --- |
| --port <n> | 3000 | Cổng được ghi vào .env.example, vào README sinh ra, và vào mọi URL mà lệnh in ra. Giá trị không phải số dương sẽ bị từ chối với --port must be a number |
sb.json — file mà dev và deploy đọc
Cả sb dev lẫn sb deploy đều đọc sb.json từ thư mục hiện tại.
sb init không ghi file này, và không thể ghi được: ba trong năm trường bắt
buộc là các id do nền tảng sinh ra khi bạn tạo app và bản draft của nó — những
việc chưa xảy ra ở thời điểm init. Hãy tự viết một lần khi đã có chúng:
{
"orgId": "org_yourorg",
"appId": "app_1a2b3c4d",
"versionId": "apv_5e6f7a8b",
"island": "countdown",
"entry": "islands/countdown.js"
}Bắt buộc — thiếu một trong năm là cả hai lệnh đều từ chối
| Khoá | Là gì |
| --- | --- |
| orgId | Tổ chức sở hữu app |
| appId | App |
| versionId | Bản draft đang được sửa |
| island | Island mà sb dev tải code lên |
| entry | File mà sb dev theo dõi, tính tương đối với sb.json |
Thiếu khoá nào sẽ bị gọi tên khoá đó — sb.json is missing "versionId". — và
thiếu hẳn file thì bị từ chối kèm danh sách những gì cần có. sb deploy cũng đòi
đủ năm khoá dù công việc của nó được mô tả bởi các khoá tuỳ chọn bên dưới, nên
hãy điền đủ ngay cả khi bạn chỉ deploy blocks.
Tuỳ chọn — mỗi khoá tìm thấy trở thành một bước deploy
| Khoá | Kiểu | sb deploy làm gì với nó |
| --- | --- | --- |
| version | object | PUT làm các trường của version — scopes, embedUrl, redirectUri và phần còn lại |
| blocks | đường dẫn | Manifest của block, PUT làm body của .../blocks |
| islands | mảng {name, entry} | Khai báo mọi name, rồi tải lên mọi entry |
Một sb.json chỉ có năm khoá bắt buộc vẫn hợp lệ: sb dev chạy được, còn
sb deploy sẽ không tìm thấy bước nào để chạy.
sb code đọc thêm đúng một khoá tuỳ chọn từ cùng file này, siteId, và không đọc
gì khác: nó không cần năm khoá bắt buộc.
Một file đầy đủ hơn:
{
"orgId": "org_yourorg",
"appId": "app_1a2b3c4d",
"versionId": "apv_5e6f7a8b",
"island": "countdown",
"entry": "islands/countdown.js",
"version": {
"scopes": ["products.read", "orders.read"],
"embedUrl": "https://app.example.com/embed",
"redirectUri": "https://app.example.com/oauth/callback"
},
"blocks": "blocks.json",
"islands": [
{ "name": "countdown", "entry": "islands/countdown.js" },
{ "name": "stock-bar", "entry": "islands/stock-bar.js" }
]
}sb login / sb logout — đăng nhập qua trình duyệt
sb login
sb logoutsb login đăng nhập CLI thông qua editor trên trình duyệt của bạn, nên dùng
được cả với tài khoản chỉ đăng nhập bằng Google hoặc GitHub, không có mật khẩu.
Nó không bao giờ hỏi mật khẩu:
- Nó in ra một địa chỉ — trang
/devicecủa editor — và một mã 8 ký tự, ví dụBCDF-GHJK. - Mở trang đó trong trình duyệt bạn đang đăng nhập (chưa thì đăng nhập trước),
gõ mã vào, kiểm tra trang hiện đúng mã đó và client
sb-cli, rồi duyệt. - CLI, vốn đang hỏi lại server định kỳ, nhận credential và lưu lại.
Mã được gõ tay, không bao giờ nằm trong link: một link điền sẵn mã sẽ cho
phép người khác gửi bạn mã của họ để bạn duyệt hộ. Mã hết hạn sau 10 phút và chỉ
duyệt được một lần. Từ chối trong trình duyệt thì CLI dừng với
The sign-in was denied in the browser. Nothing was stored.
Những gì được lưu. Một access token và một refresh token, theo từng địa chỉ
API (nên đăng nhập local và production cùng tồn tại được), trong
${XDG_CONFIG_HOME:-~/.config}/sb/credentials.json, tạo ra với quyền chỉ mình
bạn đọc được (mode 0600). Mỗi lần sb login là một thiết bị đăng nhập riêng
trên tài khoản, nằm cùng danh sách phiên với các thiết bị khác; đăng xuất mọi
nơi cũng kết thúc nó.
Nó tự gia hạn. Khi server từ chối access token, sb dev, sb deploy và
sb code xoay cặp token một lần, lưu lại, rồi gửi lại request. Hai tiến trình sb cùng gia
hạn một lúc sẽ lần lượt đi qua một file khoá đặt cạnh file credential, và tiến
trình thứ hai dùng luôn cặp mà tiến trình đầu đã lưu — một refresh token bị dùng
hai lần sẽ kết thúc phiên. Nếu chính việc gia hạn bị từ chối, mục đó bị xoá và
CLI bảo bạn chạy lại sb login.
sb logout thu hồi phiên của thiết bị này trên server và xoá mục của nó khỏi
file. Các thiết bị khác của bạn vẫn đăng nhập.
SB_TOKEN, khi được đặt, được ưu tiên hơn credential đã lưu — xem
Biến môi trường.
sb dev — lưu, tải lên, refresh
SB_TOKEN=<token của bạn> sb devTheo dõi file entry khai trong sb.json và tải nó lên island của version mỗi
lần bạn lưu. Nó tải lên ngay một lần lúc khởi động chứ không chờ lần lưu đầu
tiên, rồi chạy cho tới khi bạn ngắt.
watching islands/countdown.js — save it and this uploads to version apv_5e6f7a8b.
This is not hot reload: after each upload, refresh the page.
uploaded countdown — refresh the page to see itĐây không phải hot reload, và nó sẽ không bao giờ tự nhận như vậy. Code của một island trên trang đã render luôn đến từ object store của nền tảng, nên không thể trỏ một trang vào dev server ở máy bạn, và cũng không có chuyện vá code trực tiếp. Cái mà lệnh này bỏ đi là công đoạn đi tìm endpoint: bạn lưu, nó tải lên, bạn refresh trang.
Nó tải lên một bản draft. Một version đã rời trạng thái draft sẽ từ chối ghi — việc duyệt ghim chặt payload, và một island bị tráo sau khi duyệt là code chạy trên trang của merchant mà không ai nhìn qua.
sb dev không nhận flag nào. Nó tải lên một island — cái được đặt tên trong
sb.json. Muốn đẩy nhiều island một lúc thì dùng sb deploy với mảng islands.
sb deploy — toàn bộ payload, theo thứ tự phụ thuộc
SB_TOKEN=<token của bạn> sb deploy
SB_TOKEN=<token của bạn> sb deploy --submitChạy mọi bước mà sb.json mô tả, theo đúng thứ tự này:
version fields PUT /api/orgs/{orgId}/apps/{appId}/versions/{versionId}
blocks PUT .../blocks
island declarations PUT .../islands
island "<name>" POST .../islands/module?name=<name> (mỗi island một lần)Thứ tự chính là thiết kế. Phần khai báo đi trước các module lấp vào chúng, vì
code tải lên cho một island mà version chưa khai báo sẽ bị từ chối
(island_not_found), trong khi một khai báo chưa có code là trạng thái nền tảng
hoàn toàn chấp nhận. Nhờ vậy một lần dừng giữa chừng để lại đúng hình dạng thứ
bạn định làm, chứ không phải mấy đống bytes mồ côi.
Nó không nguyên tử, và nó không cần phải thế
Payload của một version được ghi qua năm cánh cửa, không lời gọi đơn lẻ nào chở hết được; một công cụ xâu chuỗi chúng lại rồi tuyên bố kết quả là nguyên tử thì đang hứa hẹn đúng ở chỗ mà bạn sẽ tin vào lời hứa đó. Mà nó không cần lời hứa ấy: một bản draft được thiết kế để có thể không nhất quán giữa các lần ghi. Cả hai bước kiểm tra tính nhất quán đều chạy lúc submit chứ không phải ở từng lệnh ghi, nên một lần deploy dở dang cho ra một version chưa xong chứ không phải một version hỏng.
Đổi lại, thứ lệnh này nợ bạn là nói rõ nó dừng ở đâu:
Stopped at: island "countdown"
This version is in review or already approved, so its code is frozen.
Create a new draft version and point sb dev at that one.
(server: version has left draft)
Already applied: version fields, blocks, island declarations
This left the version UNFINISHED, not broken — a draft is allowed to be
partway through, and it simply cannot be submitted until the rest lands.
Fix the cause and run sb deploy again; every step is safe to repeat.Mọi lệnh ghi đều idempotent, nên "chạy tiếp" đơn giản là chạy lại.
Flags
| Flag | Tác dụng |
| --- | --- |
| --submit | Sau khi deploy thành công thì POST .../submit — cổng duyệt |
--submit trước tiên soi khối version trong sb.json của bạn xem còn URL nào
trỏ về máy bạn không, và từ chối trước khi gọi server:
This version still points at your own machine: embedUrl (http://localhost:3000/embed).
Review needs public https URLs — the loopback allowance covers development only.
Update the version to its real addresses, deploy again, then submit.Kiểm tra đó là phép lịch sự, không bao giờ là thẩm quyền. Server mới chạy bản kiểm tra thật, và nếu hai bên có mâu thuẫn thì server thắng; cái này chỉ tồn tại để hỏng sớm hơn, với nhiều chỗ giải thích hơn một status code.
sb code — file Code Dock của bạn dưới dạng một thư mục
sb code pull --site <site-id>
# sửa code/site/css/main.css bằng trình soạn thảo của bạn, rồi
sb code pushĐồng bộ các file Code Dock của một site — CSS, JavaScript và HTML dùng chung toàn site hoặc riêng từng trang — về một thư mục, để bạn sửa bằng trình soạn thảo của mình, lưu trong git và đẩy ngược lại.
Bố cục, và manifest
code/
.sb-code.json manifest — hãy commit nó
site/css/main.css file toàn site tên "css/main.css"
pages/about/track.js file "track.js" của trang có slug là "about"Dấu / trong tên file trở thành thư mục. Thư mục của một trang là slug của nó
tại lần pull đầu tiên (trang chủ là home; slug rỗng hoặc trùng thì thành
page-<id>) rồi được ghi vào manifest, nên đổi slug về sau không làm file của
bạn đổi chỗ. Đổi tên một file trong Code Dock cũng không làm nó đổi chỗ: nó giữ
nguyên đường dẫn ở máy, vì được theo dõi theo id, và nội dung của nó vẫn được đồng
bộ. Một file Code Dock không có tên sẽ được pull về thành
unnamed-<id>.<ext> và được theo dõi theo id.
Symlink không bao giờ dẫn sb code ra ngoài thư mục gốc: một file là symlink, hoặc nằm
trong thư mục dẫn ra ngoài thư mục gốc qua một symlink, được nêu tên và bỏ qua — pull
không ghi gì qua nó, push không gửi gì từ nó — các file khác vẫn đồng bộ và lần chạy
thoát 1. Hai symlink bị từ chối trước khi gửi bất kỳ thứ gì: một .sb-code.json là
symlink, và, khi không có --dir, một thư mục code là symlink — truyền --dir <path>
để cố ý đồng bộ qua nó.
.sb-code.json ghi, cho mỗi file, id và metadata phía server, updatedAt của nó
và sha256 của nội dung như lần pull hoặc push gần nhất. Đó là mốc gốc mà cả
hai chiều so sánh với, nhờ vậy sb code phân biệt được chỗ bạn sửa với chỗ sửa
trong Code Dock. Hãy commit nó: push từ CI khi đó xét xung đột theo lần pull
gần nhất mà bạn đã commit.
Pull
sb code pull ghi mọi file mà server có. Nó không bao giờ ghi đè chỗ bạn đã
sửa:
- File của bạn đã đổi còn server thì không: để nguyên và in là
pending—sb code pushsẽ gửi nó. Thoát0. - Cả hai cùng đổi: file được giữ lại, được nêu tên, và lần chạy thoát
1. sb code pull --forceghi đè mọi chỗ bạn đã sửa bằng bản của server, trong cả hai trường hợp.- File bị xoá trên server chỉ bị xoá ở máy bạn nếu bạn chưa từng sửa nó.
Cuối cùng là một dòng tổng kết: đã ghi, pending, giữ lại, đã xoá.
Push
sb code push lập một kế hoạch dựa trên manifest:
| Kế hoạch | Khi nào | Điều kiện |
| --- | --- | --- |
| update | file đã theo dõi mà nội dung khác mốc gốc | không |
| create | file chưa theo dõi nằm trong site/ hoặc pages/<page>/ | đuôi .css, .js hoặc .html; đuôi khác bị từ chối và nêu tên |
| delete | file đã theo dõi nhưng không còn ở máy | --delete; không có nó thì file được in là missing và vẫn giữ trên server |
Create chạy trước, rồi update, rồi delete. Mỗi update và delete mang theo
updatedAt từ lần pull gần nhất của bạn, và server so sánh nó ngay bên trong
lệnh ghi: một file đã bị đổi trong Code Dock kể từ đó sẽ trả 409
code_file_changed, riêng file đó bị từ chối ("changed in the Code Dock since your
pull; run sb code pull, or push --force"), phần còn lại vẫn chạy tiếp, và mã
thoát là 1.
Manifest được ghi sau mỗi thao tác, nên một lần chạy dừng giữa chừng — lỗi server hoặc mất kết nối sẽ làm nó dừng — được tiếp tục bằng cách chạy lại; không có gì bị tạo hai lần.
Chỉ nội dung được đồng bộ. Vị trí chèn (placement), bật/tắt, thứ tự và ngôn
ngữ của một file đã có vẫn nằm trong Code Dock, nơi hiệu ứng của chúng nhìn thấy
được. File mới nhận giá trị mặc định của server — vị trí chèn head cho .css
và body_end cho .js và .html, giống như trong Code Dock — và dòng in ra cho
nó nói rõ là giá trị nào, nên một file .js rơi vào body_end không bao giờ là bất ngờ.
File bị di chuyển hay đổi tên ở máy là một create cộng với một delete (cần
--delete), và --dry-run hiển thị đúng như vậy.
Flags
| Flag | Áp dụng cho | Tác dụng |
| --- | --- | --- |
| --site <id> | pull, push | Site cần đồng bộ. Cần khi dùng sb login hoặc user token, trừ khi sb.json hay manifest đã nêu; key wbk_ ngầm chỉ định site của nó |
| --dir <path> | pull, push | Thư mục gốc, mặc định code |
| --force | pull, push | Pull ghi đè mọi chỗ bạn đã sửa bằng bản của server. Push không gửi expectedUpdatedAt, nên nội dung của bạn thắng; nó vẫn gửi metadata hiện tại của server, nên không bao giờ hoàn tác những gì Code Dock đã đổi |
| --dry-run | push | In kế hoạch và không gửi gì |
| --delete | push | Xoá luôn các file trên server mà bản ở máy đã mất |
Xoá thứ mà bạn còn đang dựa vào là một quyết định, không bao giờ là mặc định —
vì thế --delete tồn tại, thay vì để push tự suy ra.
Nó nói chuyện với API nào
SB_TOKENbắt đầu bằngwbk_— một API key của merchant — dùng/api/v1/code-files. Key ngầm chỉ định site của nó, nên không cần--site.- Mọi trường hợp khác — credential do
sb loginlưu, hoặc một user token dán tay — dùng/api/sites/{siteId}/code-files. Site lấy từ--site, nếu không thì khoásiteIdtuỳ chọn trongsb.json, nếu không nữa thì từ manifest. Hai nguồn nêu hai site khác nhau thì bị từ chối trước khi gửi bất kỳ request nào. SB_TOKENbắt đầu bằngsbdk_bị từ chối trước khi gửi bất kỳ request nào. Deploy key thuộc về một tổ chức developer và chỉ chạm tới các route version của app nó; code của site là nội dung của merchant.
Một key wbk_ mà manifest không có file nào trùng với danh sách của server bị
từ chối vì thuộc về site khác, nên một key CI không thể ghi file của site A lên
site B. --force bỏ qua điều đó.
CI cho sb code
Tạo một API key trong Settings → API keys của merchant với codefiles.write
(thêm pages.read nếu CI tạo file trong một thư mục trang mà manifest chưa
biết), rồi lưu nó thành secret SB_TOKEN của CI:
SB_TOKEN="$SB_API_KEY" sb code pushKey không có codefiles.write bị server từ chối và không có gì được ghi.
codefiles.write nghĩa là "được thêm script vào mọi trang đã publish", nên chỉ
cấp cho key khi pipeline thật sự cần. Hãy commit code/, kể cả manifest.
Mã thoát
0 khi mọi thao tác đã lên kế hoạch đều thành công. 1 khi có gì đó bị từ chối
hoặc bỏ qua trái ý server: một 409, lỗi validate, đuôi file lạ, một lần pull
đã giữ lại file mà cả bạn và server cùng sửa, key sbdk_, site không khớp, hoặc
token bị từ chối. Một chỗ sửa ở máy đang chờ mà pull nhìn thấy, hoặc một file đã
theo dõi bị mất ở máy khi không có --delete, được in ra và không phải lỗi.
CI
User access token sẽ hết hạn, nên không hợp cho pipeline. Hãy dùng deploy key:
- Trong Developer portal, mở tổ chức của bạn và vào Deploy keys (chủ sở hữu
hoặc admin mới làm được), rồi tạo một key. Secret bắt đầu bằng
sbdk_và chỉ hiện một lần. - Lưu nó thành secret
SB_TOKENcủa CI.sb devvàsb deploynhận nó y như một token dán tay. (sb codethì không: xem công thức CI riêng của nó.)
SB_TOKEN="$SB_DEPLOY_KEY" sb deployDeploy key không hết hạn và thuộc về tổ chức, không thuộc người đã tạo ra nó. Nó chỉ tải lên được cho các app của chính tổ chức đó: cập nhật các trường, block và island của một version, tải lên island module và gửi version đi duyệt. Nó không thể tạo hay xoá app, tạo version, rút lại version, xoay vòng secret, quản lý thành viên hay quản lý deploy key.
Nếu key bị lộ, hãy thu hồi nó ngay trên cùng màn hình; yêu cầu kế tiếp dùng key đó sẽ bị từ chối.
Biến môi trường
Hai biến do chính CLI đọc:
| Biến | Lệnh cần nó | Mặc định |
| --- | --- | --- |
| SB_TOKEN | sb dev, sb deploy, sb code — tuỳ chọn | không có — dùng credential của sb login; thiếu cả hai thì mỗi lệnh đều dừng và nhắc sb login |
| SB_API | mọi lệnh trừ sb init | http://localhost:8080 |
SB_TOKEN, khi được đặt, ghi đè credential đã lưu của sb login. Với
sb dev và sb deploy, nó là token của tổ chức sở hữu app — đúng cái user
access token bạn sẽ đặt vào header Authorization: Bearer khi gọi các route theo
tổ chức. Nó không phải app token dạng wba_; loại đó thuộc về một install,
và một install không thể sửa chính cái app mà nó là install của. Với sb code,
nó là user token có quyền truy cập site, hoặc một API key wbk_ của merchant
(xem sb code).
Token dán tay không tự gia hạn được, và CLI không bao giờ thử refresh nó. Khi
server từ chối một token dán tay, sb dev và sb deploy báo
SB_TOKEN was refused: it has expired or been revoked và chỉ bạn sang
sb login. sb code thì báo
Not signed in, or the token was refused (expired or revoked). Run `sb login`, or set SB_TOKEN to an API key (wbk_…) with codefiles.read / codefiles.write from Settings -> API keys.
và không bao giờ gợi ý deploy key, vì sb code từ chối deploy key.
Ba biến còn lại do app mà sb init sinh ra tự đọc, từ .env của chính nó:
| Biến | Ai đọc | Là gì |
| --- | --- | --- |
| SB_CLIENT_ID | server.js được sinh ra | Hiện lên khi bạn tạo app |
| SB_CLIENT_SECRET | server.js được sinh ra | Chỉ hiện một lần lúc tạo. Mất thì xoay vòng lại, đừng đi tìm |
| SB_REDIRECT_URI | server.js được sinh ra | Phải khớp từng ký tự với redirect URI trên version của bạn |
App sinh ra cũng đọc SB_API và PORT.
Các từ chối, và ý nghĩa của chúng
Mọi lệnh thoát 0 khi thành công và 1 khi từ chối có lý do giải thích được.
Ngoài hai giá trị đó là bug của chính công cụ, và khi đó nó in stack trace, vì
một công cụ tạo khung mà nuốt lỗi của chính mình là công cụ không ai báo lỗi
được.
sb dev và sb deploy dịch lại các mã lỗi từ server trong bảng dưới đây thay vì
bê nguyên văn. sb code có những câu từ chối riêng: câu về token bị từ chối nằm
ở phía trên, và mục
sb code mô tả lệnh
này.
| Mã từ server | sb nói gì thay vào đó |
| --- | --- |
| not_draft | Version này đang duyệt hoặc đã được duyệt nên code bị đóng băng — tạo bản draft mới và trỏ vào đó |
| island_not_found | Version này không khai báo island tên đó; khai báo trước đã |
| island_module_not_text | File đó không phải text. Một island module là JavaScript |
| island_module_too_large | File đó quá lớn để tải lên làm island module |
| unauthorized | Chưa đăng nhập. Chạy sb login, hoặc đặt SB_TOKEN là token của tổ chức sở hữu app này |
| mọi 401/403 khác | Token này không sửa được app đó — kiểm tra bạn đang đăng nhập bằng gì (sb login / SB_TOKEN), và kiểm tra app có thuộc tổ chức bạn khai không |
Mỗi dòng đều giữ nguyên câu chữ của server trong (server: …) rồi thêm việc cần
làm tiếp. Một mã lỗi công cụ chưa được dạy sẽ được in bằng chính lời của server,
chứ không phải một cái nhún vai.
Những gì nó cố tình KHÔNG làm
Nói ra để bạn tính đường trước, thay vì tự phát hiện giữa chừng.
- Nó không tạo app, không tạo version, không tạo install.
sb initkhông gọi mạng lần nào. Những bước đó là của bạn, làm tay hoặc bằng script của bạn; CLI chỉ bắt đầu có ích khi đã có các id ấy. - Nó không ghi
sb.json, cùng lý do trên. - Nó không bao giờ hỏi mật khẩu.
sb loginđăng nhập qua trình duyệt, và thứ duy nhất nó lưu là file credential mô tả ở trên. sb devkhông phải hot reload, và không phiên bản tương lai nào của nó có thể là hot reload chừng nào code island còn được phục vụ từ object store của nền tảng.sb deploykhông nguyên tử, một cách có chủ đích.
Xử lý sự cố
| Hiện tượng | Nguyên nhân | Cách xử lý |
| --- | --- | --- |
| Not signed in. Run sb login … | dev/deploy không có credential nào | sb login, hoặc đặt SB_TOKEN |
| Your sb login has expired or was revoked. | Phiên đã lưu đã kết thúc (đăng xuất mọi nơi, hoặc hết hạn) | Chạy lại sb login |
| SB_TOKEN was refused: … | Token dán tay đã hết hạn hoặc bị thu hồi | sb login, hoặc lấy token mới |
| Not signed in, or the token was refused … | sb code không có credential nào, SB_TOKEN dán tay bị từ chối, hoặc server vẫn trả 401 sau khi đã gia hạn sb login của bạn | sb login, hoặc đặt SB_TOKEN là một API key wbk_ có codefiles.read / codefiles.write từ Settings → API keys |
| No sb.json here. | Chạy sai thư mục | cd về đúng thư mục chứa sb.json |
| sb.json is missing "versionId". | Thiếu hoặc để rỗng một khoá bắt buộc | Điền đủ cả năm khoá bắt buộc |
| unknown command: … | Gõ nhầm, hoặc dist/ đã cũ | npm run build --workspace cli |
| --port must be a number | --port nhận giá trị không phải số dương | Truyền một số nguyên dương |
| Bị từ chối với not_draft | Version đã rời draft; việc duyệt ghim payload lại | Tạo version draft mới và trỏ sb.json vào đó |
| Bị từ chối với island_not_found | Version chưa khai báo island đó | Khai báo trước — sb deploy với mảng islands làm đúng thứ tự này |
| --submit bị từ chối vì URL loopback | version.embedUrl / version.redirectUri vẫn trỏ localhost | Đặt URL https public, sb deploy lại, rồi submit |
| Island đã đổi mà trang không đổi | sb dev không phải hot reload | Refresh trang |
| sb báo một flag trang này không liệt kê | Bạn đang chạy dist/ cũ | Build lại |
Giấy phép
MIT © Store Builder
