@fa-software/semi2-dsh 0.0.10 → 0.0.11-preview.20260921034433

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.
@@ -7,8 +7,7 @@ import { codeOf } from '../hub/errors.js';
7
7
  /** 等运行面契约出现的上限;超时按宿主直跑(无适配器)处理。 */
8
8
  export const CONTRACT_TIMEOUT_MS = 5_000;
9
9
  const CONTRACT_POLL_MS = 25;
10
- const CREDENTIAL_TRIES = 10;
11
- const CREDENTIAL_INTERVAL_MS = 150;
10
+ export const CREDENTIAL_RETRY = { tries: 10, intervalMs: 150 };
12
11
  /**
13
12
  * 运行面契约:适配器 apply 是长跑 async(等配置 settle),其 fiber 尚未 active:严格查找一直
14
13
  * undefined,故不用 ctx.inject 而直接宽松轮询(服务注册本身是同步的)。
@@ -36,16 +35,16 @@ export async function connectionSnapshot(ports, environment, contract) {
36
35
  return { fields, contract };
37
36
  }
38
37
  /** credentials 存储首次读盘可能晚于插件启动:有界窗口内重试,仍无凭据即按「未配置」处理。 */
39
- export async function resolveConnectionWithRetry(ports, environment, contract) {
38
+ export async function resolveConnectionWithRetry(ports, environment, contract, retry = CREDENTIAL_RETRY) {
40
39
  let consoleUrl = null;
41
- for (let attempt = 0; attempt < CREDENTIAL_TRIES; attempt += 1) {
40
+ for (let attempt = 0; attempt < retry.tries; attempt += 1) {
42
41
  const { fields } = await connectionSnapshot(ports, environment, contract);
43
42
  consoleUrl = fields.url?.value ?? consoleUrl;
44
43
  const connection = connectionOf(fields);
45
44
  if (connection !== null)
46
45
  return { connection, consoleUrl };
47
- if (attempt < CREDENTIAL_TRIES - 1)
48
- await delay(CREDENTIAL_INTERVAL_MS);
46
+ if (attempt < retry.tries - 1)
47
+ await delay(retry.intervalMs);
49
48
  }
50
49
  return { connection: null, consoleUrl };
51
50
  }
@@ -31,7 +31,7 @@ export async function start(engine) {
31
31
  }
32
32
  await ensureContract(engine);
33
33
  engine.workspace().ensureImplicit();
34
- const { connection, consoleUrl } = await resolveConnectionWithRetry(engine.ports, engine.environment, engine.contract());
34
+ const { connection, consoleUrl } = await resolveConnectionWithRetry(engine.ports, engine.environment, engine.contract(), engine.credentialRetry);
35
35
  engine.setConnection(await exchange(engine, connection));
36
36
  if (engine.connection() === null)
37
37
  engine.setCurrent(initialState(false, consoleUrl, engine.workspace().tracked()));
@@ -1,7 +1,7 @@
1
1
  import { setTimeout as delay } from 'node:timers/promises';
2
2
  import { initialState, } from '../hub/facts.js';
3
3
  import { DOMAINS } from './registry.js';
4
- import { CONTRACT_TIMEOUT_MS } from './connection.js';
4
+ import { CONTRACT_TIMEOUT_MS, CREDENTIAL_RETRY } from './connection.js';
5
5
  import { healthSnapshot } from './publish.js';
6
6
  /** 领域 attach 的等待上限:超时按「该面不提供此能力」审计(依赖永不到达不能永久悬空)。 */
7
7
  const DOMAIN_ATTACH_TIMEOUT_MS = 2_000;
@@ -25,6 +25,7 @@ export class Orchestrator {
25
25
  environment;
26
26
  startupDir;
27
27
  contractTimeoutMs;
28
+ credentialRetry;
28
29
  runtimeContract;
29
30
  resolved = false;
30
31
  activeConnection = null;
@@ -41,6 +42,7 @@ export class Orchestrator {
41
42
  this.environment = { ...environment };
42
43
  this.startupDir = process.cwd();
43
44
  this.contractTimeoutMs = options.contractTimeoutMs ?? CONTRACT_TIMEOUT_MS;
45
+ this.credentialRetry = { ...CREDENTIAL_RETRY, ...options.credentialRetry };
44
46
  const settled = Promise.withResolvers();
45
47
  this.ready = settled.promise;
46
48
  this.settledResolve = settled.resolve;
@@ -5,6 +5,12 @@ import type { Semi2Api } from '../api/index.js';
5
5
  import type { Ports } from './ports.js';
6
6
  /** 等运行面契约出现的上限;超时按宿主直跑(无适配器)处理。 */
7
7
  export declare const CONTRACT_TIMEOUT_MS = 5000;
8
+ /** 凭据存储首次读盘可能晚于插件启动:有界重试窗口(生产默认见 CREDENTIAL_RETRY)。 */
9
+ export interface CredentialRetry {
10
+ tries: number;
11
+ intervalMs: number;
12
+ }
13
+ export declare const CREDENTIAL_RETRY: CredentialRetry;
8
14
  export interface ConnectionStore {
9
15
  /** 当前连接凭据(契约或 dsh credentials 存储);未配置为 null。 */
10
16
  get(): ConnectionCredentials | null;
@@ -27,7 +33,7 @@ export interface ConnectionResolution {
27
33
  /** 凭据与地址的当前快照(地址单独解析:只有地址没有令牌也算「未登录但已知端点」)。 */
28
34
  export declare function connectionSnapshot(ports: Ports, environment: NodeJS.ProcessEnv, contract: Semi2Runtime | undefined): Promise<ConnectionSnapshot>;
29
35
  /** credentials 存储首次读盘可能晚于插件启动:有界窗口内重试,仍无凭据即按「未配置」处理。 */
30
- export declare function resolveConnectionWithRetry(ports: Ports, environment: NodeJS.ProcessEnv, contract: Semi2Runtime | undefined): Promise<ConnectionResolution>;
36
+ export declare function resolveConnectionWithRetry(ports: Ports, environment: NodeJS.ProcessEnv, contract: Semi2Runtime | undefined, retry?: CredentialRetry): Promise<ConnectionResolution>;
31
37
  /**
32
38
  * CNB 面:把平台注入的短期 CNB_TOKEN 换成 hub 用户密钥(一次兑换,之后一律用换来的密钥)。
33
39
  * 兑换失败按现有降级口径:本次不注入配置,不阻断会话。其它面 / 登录态原样返回。
@@ -6,6 +6,7 @@ import type { Semi2Runtime } from '../contract.js';
6
6
  import type { ConnectionCredentials } from '../hub/credentials.js';
7
7
  import type { HealthContributor } from './health.js';
8
8
  import type { Ports, SettingsLike } from './ports.js';
9
+ import { type CredentialRetry } from './connection.js';
9
10
  /** 编排层驱动的工作区面 = 工作区 peer 去掉项目解析(缺席时由空操作替身顶上)。 */
10
11
  export type WorkspaceOps = Omit<WorkspacePeer, 'projectForCwd' | 'workspaceProjects'>;
11
12
  export declare const NOOP_WORKSPACE: WorkspaceOps;
@@ -18,6 +19,7 @@ export interface OrchestratorInternals {
18
19
  /** 启动目录(迁移与状态展示共用同一个事实;状态渲染因此保持纯函数)。 */
19
20
  readonly startupDir: string;
20
21
  readonly contractTimeoutMs: number;
22
+ readonly credentialRetry: CredentialRetry;
21
23
  readonly domains: ReadonlyMap<DomainId, DomainService & object>;
22
24
  /** 领域 peer 面(类型化;该领域未就位返回 undefined)。 */
23
25
  peer<K extends DomainId>(id: K): DomainPeers[K] | undefined;
@@ -45,7 +47,10 @@ export interface OrchestratorInternals {
45
47
  noteFailure(area: string, error: unknown): string;
46
48
  }
47
49
  export interface OrchestratorOptions {
50
+ /** 等运行面契约出现的上限(ms):默认 5s,宿主直跑即等满。 */
48
51
  contractTimeoutMs?: number;
52
+ /** 凭据重试窗口:宿主的凭据存储晚就绪时用(测试可收短,默认见 connection.ts)。 */
53
+ credentialRetry?: Partial<CredentialRetry>;
49
54
  }
50
55
  export declare class Orchestrator implements DomainHost, OrchestratorInternals {
51
56
  readonly ctx: Context;
@@ -57,6 +62,7 @@ export declare class Orchestrator implements DomainHost, OrchestratorInternals {
57
62
  readonly environment: NodeJS.ProcessEnv;
58
63
  readonly startupDir: string;
59
64
  readonly contractTimeoutMs: number;
65
+ readonly credentialRetry: CredentialRetry;
60
66
  private runtimeContract;
61
67
  private resolved;
62
68
  private activeConnection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fa-software/semi2-dsh",
3
- "version": "0.0.10",
3
+ "version": "0.0.11-preview.20260921034433",
4
4
  "type": "module",
5
5
  "description": "Semi2 单插件:semi2-hub 配置引导 + codegraph 结构索引 + 公共 Web 能力。",
6
6
  "main": "lib/index.js",
@@ -77,7 +77,6 @@
77
77
  "scripts": {
78
78
  "build": "rm -rf lib && node scripts/gen-documents.mjs && graphql-codegen -c codegen.ts && tsc -p tsconfig.json && tsdown -c tsdown.config.ts",
79
79
  "typecheck": "tsc -p tsconfig.json --noEmit",
80
- "test": "pnpm run build && node --test test/*.test.mjs",
81
80
  "dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
82
81
  "dev:client": "tsdown -c tsdown.config.ts --watch"
83
82
  }