# @jsm-mit/tigi-sharded-package 中文文档

规范地址：https://npmcn.com/package/%40jsm-mit/tigi-sharded-package/

版本：0\.12\.0
npm 元数据更新时间：2026-11-01T13:15:15.800Z
中文译文更新时间：2026-11-01T14:37:19.642Z
软件包许可：ISC

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40jsm-mit/tigi-sharded-package
原文对照：https://npmcn.com/package/%40jsm-mit/tigi-sharded-package/?lang=original
项目主页：https://github.com/JSM-Tigi/tigi-sharded/tree/master/package#readme
源码仓库：https://github.com/JSM-Tigi/tigi-sharded

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：486 kB，59 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- 首次发布：2026-10-23T05:49:19.445Z
- 最新版本发布：2026-11-01T13:15:15.665Z
- 已发布版本数：14（近 12 个月 14 个）

## 中文简介

Tigi网络组的一个包：获取协调器的id，并隐藏协调器、核心和工作器——对于消费者来说，组是一个罐子；加上车手的几个驾驶罐端点（U-14）。

## 安装

```sh
npm install @jsm-mit/tigi-sharded-package
```

也可以使用：`pnpm add @jsm-mit/tigi-sharded-package`、`yarn add @jsm-mit/tigi-sharded-package`、`bun add @jsm-mit/tigi-sharded-package`

## README

# @jsm-mit / tigi-sharded-package

Tigi网络组的一个包：它接受协调器的id并隐藏 协调员、核心和工人——对于一个消费者来说，这个群体是一个罐子。它还 携带着车手的几个驱动罐端点（U-14）； `getRide`， `cancelRide`， `getLicence`， `getRideRoute`)，由 `protocol/tigi-driver.did`，所以消费者永远看不到司机 罐的id。

状态：骑手侧（1夜，U-42）；0.2.0（阶段2a， U-43）增加了骑手自己的 评级和在哪里与司机聊天；0.3.0 （U-45）添加 `DriverCanistersActor` - - - 示范租约及一次性索赔代码；0.4.0（路线，2026-10-24）增加了驾驶员的 地图上的路线-提供的线路，乘车线路-以及确切的针 报价(`pinExact`);0.5.0（第7阶段，骑行历史，2026-10-24）添加了过去的位置 ride （Skąd, Dokąd）和历史上过去一次骑行的评分。版本0.1.0是 首先发表。

## 骑手

