refactor(liveshare-protocol): publish one entry point

The root entry already re-exports the wire codecs, the identity contract, the
viewer carrier, and the viewer-state vocabulary, so `./protocol` and
`./identity` were aliases of subsets that every consumer had to mirror in the
tsconfig path list. Keep `.` alone, keep the mock provider in its source module
for tests, and bundle only the root.
This commit is contained in:
mektpoy committed 2026-10-23 16:13:34 +08:00
1 parent c34276ec5a
commit c682dfaa3b
11 files changed
+31 -57

No files matched your search

@@ -18,14 +18,14 @@
en: bbff250eba0f1b89
zh: 0a618f05cc88ee2b
/deepseek-ai-dsh-experimental-liveshare-protocol/use-this-package/when-to-use-it:
en: fc94a4bd3119d40d
zh: e85f74bbacb4fd09
en: d3f965cdd4635ef2
zh: cca0198bc469ba1d
/deepseek-ai-dsh-experimental-liveshare-protocol/use-this-package/entry-point:
en: 452b98f914e90804
zh: 20c344a12a23f9c1
/deepseek-ai-dsh-experimental-liveshare-protocol/understand-the-implementation:
en: ae0264f375192b04
zh: ba1d95ab72fc003c
en: 2b683ba1b31c8ce5
zh: 94ad38d16e83f823
/deepseek-ai-dsh-experimental-liveshare-protocol/further-exploration:
en: e773c21200a61a9d
zh: 57108786433cf892
@@ -26,13 +26,13 @@ English | [中文](README.zh.md)
### When to use it
Import `./protocol` and `./identity` from this package whenever code must speak the Liveshare wire or resolve one viewer identity: the owner host and its gateway worker, the Relay server and its acceptance tests. The viewer carrier and the viewer-state vocabulary are imported from the package root. This is a library — no profile mounts it and no `cordis.yml` row names it.
Import this package whenever code must speak the Liveshare wire or resolve one viewer identity: the owner host and its gateway worker, the Relay server and its acceptance tests. The root entry carries the wire codecs, the identity contract, the viewer carrier, and the viewer-state vocabulary; the mock provider lives in `src/identity/mock.ts` for tests only and no package entry exposes it. This is a library — no profile mounts it and no `cordis.yml` row names it.
### Entry point
```ts
import { parseGatewayFrame, rawText, sendFrame } from '@deepseek-ai/dsh-experimental-liveshare-protocol/protocol'
import { identityKeyOf, normalizeIdentity } from '@deepseek-ai/dsh-experimental-liveshare-protocol/identity'
import { parseGatewayFrame, rawText, sendFrame } from '@deepseek-ai/dsh-experimental-liveshare-protocol'
import { identityKeyOf, normalizeIdentity } from '@deepseek-ai/dsh-experimental-liveshare-protocol'
```
The viewer carrier (`installViewerCarrier`) and the viewer-state vocabulary are published through the root entry, not through their own subpaths, because both faces of the owner page consume them together.
@@ -56,7 +56,7 @@ Relay compatibility uses declared versions, capabilities, and explicit refusals,
| [`src/index.ts`](src/index.ts) | Both faces re-exported for callers that want one import |
| [`src/tunnel-protocol.ts`](src/tunnel-protocol.ts) | Owner/worker IPC frames, gateway frames, and their codecs |
| [`src/viewer-carrier.ts`](src/viewer-carrier.ts) | Viewer-page carrier script and the owner page routes it forwards; reachable through the root entry |
| [`src/viewer-states.ts`](src/viewer-states.ts) | Viewer state vocabulary and its answers, re-exported by `./protocol` and the root entry |
| [`src/viewer-states.ts`](src/viewer-states.ts) | Viewer state vocabulary and its answers, re-exported by the root entry |
| [`src/identity/types.ts`](src/identity/types.ts) | Provider-neutral identity triple and `IdentityProvider` contract |
| [`src/identity/keys.ts`](src/identity/keys.ts) | Canonical ACL key codec and the tenant normalization adapters apply before storing an identity |
| [`src/identity/mock.ts`](src/identity/mock.ts) | Loopback identity provider for local runs and tests |
@@ -26,13 +26,13 @@ kind: "package-library"
### 何时使用
凡是需要说 Liveshare 线路协议或解析某个 viewer 身份的代码,都从本包导入 `./protocol` 与 `./identity`:owner host 及其 gateway worker、Relay server 及其验收测试。查看页载体与查看页状态词汇从包根入口导入。这是一个库——没有 profile 会挂载它,也没有 `cordis.yml` 行引用它。
凡是需要说 Liveshare 线路协议或解析某个 viewer 身份的代码,都导入本包:owner host 及其 gateway worker、Relay server 及其验收测试。包根入口同时携带帧编解码、身份契约、查看页载体与查看页状态词汇;mock provider 位于 `src/identity/mock.ts`,仅供测试使用,任何包入口都不导出它。这是一个库——没有 profile 会挂载它,也没有 `cordis.yml` 行引用它。
### 入口
```ts
import { parseGatewayFrame, rawText, sendFrame } from '@deepseek-ai/dsh-experimental-liveshare-protocol/protocol'
import { identityKeyOf, normalizeIdentity } from '@deepseek-ai/dsh-experimental-liveshare-protocol/identity'
import { parseGatewayFrame, rawText, sendFrame } from '@deepseek-ai/dsh-experimental-liveshare-protocol'
import { identityKeyOf, normalizeIdentity } from '@deepseek-ai/dsh-experimental-liveshare-protocol'
```
查看页载体(`installViewerCarrier`)与查看页状态词汇通过根入口发布,而不是各自的子路径,因为 owner 页面的两个面会一起消费它们。
@@ -56,7 +56,7 @@ Relay 兼容性依靠声明版本、能力和明确拒绝,不提供逐发布
| [`src/index.ts`](src/index.ts) | 为只想一次导入的调用方复出两个面 |
| [`src/tunnel-protocol.ts`](src/tunnel-protocol.ts) | owner/worker IPC 帧、gateway 帧及其编解码 |
| [`src/viewer-carrier.ts`](src/viewer-carrier.ts) | 查看页载体脚本及其转发的 owner 页面路由;经根入口引入 |
| [`src/viewer-states.ts`](src/viewer-states.ts) | 查看页状态词汇及其应答,由 `./protocol` 与根入口复出 |
| [`src/viewer-states.ts`](src/viewer-states.ts) | 查看页状态词汇及其应答,由根入口复出 |
| [`src/identity/types.ts`](src/identity/types.ts) | 与 provider 无关的身份三元组与 `IdentityProvider` 契约 |
| [`src/identity/keys.ts`](src/identity/keys.ts) | 规范 ACL 身份键编解码,以及 adapter 存入身份前的 tenant 规范化 |
| [`src/identity/mock.ts`](src/identity/mock.ts) | 供本地运行与测试使用的 loopback 身份 provider |
@@ -15,26 +15,10 @@
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./identity": {
"types": "./lib/types/identity/index.d.ts",
"default": "./lib/identity/index.js"
},
"./identity/mock": {
"types": "./lib/types/identity/mock.d.ts",
"default": "./lib/identity/mock.js"
},
"./protocol": {
"types": "./lib/types/tunnel-protocol.d.ts",
"default": "./lib/tunnel-protocol.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/identity/index.js",
"lib/identity/mock.js",
"lib/tunnel-protocol.js",
"lib/types/**/*.d.ts"
],
"license": "MIT",
@@ -1,27 +1,23 @@
/** The package's public entry points re-export the one shared contract. */
/** The package's single public entry carries the whole shared contract. */
import { expect, it } from 'vitest'
import * as identity from '@deepseek-ai/dsh-experimental-liveshare-protocol/identity'
import * as protocol from '@deepseek-ai/dsh-experimental-liveshare-protocol/protocol'
import * as root from '@deepseek-ai/dsh-experimental-liveshare-protocol'
import { MockIdentityProvider } from '../src/identity/mock.ts'
it('publishes the mock identity provider only on its test-scoped entry', async () => {
const mock = await import('@deepseek-ai/dsh-experimental-liveshare-protocol/identity/mock')
expect(mock.MockIdentityProvider).toBeTypeOf('function')
expect('MockIdentityProvider' in root).toBe(false)
})
it('re-exports the protocol and identity contracts from the package root', () => {
expect(root.LIVESHARE_PROTOCOL_VERSION).toBe(protocol.LIVESHARE_PROTOCOL_VERSION)
expect(root.parseShareAccessState).toBe(protocol.parseShareAccessState)
expect(root.identityKeyOf).toBe(identity.identityKeyOf)
expect('MockIdentityProvider' in identity).toBe(false)
it('publishes the wire, identity, carrier, and viewer-state contracts from the package root', () => {
expect(root.LIVESHARE_PROTOCOL_VERSION).toBeTypeOf('number')
expect(root.parseShareAccessState).toBeTypeOf('function')
expect(root.parseTunnelWorkerCommand).toBeTypeOf('function')
expect(root.identityKeyOf({ providerId: 'p', tenantId: 't', subjectId: 's' })).toBe('p:t:s')
expect(root.identityFromKey('p:t:s')).toEqual({ providerId: 'p', tenantId: 't', subjectId: 's' })
expect(root.identityFromKey('p:t')).toBeUndefined()
expect(root.identityFromKey('p::s')).toBeUndefined()
expect(root.viewerCarrierScript).toBeTypeOf('function')
expect(root.VIEWER_STATE_REACH).toBeTypeOf('object')
})
it('re-exports the identity contract from its own entry', () => {
expect(identity.identityKeyOf({ providerId: 'p', tenantId: 't', subjectId: 's' })).toBe('p:t:s')
expect(identity.identityFromKey('p:t:s')).toEqual({ providerId: 'p', tenantId: 't', subjectId: 's' })
expect(identity.identityFromKey('p:t')).toBeUndefined()
expect(identity.identityFromKey('p::s')).toBeUndefined()
it('keeps the mock identity provider out of the published surface', () => {
// Tests import the mock from its source module; no package entry exposes it.
expect('MockIdentityProvider' in root).toBe(false)
expect(MockIdentityProvider).toBeTypeOf('function')
})
@@ -4,7 +4,7 @@ import { describe, expect, it } from 'vitest'
import {
MockIdentityProvider,
type MockIdentityPersona,
} from '@deepseek-ai/dsh-experimental-liveshare-protocol/identity/mock'
} from '../src/identity/mock.ts'
/** The personas one provider is built from; the array stays writable so a test can empty it. */
function personas(): MockIdentityPersona[] {
@@ -6,7 +6,7 @@ import {
normalizeIdentity,
requireIdentityTenant,
type IdentityActor,
} from '@deepseek-ai/dsh-experimental-liveshare-protocol/identity'
} from '@deepseek-ai/dsh-experimental-liveshare-protocol'
const actor: IdentityActor = {
providerId: 'example',
@@ -11,7 +11,7 @@ import {
parseTunnelWorkerEvent,
rejectedCommandShareId,
unsupportedFrameRefusal,
} from '@deepseek-ai/dsh-experimental-liveshare-protocol/protocol'
} from '@deepseek-ai/dsh-experimental-liveshare-protocol'
/** Which two endpoints exchanged a recorded frame, which also names the codec that reads it. */
type Direction = 'relay->gateway' | 'gateway->relay' | 'host->worker' | 'worker->host'
@@ -11,7 +11,7 @@ import {
sendFrame,
unsupportedFrameRefusal,
viewerRequestFields,
} from '@deepseek-ai/dsh-experimental-liveshare-protocol/protocol'
} from '@deepseek-ai/dsh-experimental-liveshare-protocol'
/** One registration token; the parsers accept only this UUID-v4 shape. */
const REGISTRATION = '11111111-1111-4111-8111-111111111111'
@@ -12,9 +12,6 @@ export default defineConfig(({ env }) => {
return {
entry: [
'lib/types/index.js',
'lib/types/identity/index.js',
'lib/types/identity/mock.js',
'lib/types/tunnel-protocol.js',
],
outDir: 'lib',
format: ['esm'],
-3
View File
@@ -375,9 +375,6 @@
"@deepseek-ai/dsh-experimental-session-inspector/client": ["./packages/experimental/session-inspector/src/client/index.ts"],
"@deepseek-ai/dsh-experimental-inspector/client": ["./packages/experimental/inspector/src/client/index.ts"],
"@deepseek-ai/dsh-experimental-liveshare-protocol": ["./packages/experimental/liveshare-protocol/src"],
"@deepseek-ai/dsh-experimental-liveshare-protocol/identity": ["./packages/experimental/liveshare-protocol/src/identity/index.ts"],
"@deepseek-ai/dsh-experimental-liveshare-protocol/identity/mock": ["./packages/experimental/liveshare-protocol/src/identity/mock.ts"],
"@deepseek-ai/dsh-experimental-liveshare-protocol/protocol": ["./packages/experimental/liveshare-protocol/src/tunnel-protocol.ts"],
"@deepseek-ai/dsh-experimental-ptc-runtime-python": ["./packages/experimental/ptc-runtime-python/src"],
"@deepseek-ai/dsh-util-crypto": ["./packages/util/crypto/src"],
"@deepseek-ai/dsh-util-values": ["./packages/util/values/src"],