@xbibzlibrary/telebibz 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.id.md +6 -4
  2. package/README.md +3 -1
  3. package/README.zh-CN.md +7 -5
  4. package/RELEASE_AUTOMATION.md +10 -6
  5. package/dist/src/api/client.d.ts +1 -1
  6. package/dist/src/api/client.d.ts.map +1 -1
  7. package/dist/src/api/client.js +13 -1
  8. package/dist/src/api/client.js.map +1 -1
  9. package/dist/src/api/transport.d.ts.map +1 -1
  10. package/dist/src/api/transport.js +45 -4
  11. package/dist/src/api/transport.js.map +1 -1
  12. package/dist/src/core/bot.d.ts.map +1 -1
  13. package/dist/src/core/bot.js +7 -1
  14. package/dist/src/core/bot.js.map +1 -1
  15. package/dist/src/core/events.d.ts.map +1 -1
  16. package/dist/src/core/events.js +13 -2
  17. package/dist/src/core/events.js.map +1 -1
  18. package/dist/src/observability/logger.d.ts.map +1 -1
  19. package/dist/src/observability/logger.js +17 -1
  20. package/dist/src/observability/logger.js.map +1 -1
  21. package/dist/src/plugins/plugin.d.ts.map +1 -1
  22. package/dist/src/plugins/plugin.js +22 -1
  23. package/dist/src/plugins/plugin.js.map +1 -1
  24. package/dist/src/queue/queue.d.ts.map +1 -1
  25. package/dist/src/queue/queue.js +11 -4
  26. package/dist/src/queue/queue.js.map +1 -1
  27. package/dist/src/state/conversation.d.ts +1 -0
  28. package/dist/src/state/conversation.d.ts.map +1 -1
  29. package/dist/src/state/conversation.js +12 -3
  30. package/dist/src/state/conversation.js.map +1 -1
  31. package/dist/src/storage/storage.js +1 -1
  32. package/dist/src/storage/storage.js.map +1 -1
  33. package/dist/src/telegram-features.d.ts.map +1 -1
  34. package/dist/src/telegram-features.js +2 -0
  35. package/dist/src/telegram-features.js.map +1 -1
  36. package/dist/src/webhook/handler.d.ts.map +1 -1
  37. package/dist/src/webhook/handler.js +10 -1
  38. package/dist/src/webhook/handler.js.map +1 -1
  39. package/dist-cjs/src/api/client.js +13 -1
  40. package/dist-cjs/src/api/transport.js +45 -4
  41. package/dist-cjs/src/core/bot.js +7 -1
  42. package/dist-cjs/src/core/events.js +13 -2
  43. package/dist-cjs/src/observability/logger.js +17 -1
  44. package/dist-cjs/src/plugins/plugin.js +22 -1
  45. package/dist-cjs/src/queue/queue.js +11 -4
  46. package/dist-cjs/src/state/conversation.js +12 -3
  47. package/dist-cjs/src/storage/storage.js +1 -1
  48. package/dist-cjs/src/telegram-features.js +2 -0
  49. package/dist-cjs/src/webhook/handler.js +10 -1
  50. package/docs/API.id.md +3 -3
  51. package/docs/API.md +5 -5
  52. package/docs/API.zh-CN.md +3 -3
  53. package/docs/GITHUB_PACKAGES.id.md +82 -0
  54. package/docs/GITHUB_PACKAGES.md +82 -0
  55. package/docs/GITHUB_PACKAGES.zh-CN.md +82 -0
  56. package/package.json +1 -1
@@ -42,10 +42,17 @@ class TaskQueue {
42
42
  return false; job.status = "cancelled"; this.controllers.get(id)?.abort(); return true; }
43
43
  async onIdle() { while (this.pending.some((job) => job.status === "queued") || this.active)
44
44
  await sleep(10); }