```ts
import { ProfilesActor, RidesActor, TestManagerActor, REQUEST_POLL_MS } from "@jsm-mit/tigi-sharded-package";

const profiles = new ProfilesActor(coordinatorId, identity, { host });
await profiles.setMyProfileAsyncUnsafe("Ala");             // C-2: once, before the first request

const rides = new RidesActor(coordinatorId, identity, { host });
const request = await rides.requestRideAsyncUnsafe({ pickup, destination });
localStorage.setItem("tigi-request", request.token);       // rides.resumeRequest(token) after a reload

const snapshot = await request.getAsyncUnsafe();            // every REQUEST_POLL_MS (1 s)
// snapshot.phase: searching | waitingForDriver ("Zamawiam…", a second or two) | accepted | closed
// snapshot.offers: a FIXED list (U-42) — by first arrival, new ones at the end, nothing
//   re-sorted; an offer that left keeps its entry with `gone` (rejected | driverNotFree |
//   taken | closed): draw a grey row of the same height there
// offer.pin: the driver's exact position (offer.pinExact) — the geohash7 centre from an old driver canister
const line = await request.getOfferRouteAsyncUnsafe(offer.offerId);  // ZO-21, after a tap: { toPickup: Geo[]; ride: Geo[] } | undefined
await request.rejectOfferAsyncUnsafe(offer.offerId);        // ✕ → gone "rejected"; the next nearest driver
await request.refreshOfferAsyncUnsafe(offer.offerId);       // a stale (grey) offer asks again
await request.chooseOfferAsyncUnsafe(offer.offerId);        // ordered (= the ride, accepted at once) | busy | offerExpired
                                                            // | driverNotFree ("Kierowca jest już zajęty") | closed
await request.giveUpAsyncUnsafe();
// After "Kierowca anulował kurs" (ride status cancelledByDriver): "Szukaj ponownie" —
const again = await request.searchAgainAsyncUnsafe();       // a new request, the same pickup and destination

const ride = await request.getRideAsyncUnsafe();            // from the driver canister, every RIDE_POLL_MS (2 s)
await request.getRideRouteAsyncUnsafe();                    // K-13: the ride's line while it is active (once; undefined after the end)
await request.cancelRideAsyncUnsafe();                      // before inProgress, once
// ZT-*: a ride at a chosen time (1 h … 7 days ahead; drivers asked by their base, 3 → 25 km by the workers themselves):
const later = await rides.requestScheduledAsyncUnsafe({ pickup, destination, pickupAtMs }); // keep later.token; rides.resumeScheduled(token)
const s = await later.getAsyncUnsafe();                     // phase collecting | booking | booked | started | rescue | closed; offers cheapest first
await later.chooseAsyncUnsafe(s.offers[0].offerId);         // a booking; read again for booked / lastOrderRefused
// started → rides.resumeRequest(s.rideToken) is the ride; rescue → requestRideAsyncUnsafe with the same A, B from T−10 min (RESCUE_BEFORE_MS)
// P-20: card straight to the driver (Stripe) — when ride.cardAccepted, during inProgress:
const card = await request.startCardPaymentAsyncUnsafe(returnUrl); // open → go to card.url; the same page again while it stands
await request.checkCardPaymentAsyncUnsafe();                // back from Stripe (card=paid|cancelled in the URL); ride.cardPayment shows it too
await request.getLicenceAsyncUnsafe();                      // from accepted to the end of the ride
await request.rateDriverAsyncUnsafe(5);                     // after completed, once

const page = await profiles.getMyRidesAsyncUnsafe();        // the history in the core, 20 a page
// 0.5.0 — a line: pickup?, destination? (KU-4; none before stage 7), ratable (KU-5), myRating?
const past = await profiles.getMyRideAsyncUnsafe(page.rides[0].rideRef);  // one line (a reload); undefined until the core has it
if (past?.ratable) await profiles.ratePastRideAsyncUnsafe(past.rideRef, 5);
//   → "ok" | "alreadyRated" (also after rateDriverAsyncUnsafe) | "notRatable" (not completed,
//     the 24 h are over, not in the core yet) | "notAuthorized" (another rider's ride)
const mine = await profiles.getMyRatingAsyncUnsafe();       // PF-4: { average: 4.87, count, sum } | undefined ("Brak ocen")
await rides.getPastRideAsyncUnsafe(page.rides[0].rideRef);  // its details from the driver canister
```

这个包对网络的作用（zgloszenie-i-oferty.md）：

-   该请求发送给皮卡车（ZO-1）周围3公里范围内的每个工人 使用协调器的前缀映射（保持30秒）；一个工人的 `NOT_MY_AREA` 让它再问一次)；
-   15秒无报价→6公里，在相同的和新的工人（ZO-8），在里面 `getAsyncUnsafe`；
-   在所有工人中一次选择一个（ZO-14）；在接受之后， `closeRequest otherOfferChosen` 在其他工人（ZO-15）；
-   一个停止的罐（升级，IC0508/IC0509）等待大约一分钟。

错误: `CanisterError` (与 `errorKey`； `refusalKeyOf(err)` 给出工人的拒绝： `ALREADY_OPEN`， `NOT_MY_AREA`， `FULL`， `CLOSED`， `ORDERING`， `DRIVER_NOT_FREE`， `NOT_COMPLETED`， `EXPIRED`， `BLOCKED`)， `CallRefusedAtInspectionStage`， `CriticalCanisterError`.

## 正面：U-43

