livedomains 0.0.0-stage → 1.0.1

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.
package/README.md CHANGED
@@ -1,3 +1,112 @@
1
- # Temporary Holding Version
1
+ # livedomains
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Base64 编码的直播域名配置包,用于 Android App 域名容灾。
4
+
5
+ ## 核心思路
6
+
7
+ > **用 npm + CDN 作为免费、高可用的域名配置分发通道,让 Android App 在域名挂了的时候能自我修复。**
8
+
9
+ ```text
10
+ 域名挂了时(你的操作):
11
+ python3 publish.py → 自动拉接口 → 生成 domains.json → npm publish
12
+ │
13
+ ▼
14
+ jsdelivr / unpkg CDN 自动更新(1-5分钟)
15
+ │
16
+ ▼
17
+ Android App:
18
+ CDN 拉取 domains.json → base64 解码 → 获得新域名 → 切换重试
19
+ ```
20
+
21
+ ## 与 domains007 的区别
22
+
23
+ | 维度 | domains007 | livedomains |
24
+ | ------ | ------ | ------ |
25
+ | 顶级标识 | `channels[产品code]` | `projects[project_key]` |
26
+ | 每项结构 | `{ primary, fallbacks }` | 5 个具名槽位,每个是列表 |
27
+ | 槽位 | 主域名 + fallbacks | primary / payment / activity / ext1 / ext2 |
28
+
29
+ ## 项目结构
30
+
31
+ ```text
32
+ livedomains/
33
+ ├── package.json # name=livedomains, version
34
+ ├── domains.json # ★ 核心:base64 编码的域名配置(发布到 npm)
35
+ ├── index.js # CommonJS 入口,自动解码
36
+ ├── index.mjs # ESM 入口
37
+ ├── index.d.ts # TypeScript 类型定义
38
+ ├── publish.py # 一键发布脚本(本地工具,不入库)
39
+ ├── encode.js # 手动编码脚本
40
+ ├── .npmignore
41
+ └── README.md
42
+ ```
43
+
44
+ ## domains.json 设计
45
+
46
+ ```json
47
+ {
48
+ "version": 1,
49
+ "updatedAt": "2026-10-31T00:00:00.000Z",
50
+ "payload": "eyJwcm9qZWN0cyI6..."
51
+ }
52
+ ```
53
+
54
+ `payload` 是 base64 编码的 JSON,解码后是多项目结构:
55
+
56
+ ```json
57
+ {
58
+ "projects": {
59
+ "k8": {
60
+ "primary": ["https://minio-api.shooko.cn"],
61
+ "payment": ["https://live-payment.shooko.cn"],
62
+ "activity": ["https://minio-h5.shooko.cn"],
63
+ "ext1": ["https://minio-ext1.shooko.cn"],
64
+ "ext2": ["https://minio-ext2.shooko.cn"]
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ 每个项目有 5 个语义固定的槽位,每个槽位是一个域名列表(按顺序尝试):
71
+
72
+ | 槽位 | 含义 |
73
+ | ------ | ------ |
74
+ | `primary` | 主域名(API) |
75
+ | `payment` | 支付域名 |
76
+ | `activity` | 活动域名(H5) |
77
+ | `ext1` | 扩展位 1 |
78
+ | `ext2` | 扩展位 2 |
79
+
80
+ ## Usage (Node.js)
81
+
82
+ ```js
83
+ const live = require('livedomains');
84
+ console.log(live.getProjectKeys()); // ["k8", ...]
85
+ console.log(live.getProject('k8')); // { primary, payment, activity, ext1, ext2 }
86
+ console.log(live.getDomains('k8', 'payment')); // ["https://live-payment.shooko.cn"]
87
+ console.log(live.getVersion()); // 1
88
+ ```
89
+
90
+ ## 发布流程(一键脚本)
91
+
92
+ ```bash
93
+ cd npm_plan/livedomains
94
+ python3 publish.py # 交互:打印摘要 → 输入 y 发布
95
+ python3 publish.py --yes # 跳过确认直接发布
96
+ ```
97
+
98
+ > ⚠️ 当前 `publish.py` 的 `API_URL` 为空占位,待填入真实接口地址后才能拉取发布。
99
+ > 接口返回结构约定:
100
+ > `{"code":200,"msg":"ok","data":{"primary":[],"payment":[],"activity":[],"ext1":[],"ext2":[]}}`
101
+
102
+ ## Android: Fetch from CDN
103
+
104
+ ```text
105
+ https://cdn.jsdelivr.net/npm/livedomains/domains.json
106
+ https://cdn.jsdelivr.net/npm/livedomains@latest/domains.json
107
+ https://unpkg.com/livedomains@latest/domains.json
108
+ ```
109
+
110
+ ## License
111
+
112
+ MIT
package/domains.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "version": 2,
3
+ "updatedAt": "2026-11-04T16:25:05.498234Z",
4
+ "payload": "eyJwcm9qZWN0cyI6IHsiazhsaXZlIjogeyJwcmltYXJ5IjogW10sICJwYXltZW50IjogW10sICJhY3Rpdml0eSI6IFsiaHR0cHM6Ly9taW5pby1saXZlLnNob29rby5jbiJdLCAiZXh0MSI6IFtdLCAiZXh0MiI6IFtdfX19"
5
+ }
package/index.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ declare module 'livedomains' {
2
+ /** Named domain slots of a project */
3
+ type SlotName = 'primary' | 'payment' | 'activity' | 'ext1' | 'ext2';
4
+
5
+ /** Project domain config: each slot is a list of candidate domains */
6
+ type ProjectConfig = Record<SlotName, string[]>;
7
+
8
+ /**
9
+ * Get config for a specific project.
10
+ * @returns null if project not found
11
+ */
12
+ export function getProject(key: string): ProjectConfig | null;
13
+
14
+ /**
15
+ * Get all project keys.
16
+ */
17
+ export function getProjectKeys(): string[];
18
+
19
+ /**
20
+ * Get the domain list for a specific slot of a project.
21
+ * @returns null if project or slot not found
22
+ */
23
+ export function getDomains(key: string, slot: SlotName): string[] | null;
24
+
25
+ /**
26
+ * Get the config version number for cache comparison.
27
+ */
28
+ export function getVersion(): number;
29
+
30
+ /** Config version */
31
+ export const version: number;
32
+
33
+ /** Last update timestamp (ISO 8601) */
34
+ export const updatedAt: string;
35
+
36
+ /** Raw projects map */
37
+ export const projects: Record<string, ProjectConfig>;
38
+
39
+ const _default: {
40
+ version: number;
41
+ updatedAt: string;
42
+ projects: Record<string, ProjectConfig>;
43
+ };
44
+ export default _default;
45
+ }
package/index.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * livedomains
3
+ *
4
+ * Decodes base64-encoded project-based domain configuration from domains.json.
5
+ * Each project has five named slots: primary / payment / activity / ext1 / ext2.
6
+ * Usage:
7
+ * const live = require('livedomains');
8
+ * const project = live.getProject('k8live');
9
+ * console.log(project.payment); // ["https://live-payment.shooko.cn"]
10
+ */
11
+
12
+ const raw = require('./domains.json');
13
+
14
+ function decodeBase64(str) {
15
+ if (typeof Buffer !== 'undefined') {
16
+ return Buffer.from(str, 'base64').toString('utf-8');
17
+ }
18
+ if (typeof atob !== 'undefined') {
19
+ return atob(str);
20
+ }
21
+ throw new Error('No base64 decoder available');
22
+ }
23
+
24
+ function parseConfig(rawConfig) {
25
+ if (!rawConfig || !rawConfig.payload) {
26
+ throw new Error('Invalid domains.json: missing payload');
27
+ }
28
+ try {
29
+ const decoded = decodeBase64(rawConfig.payload);
30
+ const config = JSON.parse(decoded);
31
+ return {
32
+ version: rawConfig.version,
33
+ updatedAt: rawConfig.updatedAt,
34
+ ...config,
35
+ };
36
+ } catch (e) {
37
+ throw new Error('Failed to decode domain config: ' + e.message);
38
+ }
39
+ }
40
+
41
+ const config = parseConfig(raw);
42
+
43
+ /**
44
+ * Get config for a specific project.
45
+ * @param {string} key - project key, e.g. "k8live"
46
+ * @returns {{ primary: string[], payment: string[], activity: string[], ext1: string[], ext2: string[] } | null}
47
+ */
48
+ function getProject(key) {
49
+ if (!config.projects || !config.projects[key]) return null;
50
+ return config.projects[key];
51
+ }
52
+
53
+ /**
54
+ * Get all project keys.
55
+ * @returns {string[]}
56
+ */
57
+ function getProjectKeys() {
58
+ return Object.keys(config.projects || {});
59
+ }
60
+
61
+ /**
62
+ * Get the domain list for a specific slot of a project.
63
+ * @param {string} key - project key
64
+ * @param {string} slot - one of "primary" | "payment" | "activity" | "ext1" | "ext2"
65
+ * @returns {string[] | null}
66
+ */
67
+ function getDomains(key, slot) {
68
+ const project = getProject(key);
69
+ if (!project) return null;
70
+ return project[slot] || null;
71
+ }
72
+
73
+ /**
74
+ * Get the config version number (for cache comparison).
75
+ */
76
+ function getVersion() {
77
+ return config.version;
78
+ }
79
+
80
+ module.exports = {
81
+ getProject,
82
+ getProjectKeys,
83
+ getDomains,
84
+ getVersion,
85
+ version: config.version,
86
+ updatedAt: config.updatedAt,
87
+ // Raw access if needed
88
+ projects: config.projects || {},
89
+ };
package/index.mjs ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * livedomains — ESM entry
3
+ */
4
+
5
+ import { readFileSync } from 'node:fs';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { dirname, join } from 'node:path';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const raw = JSON.parse(readFileSync(join(__dirname, 'domains.json'), 'utf-8'));
11
+
12
+ function decodeBase64(str) {
13
+ return Buffer.from(str, 'base64').toString('utf-8');
14
+ }
15
+
16
+ function parseConfig(rawConfig) {
17
+ if (!rawConfig || !rawConfig.payload) {
18
+ throw new Error('Invalid domains.json: missing payload');
19
+ }
20
+ try {
21
+ const decoded = decodeBase64(rawConfig.payload);
22
+ const config = JSON.parse(decoded);
23
+ return { version: rawConfig.version, updatedAt: rawConfig.updatedAt, ...config };
24
+ } catch (e) {
25
+ throw new Error('Failed to decode domain config: ' + e.message);
26
+ }
27
+ }
28
+
29
+ const config = parseConfig(raw);
30
+
31
+ export function getProject(key) {
32
+ if (!config.projects || !config.projects[key]) return null;
33
+ return config.projects[key];
34
+ }
35
+
36
+ export function getProjectKeys() {
37
+ return Object.keys(config.projects || {});
38
+ }
39
+
40
+ export function getDomains(key, slot) {
41
+ const project = getProject(key);
42
+ if (!project) return null;
43
+ return project[slot] || null;
44
+ }
45
+
46
+ export function getVersion() {
47
+ return config.version;
48
+ }
49
+
50
+ export const version = config.version;
51
+ export const updatedAt = config.updatedAt;
52
+ export const projects = config.projects || {};
53
+ export default config;
package/package.json CHANGED
@@ -1,6 +1,29 @@
1
1
  {
2
2
  "name": "livedomains",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "Base64-encoded live domain configuration (primary/payment/activity/ext1/ext2) for Android app failover",
5
+ "main": "index.js",
6
+ "module": "index.mjs",
7
+ "types": "index.d.ts",
8
+ "files": [
9
+ "index.js",
10
+ "index.mjs",
11
+ "index.d.ts",
12
+ "domains.json"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://gitee.com/381004367/livedomains.git"
17
+ },
18
+ "publishConfig": {
19
+ "registry": "https://registry.npmjs.org/"
20
+ },
21
+ "keywords": [
22
+ "keep-alive",
23
+ "live",
24
+ "domain",
25
+ "failover",
26
+ "android"
27
+ ],
28
+ "license": "MIT"
29
+ }