45
- async close() { this.closed = true; this.draining = false; for (const id of this.controllers.keys())
46
- this.cancel(id); for (const job of this.pending)
47
- if (job.status === "queued")
48
- job.status = "cancelled"; this.pending.length = 0; }
45
+ async close() {
46
+ this.closed = true;
47
+ this.draining = false;
48
+ for (const id of this.controllers.keys())
49
+ this.cancel(id);
50
+ for (const job of this.pending)
51
+ if (job.status === "queued")
52
+ job.status = "cancelled";
53
+ this.pending.length = 0;
54
+ await this.onIdle();
55
+ }
49
56
  async drain() {
50
57
  if (this.draining || this.closed)
51
58
  return;
@@ -31,7 +31,13 @@ class ConversationManager {
31
31
  start(key, name, values = {}) {
32
32
  const state = { name, step: 0, values, status: "active", updatedAt: Date.now() };
33
33
  this.active.set(key, state);
34
- void this.storage.set(key, state);
34
+ void this.storage.set(key, state).catch(() => undefined);
35
+ return state;
36
+ }
37
+ async startAsync(key, name, values = {}) {
38
+ const state = { name, step: 0, values, status: "active", updatedAt: Date.now() };
39
+ this.active.set(key, state);
40
+ await this.storage.set(key, state);
35
41
  return state;
36
42
  }
37
43
  get(key) { return this.active.get(key); }
@@ -50,7 +56,7 @@ class ConversationManager {
50
56
  return false;
51
57
  state.status = "cancelled";
52
58
  state.updatedAt = Date.now();
53
- void this.storage.set(key, state);
59
+ void this.storage.set(key, state).catch(() => undefined);
54
60
  return true;
55
61
  }
56
62
  async cancelAsync(key) {
@@ -90,9 +96,12 @@ class ConversationManager {
90
96
  return removed;
91
97
  }
92
98
  async run(ctx, key, name, steps) {
93
- const state = (await this.getAsync(key)) ?? this.start(key, name);
99
+ const existing = await this.getAsync(key);
100
+ const state = existing ?? await this.startAsync(key, name);
94
101
  if (state.name !== name)
95
102
  throw new Error(`Conversation ${key} belongs to ${state.name}, not ${name}`);
103
+ if (state.status !== "active")
104
+ return state;
96
105
  const flow = new ConversationFlow(ctx, state);
97
106
  const step = steps[state.step];
98
107
  if (!step)
@@ -115,7 +115,7 @@ class RedisStorage {
115
115
  key(key) { return `${this.prefix}${key}`; }
116
116
  unkey(key) { return key.slice(this.prefix.length); }
117
117
  async get(key) { const value = await this.client.get(this.key(key)); return value === null ? undefined : JSON.parse(value); }
118
- async set(key, value, options = {}) { const ttl = options.ttlMs; const redisOptions = ttl === undefined ? {} : ttl >= 1000 ? { PX: Math.max(1, Math.floor(ttl)) } : { PX: Math.max(1, Math.floor(ttl)) }; await this.client.set(this.key(key), JSON.stringify(value), redisOptions); }
118
+ async set(key, value, options = {}) { const ttl = options.ttlMs; const redisOptions = ttl === undefined ? {} : { PX: Math.max(1, Math.floor(ttl)) }; await this.client.set(this.key(key), JSON.stringify(value), redisOptions); }
119
119
  async delete(key) { return (await this.client.del(this.key(key))) > 0; }
120
120
  async has(key) { return (await this.client.exists(this.key(key))) > 0; }
121
121
  async clear() { const keys = await this.client.keys(`${this.prefix}*`); if (keys.length)
@@ -48,6 +48,8 @@ function validateWebAppInitData(initData, botToken, maxAgeSeconds = 86_400, nowM
48
48
  if (!Number.isFinite(maxAgeSeconds) || maxAgeSeconds < 0)
49
49
  throw new RangeError("maxAgeSeconds must be non-negative");
50
50
  const parsed = parseWebAppInitData(initData);
51
+ if (!/^[0-9a-fA-F]{64}$/.test(parsed.hash))
52
+ throw new Error("Web App init data hash must be a 64-character hexadecimal string");
51
53
  const checkString = Object.entries(parsed.data).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}=${value}`).join("\n");
52
54
  const secret = (0, node_crypto_1.createHmac)("sha256", "WebAppData").update(botToken).digest();
53
55
  const expected = (0, node_crypto_1.createHmac)("sha256", secret).update(checkString).digest("hex");
@@ -1,13 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createWebhookHandler = createWebhookHandler;
4
+ const node_crypto_1 = require("node:crypto");
4
5
  function createWebhookHandler(bot, options = {}) {
5
6
  const maxBodyBytes = options.maxBodyBytes ?? 1_048_576;
6
7
  return async (request) => {
7
8
  if (request.method !== "POST")
8
9
  return new Response("Method Not Allowed", { status: 405, headers: { allow: "POST" } });
9
- if (options.secretToken && request.headers.get("x-telegram-bot-api-secret-token") !== options.secretToken)
10
+ if (options.secretToken && !secureEqual(request.headers.get("x-telegram-bot-api-secret-token") ?? "", options.secretToken))
10
11
  return new Response("Unauthorized", { status: 401 });
12
+ const contentType = request.headers.get("content-type") ?? "";
13
+ if (!/^application\/json(?:\s*;|\s*$)/i.test(contentType))
14
+ return new Response("Unsupported Media Type", { status: 415 });
11
15
  const contentLength = Number(request.headers.get("content-length") ?? 0);
12
16
  if (contentLength > maxBodyBytes)
13
17
  return new Response("Payload Too Large", { status: 413 });
@@ -27,3 +31,8 @@ function createWebhookHandler(bot, options = {}) {
27
31
  }
28
32
  };
29
33
  }
34
+ function secureEqual(left, right) {
35
+ const leftBuffer = Buffer.from(left, "utf8");
36
+ const rightBuffer = Buffer.from(right, "utf8");
37
+ return leftBuffer.length === rightBuffer.length && (0, node_crypto_1.timingSafeEqual)(leftBuffer, rightBuffer);
38
+ }
package/docs/API.id.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ![telebibz overview](https://cdn.jsdelivr.net/npm/@xbibzlibrary/telebibz@latest/assets/telebibz-readme-preview.png)
6
6
 
7
- Dokumen ini adalah referensi API untuk `@xbibzlibrary/telebibz@0.1.4`. Seluruh signature dan perilaku yang dijelaskan di sini dipetakan dari source TypeScript yang diekspor package. Jika suatu tipe Telegram belum memiliki pemetaan parameter/result khusus, package tetap menyediakan akses runtime melalui API dinamis, tetapi tipe parameternya masih generik.
7
+ Dokumen ini adalah referensi API untuk rilis `@xbibzlibrary/telebibz` yang sedang dipublikasikan. Seluruh signature dan perilaku yang dijelaskan di sini dipetakan dari source TypeScript yang diekspor package. Jika suatu tipe Telegram belum memiliki pemetaan parameter/result khusus, package tetap menyediakan akses runtime melalui API dinamis, tetapi tipe parameternya masih generik.
8
8
 
9
9
  > **Status implementasi.** Dokumentasi ini menjelaskan kemampuan yang tersedia pada rilis saat ini. `JsonFileStorage`, storage Redis/SQL/Mongo berbasis driver, session/conversation berbasis Storage, cron lima field lengkap, `MenuController`, terminal status output branded, structured logging dengan redaction, validasi Web App, `PaymentsClient`, dan declaration `TelegramTypes` sudah tersedia. Core method map tetap khusus untuk inferensi request/result tertentu, sedangkan `api.raw()` tersedia untuk method Telegram berikutnya.
10
10
 
@@ -1239,8 +1239,8 @@ interface MenuItem {
1239
1239
  label: string;
1240
1240
  callbackData?: string;
1241
1241
  url?: string;
1242
- visible?: boolean | (() => boolean | Promise<boolean>);
1243
- permission?: string;
1242
+ visible?: boolean | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1243
+ permission?: string | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1244
1244
  }
1245
1245
  ```
1246
1246
 
package/docs/API.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  ![telebibz overview](https://cdn.jsdelivr.net/npm/@xbibzlibrary/telebibz@latest/assets/telebibz-readme-preview.png)
5
5
 
6
- This document is the API reference for `@xbibzlibrary/telebibz@0.1.4`. All signatures and behaviors described here are mapped from the package's exported TypeScript source. If a Telegram type does not have a specific parameter/result mapping, the package still provides runtime access via a dynamic API, but the parameter types remain generic.
6
+ This document is the API reference for the current published `@xbibzlibrary/telebibz` release. All signatures and behaviors described here are mapped from the package's exported TypeScript source. If a Telegram type does not have a specific parameter/result mapping, the package still provides runtime access via a dynamic API, but the parameter types remain generic.
7
7
 
8
8
  > **Implementation status.** This documentation describes the capabilities available in the current release. `JsonFileStorage`, driver-based Redis/SQL/Mongo storage, storage-backed sessions/conversations, full five-field cron, `MenuController`, terminal branding, structured redacted logging, Web App validation, PaymentsClient, and vendored `TelegramTypes` declarations are included. The core method map remains specialized for selected request/result inference, while `api.raw()` remains available for future Telegram methods.
9
9
 
@@ -1001,7 +1001,7 @@ interface PluginApi<Context> {
1001
1001
  }
1002
1002
  ```
1003
1003
 
1004
- In this release, `registerMiddleware` and `registerRoute` are available as API hooks but the implementation manager does not yet connect them automatically to the bot/router. Plugins may use `api.bot` and `api.services` directly.
1004
+ In this release, `registerMiddleware` connects plugin middleware to `bot.use()`, and `registerRoute` connects plugin routes to `bot.router.route()`. The bot lifecycle invokes plugin `onUpdate` and `onStop` hooks automatically.
1005
1005
 
1006
1006
  ### `ServiceContainer`
1007
1007
 
@@ -1032,7 +1032,7 @@ new PluginManager<Context>(bot: unknown): PluginManager<Context>
1032
1032
  | `dispose()` | Executes `dispose` in reverse registration order. |
1033
1033
  | `list()` | Returns a read-only list of plugins. |
1034
1034
 
1035
- `Bot.handleUpdate()` in this release does not call `plugins.update()` automatically; call the manager explicitly if plugins require an update lifecycle.
1035
+ `Bot.handleUpdate()` calls `plugins.update()` automatically after the update is processed, and `Bot.stop()` invokes plugin stop hooks before disposal.
1036
1036
 
1037
1037
  ---
1038
1038
 
@@ -1257,8 +1257,8 @@ interface MenuItem {
1257
1257
  label: string;
1258
1258
  callbackData?: string;
1259
1259
  url?: string;
1260
- visible?: boolean | (() => boolean | Promise<boolean>);
1261
- permission?: string;
1260
+ visible?: boolean | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1261
+ permission?: string | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1262
1262
  }
1263
1263
  ```
1264
1264
 
package/docs/API.zh-CN.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ![telebibz 概览](https://cdn.jsdelivr.net/npm/@xbibzlibrary/telebibz@latest/assets/telebibz-readme-preview.png)
6
6
 
7
- 本文件是 `@xbibzlibrary/telebibz@0.1.4` API 参考。此处描述的所有签名和行为均映射自该包导出的 TypeScript 源代码。如果某个 Telegram 类型尚未有特定的参数/结果映射,该包仍通过动态 API 提供运行时访问,但其参数类型仍为通用类型。
7
+ 本文件是当前发布的 `@xbibzlibrary/telebibz` API 参考。此处描述的所有签名和行为均映射自该包导出的 TypeScript 源代码。如果某个 Telegram 类型尚未有特定的参数/结果映射,该包仍通过动态 API 提供运行时访问,但其参数类型仍为通用类型。
8
8
 
9
9
  > **实现状态。** 本文档说明当前版本中可用的功能。`JsonFileStorage`、基于 driver 的 Redis/SQL/Mongo storage、基于 Storage 的 session/conversation、完整五字段 cron、`MenuController`、带 branding 的 terminal status output、带 redaction 的 structured logging、Web App 验证、`PaymentsClient` 和 `TelegramTypes` declaration 均已提供。core method map 仍主要为特定 request/result inference 提供类型,未来 Telegram method 可通过 `api.raw()` 访问。
10
10
 
@@ -1233,8 +1233,8 @@ interface MenuItem {
1233
1233
  label: string;
1234
1234
  callbackData?: string;
1235
1235
  url?: string;
1236
- visible?: boolean | (() => boolean | Promise<boolean>);
1237
- permission?: string;
1236
+ visible?: boolean | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1237
+ permission?: string | ((context: MenuContext, item: MenuItem) => boolean | Promise<boolean>);
1238
1238
  }
1239
1239
  ```
1240
1240
 
@@ -0,0 +1,82 @@
1
+ # GitHub Packages
2
+
3
+ `@xbibzlibrary/telebibz` dirilis ke [npmjs](https://www.npmjs.com/package/@xbibzlibrary/telebibz) dan registry npm GitHub Packages. Repository GitHub resminya adalah [XbibzOfficial777/telebibz](https://github.com/XbibzOfficial777/telebibz).
4
+
5
+ ## Registry
6
+
7
+ URL registry GitHub Packages:
8
+
9
+ ```text
10
+ https://npm.pkg.github.com
11
+ ```
12
+
13
+ Mapping scope npm:
14
+
15
+ ```ini
16
+ @xbibzlibrary:registry=https://npm.pkg.github.com
17
+ ```
18
+
19
+ Workflow release mempublikasikan tarball yang sama ke npmjs dan GitHub Packages setelah typecheck, test, build, security audit, dan release check berhasil. Workflow menggunakan `GITHUB_TOKEN` dengan permission `packages: write`; personal access token GitHub tidak disimpan di repository atau workflow.
20
+
21
+ ## Instalasi package
22
+
23
+ Untuk package public, tambahkan mapping berikut pada `.npmrc` project yang memakai package:
24
+
25
+ ```ini
26
+ @xbibzlibrary:registry=https://npm.pkg.github.com
27
+ ```
28
+
29
+ Jika package atau repository bersifat private, gunakan **personal access token (classic)** dengan minimal akses `read:packages`. Simpan token di luar repository, sebaiknya melalui environment variable reference pada konfigurasi npm user:
30
+
31
+ ```ini
32
+ @xbibzlibrary:registry=https://npm.pkg.github.com
33
+ //npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}
34
+ ```
35
+
36
+ Kemudian jalankan:
37
+
38
+ ```bash
39
+ export GITHUB_PACKAGES_TOKEN="<token-read-packages-kamu>"
40
+ npm install @xbibzlibrary/telebibz
41
+ ```
42
+
43
+ Jangan mengganti placeholder dengan token asli di file yang di-commit. Jangan commit `.npmrc` yang berisi kredensial literal, dan jangan memasukkan token ke issue, pull request, log, atau chat.
44
+
45
+ ## Publikasi lokal
46
+
47
+ Cara yang direkomendasikan adalah workflow GitHub Actions yang telah dilindungi. Workflow memeriksa versi dan hanya publish setelah seluruh release gate berhasil. Publikasi lokal hanya untuk maintainer yang memiliki personal access token (classic) dengan `write:packages` serta permission repository:
48
+
49
+ ```bash
50
+ export GITHUB_PACKAGES_TOKEN="<token-write-packages-kamu>"
51
+ printf '@xbibzlibrary:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}\n' > "$HOME/.npmrc"
52
+ npm run build
53
+ npm pack
54
+ npm publish ./xbibzlibrary-telebibz-<version>.tgz --registry=https://npm.pkg.github.com --access public
55
+ ```
56
+
57
+ Gunakan semantic version baru untuk setiap publikasi. Versi registry bersifat immutable dan tidak boleh ditimpa.
58
+
59
+ ## Permission GitHub Actions
60
+
61
+ Workflow release menggunakan permission minimum berikut:
62
+
63
+ ```yaml
64
+ permissions:
65
+ contents: write
66
+ packages: write
67
+ ```
68
+
69
+ `NPM_TOKEN` tetap menjadi environment secret untuk publikasi ke npmjs. GitHub Packages menggunakan `GITHUB_TOKEN` otomatis, sehingga tidak memerlukan secret GitHub tambahan untuk package milik repository ini. Jika kebijakan organisasi menonaktifkan pewarisan akses package, hubungkan package ke repository dan berikan akses workflow melalui pengaturan package.
70
+
71
+ ## Troubleshooting
72
+
73
+ Respons `401 Unauthorized` biasanya berarti token tidak ada, sudah kedaluwarsa, atau tidak mempunyai scope package yang benar. Respons `403 Forbidden` biasanya berarti akun atau workflow tidak memiliki permission package, atau kebijakan organisasi memblokir publikasi. Respons `404 Not Found` dapat muncul ketika package private diakses tanpa autentikasi atau scope belum diarahkan ke `https://npm.pkg.github.com`.
74
+
75
+ Untuk instalasi dari npmjs, hapus mapping GitHub scope atau gunakan registry npm default. Kedua registry berisi nama package dan versi yang sama, tetapi autentikasi dan access control dikelola secara terpisah.
76
+
77
+ ## Referensi
78
+
79
+ 1. [Working with the npm registry — GitHub Docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry)
80
+ 2. [About permissions for GitHub Packages — GitHub Docs](https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages)
81
+ 3. [Publishing and installing a package with GitHub Actions — GitHub Docs](https://docs.github.com/en/packages/quickstart)
82
+ 4. [npm package.json publishConfig — npm Docs](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#publishconfig)
@@ -0,0 +1,82 @@
1
+ # GitHub Packages
2
+
3
+ `@xbibzlibrary/telebibz` is released to both [npmjs](https://www.npmjs.com/package/@xbibzlibrary/telebibz) and the GitHub Packages npm registry. The canonical GitHub repository is [XbibzOfficial777/telebibz](https://github.com/XbibzOfficial777/telebibz).
4
+
5
+ ## Registry
6
+
7
+ GitHub Packages uses the following npm registry URL:
8
+
9
+ ```text
10
+ https://npm.pkg.github.com
11
+ ```
12
+
13
+ The package scope is mapped to GitHub Packages with:
14
+
15
+ ```ini
16
+ @xbibzlibrary:registry=https://npm.pkg.github.com
17
+ ```
18
+
19
+ The release workflow publishes the same verified tarball to npmjs and GitHub Packages after the type checks, tests, build, security audit, and release checks pass. The workflow uses `GITHUB_TOKEN` with `packages: write`; no GitHub personal access token is stored in the repository or workflow file.
20
+
21
+ ## Installing the package
22
+
23
+ For a public package, use a GitHub Packages-aware `.npmrc` in the consuming project:
24
+
25
+ ```ini
26
+ @xbibzlibrary:registry=https://npm.pkg.github.com
27
+ ```
28
+
29
+ If the package or repository is private, authenticate with a **personal access token (classic)** that has at least `read:packages` access. Store the token outside the repository, preferably in the user-level npm configuration or an environment-variable reference:
30
+
31
+ ```ini
32
+ @xbibzlibrary:registry=https://npm.pkg.github.com
33
+ //npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}
34
+ ```
35
+
36
+ Then install the package:
37
+
38
+ ```bash
39
+ export GITHUB_PACKAGES_TOKEN="<your-read-packages-token>"
40
+ npm install @xbibzlibrary/telebibz
41
+ ```
42
+
43
+ Do not replace the placeholder with a real token in a committed file. Do not commit `.npmrc` files containing literal credentials, and do not paste tokens into issues, pull requests, logs, or chat.
44
+
45
+ ## Publishing locally
46
+
47
+ The recommended publishing path is the protected GitHub Actions workflow. It verifies the version and publishes only after all release gates succeed. Local publishing is intended for maintainers who have a classic personal access token with `write:packages` and repository permission to publish packages:
48
+
49
+ ```bash
50
+ export GITHUB_PACKAGES_TOKEN="<your-write-packages-token>"
51
+ printf '@xbibzlibrary:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}\n' > "$HOME/.npmrc"
52
+ npm run build
53
+ npm pack
54
+ npm publish ./xbibzlibrary-telebibz-<version>.tgz --registry=https://npm.pkg.github.com --access public
55
+ ```
56
+
57
+ Use a new semantic version for every publication. Registry versions are immutable; an existing version must never be overwritten.
58
+
59
+ ## GitHub Actions permissions
60
+
61
+ The release workflow declares the minimum package permission required for publication:
62
+
63
+ ```yaml
64
+ permissions:
65
+ contents: write
66
+ packages: write
67
+ ```
68
+
69
+ `NPM_TOKEN` remains an environment secret for npmjs publication. GitHub Packages uses the automatically provided `GITHUB_TOKEN`, so no additional GitHub token secret is required for the repository's own package. If organization policy disables automatic package access inheritance, connect the package to the repository and grant the workflow access under the package's settings.
70
+
71
+ ## Troubleshooting
72
+
73
+ A `401 Unauthorized` response normally means the token is missing, expired, or lacks the required package scope. A `403 Forbidden` response usually means the account or workflow does not have permission to the package, or that organization policy blocks publication. A `404 Not Found` response can occur when a private package is queried without authentication or when the scope is not mapped to `https://npm.pkg.github.com`.
74
+
75
+ For npmjs installation, omit the GitHub scope mapping or use the default npm registry. Both registries contain the same package name and release version, but authentication and access control are handled independently.
76
+
77
+ ## References
78
+
79
+ 1. [Working with the npm registry — GitHub Docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry)
80
+ 2. [About permissions for GitHub Packages — GitHub Docs](https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages)
81
+ 3. [Publishing and installing a package with GitHub Actions — GitHub Docs](https://docs.github.com/en/packages/quickstart)
82
+ 4. [npm package.json publishConfig — npm Docs](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#publishconfig)
@@ -0,0 +1,82 @@
1
+ # GitHub Packages
2
+
3
+ `@xbibzlibrary/telebibz` 同时发布到 [npmjs](https://www.npmjs.com/package/@xbibzlibrary/telebibz) 和 GitHub Packages npm registry。官方 GitHub 仓库是 [XbibzOfficial777/telebibz](https://github.com/XbibzOfficial777/telebibz)。
4
+
5
+ ## Registry
6
+
7
+ GitHub Packages 使用以下 npm registry 地址:
8
+
9
+ ```text
10
+ https://npm.pkg.github.com
11
+ ```
12
+
13
+ npm scope 映射如下:
14
+
15
+ ```ini
16
+ @xbibzlibrary:registry=https://npm.pkg.github.com
17
+ ```
18
+
19
+ release workflow 会在 typecheck、测试、构建、安全审计和 release check 全部通过后,将同一个经过验证的 tarball 发布到 npmjs 和 GitHub Packages。workflow 使用具有 `packages: write` 权限的 `GITHUB_TOKEN`,不会把 GitHub personal access token 存储在仓库或 workflow 文件中。
20
+
21
+ ## 安装 package
22
+
23
+ 对于 public package,可以在使用方项目的 `.npmrc` 中加入:
24
+
25
+ ```ini
26
+ @xbibzlibrary:registry=https://npm.pkg.github.com
27
+ ```
28
+
29
+ 如果 package 或 repository 是 private,请使用具有至少 `read:packages` 权限的 **personal access token (classic)**。请将 token 保存在仓库之外,建议使用 npm 用户配置中的环境变量引用:
30
+
31
+ ```ini
32
+ @xbibzlibrary:registry=https://npm.pkg.github.com
33
+ //npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}
34
+ ```
35
+
36
+ 然后执行:
37
+
38
+ ```bash
39
+ export GITHUB_PACKAGES_TOKEN="<your-read-packages-token>"
40
+ npm install @xbibzlibrary/telebibz
41
+ ```
42
+
43
+ 不要把真实 token 写入已经提交的文件。不要提交包含明文凭据的 `.npmrc`,也不要在 issue、pull request、日志或聊天中粘贴 token。
44
+
45
+ ## 本地发布
46
+
47
+ 推荐使用受保护的 GitHub Actions workflow 发布。workflow 会检查版本,并且只有所有 release gate 成功后才会发布。本地发布仅适用于拥有 `write:packages` classic token 以及 repository 发布权限的 maintainer:
48
+
49
+ ```bash
50
+ export GITHUB_PACKAGES_TOKEN="<your-write-packages-token>"
51
+ printf '@xbibzlibrary:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}\n' > "$HOME/.npmrc"
52
+ npm run build
53
+ npm pack
54
+ npm publish ./xbibzlibrary-telebibz-<version>.tgz --registry=https://npm.pkg.github.com --access public
55
+ ```
56
+
57
+ 每次发布必须使用新的 semantic version。registry 中的版本是 immutable,不能覆盖已有版本。
58
+
59
+ ## GitHub Actions 权限
60
+
61
+ release workflow 声明了发布所需的最小权限:
62
+
63
+ ```yaml
64
+ permissions:
65
+ contents: write
66
+ packages: write
67
+ ```
68
+
69
+ `NPM_TOKEN` 仍然作为 npmjs 发布所需的 environment secret。GitHub Packages 使用自动提供的 `GITHUB_TOKEN`,因此本仓库的 package 不需要额外的 GitHub token secret。如果组织策略关闭了 package 权限自动继承,请在 package 设置中连接 repository,并授予 workflow 访问权限。
70
+
71
+ ## 故障排查
72
+
73
+ `401 Unauthorized` 通常表示 token 缺失、过期或没有正确的 package scope。`403 Forbidden` 通常表示账号或 workflow 没有 package 权限,或者组织策略禁止发布。访问 private package 时没有认证,或 scope 没有映射到 `https://npm.pkg.github.com`,也可能得到 `404 Not Found`。
74
+
75
+ 从 npmjs 安装时,请删除 GitHub scope mapping 或使用默认 npm registry。两个 registry 包含相同的 package 名称和版本,但认证和 access control 独立管理。
76
+
77
+ ## 参考资料
78
+
79
+ 1. [Working with the npm registry — GitHub Docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry)
80
+ 2. [About permissions for GitHub Packages — GitHub Docs](https://docs.github.com/en/packages/learn-github-packages/about-permissions-for-github-packages)
81
+ 3. [Publishing and installing a package with GitHub Actions — GitHub Docs](https://docs.github.com/en/packages/quickstart)
82
+ 4. [npm package.json publishConfig — npm Docs](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#publishconfig)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbibzlibrary/telebibz",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Production-grade, strongly typed Telegram Bot API SDK and framework for Node.js and TypeScript.",
5
5
  "type": "module",
6
6
  "private": false,