每个司机有一个聊天室 `chat-sharded` （不是每乘一次）：它的接受者是 驱动程序，并且每个Tigi帐户都可以在那里打开聊天（聊天询问Tigi） 协调者账户所在的位置和核心 `isUser`）. 核心使房间得以贯通 协调器;这个包只说WHERE -前台发送和读取消息 `@jsm-mit/chat-sharded-package` 本身（此包不包装聊天）。

```ts
import { ChatPlacesActor, driverRoomId } from "@jsm-mit/tigi-sharded-package";
import { ChatsActor, MessagesActor } from "@jsm-mit/chat-sharded-package";

// The rider (PR-25): from `accepted` to the end of the ride.
const place = await request.getChatPlaceAsyncUnsafe();      // { chatCoordinatorId, projectId, roomId } | undefined
if (place) {
    const chats = new ChatsActor(place.chatCoordinatorId, identity, { host });
    const chat = await chats.openChatAsyncUnsafe({ projectId: place.projectId, roomId: place.roomId, customerName: profile.name });
    // … MessagesActor(place.chatCoordinatorId, identity).postAsyncUnsafe / pollNewMessagesAsyncUnsafe
}

// The driver (FK-20): the room of their own canister; they are its recipient.
const driverPlace = await new ChatPlacesActor(coordinatorId, identity, { host }).getDriverChatPlaceAsyncUnsafe(myDriverCanisterId);
// list the chats of driverPlace.roomId (ChatsActor.getMyChatsAsyncUnsafe({ projectId, roomId }))
// and show only the current rider's chat
```

-   `undefined` =在这个环境中没有聊天（核心中没有聊天配置）或a 模拟司机（MVP中没有聊天）。
-   房间id是确定的： `driverRoomId(canister)` ＝ `drv-<canister id>` ( 核心的 `ChatRoomFunctions.driverRoomId`）。
-   车手需要一个Tigi档案(`setMyProfileAsyncUnsafe`) -没有一个聊天 拒绝打开它(`CanisterError`， `NotAuthorized`）。
-   每个聊天（房间，乘客，收件人）：乘客与司机有一次聊天 他们的游乐设施。由另一个测试人员接管的演示池罐将使该测试人员成为 收件人;与前一个测试人员的聊天记录会留在他们身边。
-   房间可能会在司机的罐子（核心的发箱）之后几秒钟出现； `openChatAsyncUnsafe` 答案 `NotFound` 在那之前，再试一次。

## 前方：驾驶员自备油箱（U-45）

互联网身份赋予一个人不同的身份。示范租约为 拍摄于骑手的场地；司机在罐子的正面签到 （`https://<canister>.icp0.io`)。新租约是一次性的 声明代码（15分钟，单次使用；核心只保留其sha256），将罐子交给 谁在那里认领它(`fabryka.md` F-20)。

```ts
import { DriverCanistersActor, claimLinkOf, claimCodeOfHash } from "@jsm-mit/tigi-sharded-package";

// The rider's site (the lease holder).
const canisters = new DriverCanistersActor(coordinatorId, identity, { host });
const lease = await canisters.leaseDemoAsyncUnsafe();       // { kind: "leased", canister, claim? } | { kind: "busy", untilMs }
if (lease.kind === "leased" && lease.claim) {
    link = claimLinkOf(lease.canister.canisterId, lease.claim.code);   // "Otwórz swój kanister"
}
const fresh = await canisters.newClaimCodeAsyncUnsafe();    // "Nowy link": the old code stops working
await canisters.extendDemoAsyncUnsafe();                    // F-8: 15 min more
await canisters.getMineAsyncUnsafe();                       // the held demo canister (or the own one) | undefined

// The driver's front, signed in as a non-owner, with #claim=<code> in the address.
const code = claimCodeOfHash(window.location.hash);
if (code) {
    await new DriverCanistersActor(coordinatorId, identity, { host }).claimAsyncUnsafe(canisterId, code);
    // clear the fragment, reload: the driver is the owner now
}
```

-   被拒绝的索赔总是 `CanisterError` `NotAuthorized` -错误，过期，使用或不使用 这个罐子的密码是一样的。
-   租赁权归其所有者所有： `getMineAsyncUnsafe`， `extendDemoAsyncUnsafe` 和 `newClaimCodeAsyncUnsafe` 继续从骑手的位置工作； `ownerPrincipal` 的名字 司机索赔后。罐子的聊天室得到司机作为它的 接收方。
-   相同的持有人再次租赁（没有重新安装）没有得到代码： `newClaimCodeAsyncUnsafe`.
-   这些视图携带驱动筒的id：它是驱动自己的地址。

测试管理器（阶段和测试模式）： `TestManagerActor.hasSimulatedDriversAsyncUnsafe`， `spawnDriversAsyncUnsafe` (12驱动程序), `setSpeedUpAsyncUnsafe(request, 10)` 在选择。 模拟器的报价 `simulated: true`.

## 脚本

```
npm run build              # tsc (src → dist) and the type-check of the tests
npm run test-unit          # no replica needed
npm run test-drivers       # (a) 5 real driver canisters, driver-bots, route-stub
npm run test-simulator     # (b) the simulator, 20 requests, 20 rides
npm run test-split         # (c) an area split during traffic
npm run test-claim         # (d) the demo lease and the claim code (U-45)
npm run test-route-line    # (e) the route line of an offer and of a ride
npm run test-ride-history  # (f) the history's places and the rating of a past ride (0.5.0)
npm run test-smoke         # one whole ride with the simulator (run by publish-public)
npm run load-local         # the load test: 200 simulated drivers, 100 riders (docs/load-test-2026-10-24.md)
npm run publish-public     # human-run: publish from master (see below)
npm run sync-declarations  # after a change of a .did (`… protocol` for the protocol and the simulator only)
```

端到端套件仅在LOCAL副本上运行(`scripts/run-tests-local.sh`)：新鲜的 组，局部循环，驱动程序和模拟器wasms `../../tigi-driver-rust` (建 那里，从未改变)。日志和测量值为 `/tmp/claude-1000/tigi/` （`TEST_LOG_DIR`）. 负载测试用它自己的协调器构建它的组 （`tigi-sharded-coordinator-load`)，因此共享的本地组保持不变；它的设置是 环境变量(`scripts/load-local.ts`， `scripts/run-load-local.sh`）。

## 出版

只有人跑：碰撞 `version` 在 `package.json` 那么，手工（不要提交） `npm run publish-public` 在 `master`． 该脚本拒绝，除非此repo和 `../../tigi-driver-rust` 都在戒酒吗 `master` 等于 `origin/master`，版本为 npm新增功能，声明匹配当前构建(core、worker、coordinator、protocol、 模拟器)和冒烟测试通过本地副本(`dfx start` 第一个)。这邮票 `tigiSharded.commit` 和 `tigiDriverRust.commit` 成 `package.json`发布，然后提交 “版本碰撞到”，然后按下。

## 常见问题

### @jsm-mit/tigi-sharded-package 是什么？

Tigi网络组的一个包：获取协调器的id，并隐藏协调器、核心和工作器——对于消费者来说，组是一个罐子；加上车手的几个驾驶罐端点（U-14）。

### 如何安装 @jsm-mit/tigi-sharded-package？

在项目目录运行 npm install @jsm-mit/tigi-sharded-package，或使用 pnpm add / yarn add / bun add。

### @jsm-mit/tigi-sharded-package 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @jsm-mit/tigi-sharded-package 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @jsm-mit/tigi-sharded-package 可以商用吗？

@jsm-mit/tigi-sharded-package 使用 ISC 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @jsm-mit/tigi-sharded-package 还在维护吗？

最新版本 0\.12\.0 发布于 2026/11/01（1 天前）；至今共发布 14 个版本，其中过去 12 个月发布了 14 个；首次发布于 2026/10/23。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

