@viceme-ai/sdk-poc 0.1.7-poc.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 +71 -0
- package/dist/bootstrap.min.js +2 -0
- package/dist/bootstrap.min.js.map +1 -0
- package/dist/chunks/client-DgGpWHrf.js +959 -0
- package/dist/chunks/client-DgGpWHrf.js.map +1 -0
- package/dist/chunks/version-mxCwx8AO.js +51 -0
- package/dist/chunks/version-mxCwx8AO.js.map +1 -0
- package/dist/core/build-endpoints.d.ts +9 -0
- package/dist/core/build-endpoints.d.ts.map +1 -0
- package/dist/core/capabilities.d.ts +63 -0
- package/dist/core/capabilities.d.ts.map +1 -0
- package/dist/core/client.d.ts +65 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/config.d.ts +32 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/errors.d.ts +37 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/lifecycle.d.ts +25 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/presentation.d.ts +32 -0
- package/dist/core/presentation.d.ts.map +1 -0
- package/dist/danmaku/anchor.d.ts +14 -0
- package/dist/danmaku/anchor.d.ts.map +1 -0
- package/dist/danmaku/index.d.ts +8 -0
- package/dist/danmaku/index.d.ts.map +1 -0
- package/dist/danmaku/mount.d.ts +4 -0
- package/dist/danmaku/mount.d.ts.map +1 -0
- package/dist/danmaku.js +143 -0
- package/dist/danmaku.js.map +1 -0
- package/dist/generated/public-contract.d.ts +700 -0
- package/dist/generated/public-contract.d.ts.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/loader/attributes.d.ts +21 -0
- package/dist/loader/attributes.d.ts.map +1 -0
- package/dist/loader/auto-loader.d.ts +51 -0
- package/dist/loader/auto-loader.d.ts.map +1 -0
- package/dist/loader/bootstrap.d.ts +1 -0
- package/dist/loader/bootstrap.d.ts.map +1 -0
- package/dist/loader/events.d.ts +45 -0
- package/dist/loader/events.d.ts.map +1 -0
- package/dist/loader/main.d.ts +11 -0
- package/dist/loader/main.d.ts.map +1 -0
- package/dist/loader/mount-handle.d.ts +25 -0
- package/dist/loader/mount-handle.d.ts.map +1 -0
- package/dist/loader/registry.d.ts +42 -0
- package/dist/loader/registry.d.ts.map +1 -0
- package/dist/manifest.json +52 -0
- package/dist/session/session.d.ts +67 -0
- package/dist/session/session.d.ts.map +1 -0
- package/dist/testing/test-adapter.d.ts +59 -0
- package/dist/testing/test-adapter.d.ts.map +1 -0
- package/dist/testing.d.ts +9 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +75 -0
- package/dist/testing.js.map +1 -0
- package/dist/transport/transport.d.ts +44 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/viceme.min.js +2 -0
- package/dist/viceme.min.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-DgGpWHrf.js","sources":["../../src/core/config.ts","../../src/core/lifecycle.ts","../../src/session/session.ts","../../src/core/presentation.ts","../../src/core/capabilities.ts","../../src/core/client.ts"],"sourcesContent":["/**\n * Public client configuration.\n *\n * Production `createViceMe()` accepts exactly `workKey`, `region`, and\n * `signal`. Anything else (transport, clock, request ids, base URLs) is a\n * testing-only concern and lives in `@viceme-ai/sdk/testing`, so Agents can\n * never bake temporary or internal endpoints into user projects.\n */\n\nimport { configInvalid } from './errors.ts';\nimport { BUILD_API_BASE_URLS } from './build-endpoints.ts';\nexport type ViceMeRegion = 'cn' | 'global';\n\nexport interface ViceMeConfig {\n /** Public opaque work key (`wrk_…`). Locates a Work; it is not a secret. */\n workKey: string;\n /** Routes public API and CDN traffic. */\n region: ViceMeRegion;\n /** Optional abort signal owned by the host page. */\n signal?: AbortSignal;\n}\n\nconst REGIONS: ReadonlySet<string> = new Set(['cn', 'global']);\n\n/**\n * Public API origins per region. These are the only production endpoints the\n * SDK may contact; B1 confirms final hostnames and any change happens here in\n * one place (never via a public `apiBaseUrl` option).\n */\nexport const PUBLIC_API_BASE_URLS: Readonly<Record<ViceMeRegion, string>> = {\n cn: BUILD_API_BASE_URLS.cn,\n global: BUILD_API_BASE_URLS.global,\n};\n\nexport function resolveApiBaseUrl(region: ViceMeRegion): string {\n return PUBLIC_API_BASE_URLS[region];\n}\n\nexport function isValidWorkKey(value: unknown): value is string {\n return typeof value === 'string' && /^wrk_[A-Za-z0-9_-]{4,124}$/.test(value);\n}\n\nexport function isValidRegion(value: unknown): value is ViceMeRegion {\n return typeof value === 'string' && REGIONS.has(value);\n}\n\n/**\n * Validate unknown input as a public client config. Throws a CONFIG_INVALID\n * ViceMeError that never echoes values back beyond the offending field name.\n */\nexport function validatePublicConfig(input: unknown): ViceMeConfig {\n if (typeof input !== 'object' || input === null) {\n throw configInvalid('createViceMe expects a configuration object.');\n }\n const raw = input as Record<string, unknown>;\n\n const known = new Set(['workKey', 'region', 'signal']);\n for (const key of Object.keys(raw)) {\n if (!known.has(key)) {\n throw configInvalid(`Unknown configuration field \"${key}\".`);\n }\n }\n if (!isValidWorkKey(raw.workKey)) {\n throw configInvalid('Configuration field \"workKey\" must be a public work key (\"wrk_…\").');\n }\n if (!isValidRegion(raw.region)) {\n throw configInvalid('Configuration field \"region\" must be \"cn\" or \"global\".');\n }\n if (raw.signal !== undefined && !(raw.signal instanceof AbortSignal)) {\n throw configInvalid('Configuration field \"signal\" must be an AbortSignal.');\n }\n return {\n workKey: raw.workKey,\n region: raw.region,\n signal: raw.signal,\n };\n}\n","/**\n * Client lifecycle state machine.\n *\n * ```text\n * CREATED -> INITIALIZING -> READY -> DESTROYED\n * INITIALIZING -> FAILED (retryable: FAILED -> INITIALIZING)\n * READY -> DEGRADED (single capability unavailable; host page keeps working)\n * DEGRADED -> READY (when all capabilities recover is a B1+ concern)\n * ```\n *\n * State is exposed read-only; consumers can never assign it directly.\n */\n\nimport { ViceMeError, clientDestroyed } from './errors.ts';\n\nexport type ViceMeClientState =\n 'CREATED' | 'INITIALIZING' | 'READY' | 'DEGRADED' | 'FAILED' | 'DESTROYED';\n\nconst ALLOWED_TRANSITIONS: Readonly<Record<ViceMeClientState, readonly ViceMeClientState[]>> = {\n CREATED: ['INITIALIZING', 'DESTROYED'],\n INITIALIZING: ['READY', 'FAILED', 'DESTROYED'],\n READY: ['DEGRADED', 'DESTROYED'],\n DEGRADED: ['DESTROYED'],\n FAILED: ['INITIALIZING', 'DESTROYED'],\n DESTROYED: [],\n};\n\nexport type LifecycleListener = (state: ViceMeClientState) => void;\n\nexport class Lifecycle {\n #state: ViceMeClientState = 'CREATED';\n #listeners = new Set<LifecycleListener>();\n\n get state(): ViceMeClientState {\n return this.#state;\n }\n\n get destroyed(): boolean {\n return this.#state === 'DESTROYED';\n }\n\n transition(next: ViceMeClientState): void {\n if (next === this.#state) return;\n if (!ALLOWED_TRANSITIONS[this.#state]!.includes(next)) {\n throw new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: `Illegal lifecycle transition ${this.#state} -> ${next}.`,\n retryable: false,\n });\n }\n this.#state = next;\n for (const listener of this.#listeners) listener(next);\n }\n\n /** Any operation on a destroyed client must fail closed with this guard. */\n assertAlive(): void {\n if (this.destroyed) throw clientDestroyed();\n }\n\n subscribe(listener: LifecycleListener): () => void {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n clearListeners(): void {\n this.#listeners.clear();\n }\n}\n","/**\n * Public visitor session.\n *\n * ```text\n * SDK + workKey + Origin -> POST /v1/public/v1/work-sessions\n * -> short-lived capability token -> public capability calls\n * ```\n *\n * The token lives in memory only (never localStorage/cookies), is bound to the\n * Work, Origin, capability set, and expiry by the server, and is dropped on\n * `destroy()`. `workKey` locates the Work — it is never an authorization\n * credential.\n */\n\nimport { ViceMeError } from '../core/errors.ts';\nimport type { Transport, TransportRequest, TransportResponse } from '../transport/transport.ts';\nimport type { components } from '../generated/public-contract.ts';\n\n/**\n * DTO shapes come from the generated public contract snapshot — the SDK never\n * hand-writes a second copy of the server DTOs. The runtime validator below\n * stays intentionally narrow (required fields of the current contract only).\n */\ntype WorkSessionDto = components['schemas']['WorkSession'];\nexport type CreateWorkSessionRequestDto = components['schemas']['CreateWorkSessionRequest'];\n\nexport interface WorkDescriptor {\n key: string;\n /** Capability names enabled for this work. */\n capabilities: string[];\n}\n\nexport interface WorkSessionSnapshot {\n work: WorkDescriptor;\n /** Opaque short-lived capability token; memory-only. */\n token?: string;\n /** Epoch milliseconds when the token expires, when provided by the server. */\n expiresAt?: number;\n user?: WorkUser;\n}\n\nexport interface WorkUser {\n subject: string;\n nickname: string | null;\n avatarUrl: string | null;\n}\n\nexport interface SessionManagerOptions {\n workKey: string;\n transport: Transport;\n signal?: AbortSignal;\n timeoutMs?: number;\n /** Injectable clock for tests. */\n now?: () => number;\n}\n\nfunction parseSessionResponse(body: unknown, workKey: string): WorkSessionSnapshot {\n if (typeof body !== 'object' || body === null) {\n throw malformedSessionResponse();\n }\n const raw = body as WorkSessionDto;\n const work = raw.work as { key?: unknown; capabilities?: unknown } | undefined;\n if (\n typeof work !== 'object' ||\n work === null ||\n typeof work.key !== 'string' ||\n !Array.isArray(work.capabilities) ||\n !work.capabilities.every((c) => typeof c === 'string')\n ) {\n throw malformedSessionResponse();\n }\n if (work.key !== workKey) {\n throw new ViceMeError({\n code: 'WORK_NOT_FOUND',\n message: 'Work-session response did not match the requested work key.',\n retryable: false,\n });\n }\n const snapshot: WorkSessionSnapshot = {\n work: {\n key: work.key,\n capabilities: work.capabilities as string[],\n },\n };\n // Unknown extra fields are allowed and ignored (forward compatibility).\n if (typeof raw.token === 'string') snapshot.token = raw.token;\n if (typeof raw.expiresAt === 'number') snapshot.expiresAt = raw.expiresAt;\n return snapshot;\n}\n\nfunction malformedSessionResponse(): ViceMeError {\n return new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Malformed work-session response.',\n retryable: true,\n });\n}\n\nexport class SessionManager {\n readonly #options: SessionManagerOptions;\n readonly #now: () => number;\n #snapshot: WorkSessionSnapshot | undefined;\n #pending: Promise<WorkSessionSnapshot> | undefined;\n\n constructor(options: SessionManagerOptions) {\n this.#options = options;\n this.#now = options.now ?? (() => Date.now());\n }\n\n get snapshot(): WorkSessionSnapshot | undefined {\n return this.#snapshot;\n }\n\n /** True when the cached snapshot's server-provided expiry has passed. */\n #isExpired(): boolean {\n const expiresAt = this.#snapshot?.expiresAt;\n return expiresAt !== undefined && expiresAt <= this.#now();\n }\n\n /**\n * Establish (or return the established) public session.\n *\n * A cached snapshot is reused only while it is unexpired; an expired\n * snapshot is dropped and re-authenticated. Concurrent callers share one\n * in-flight request (single flight).\n */\n establish(): Promise<WorkSessionSnapshot> {\n if (this.#snapshot) {\n if (!this.#isExpired()) return Promise.resolve(this.#snapshot);\n this.#snapshot = undefined;\n }\n this.#pending ??= this.#options.transport\n .request({\n method: 'POST',\n path: '/v1/public/v1/work-sessions',\n body: { workKey: this.#options.workKey } satisfies CreateWorkSessionRequestDto,\n signal: this.#options.signal,\n timeoutMs: this.#options.timeoutMs,\n })\n .then((response) => {\n const snapshot = parseSessionResponse(response.body, this.#options.workKey);\n this.#snapshot = snapshot;\n return snapshot;\n })\n .finally(() => {\n this.#pending = undefined;\n });\n return this.#pending;\n }\n\n async request(\n request: Omit<TransportRequest, 'authorization' | 'signal'>,\n ): Promise<TransportResponse> {\n const snapshot = await this.establish();\n if (!snapshot.token) throw malformedSessionResponse();\n return this.#options.transport.request({\n ...request,\n authorization: snapshot.token,\n signal: this.#options.signal,\n });\n }\n\n authenticate(input: { token: string; expiresAt: number; user: WorkUser }): void {\n if (!this.#snapshot) throw malformedSessionResponse();\n this.#snapshot = {\n ...this.#snapshot,\n token: input.token,\n expiresAt: input.expiresAt,\n user: input.user,\n };\n }\n\n async signOut(): Promise<void> {\n this.invalidate();\n await this.establish();\n }\n\n /** Drop the token; next `establish()` re-authenticates. */\n invalidate(): void {\n this.#snapshot = undefined;\n }\n\n /** Hard cleanup: forget the token and pending work. */\n destroy(): void {\n this.invalidate();\n this.#pending = undefined;\n }\n}\n","import type { FollowTarget } from './capabilities.ts';\n\nexport type AccessInteractionAction = 'SIGN_IN' | 'FOLLOW' | 'CHECKOUT';\n\nexport interface PhoneAuthInteraction {\n sendCode(phone: string): Promise<{\n expiresInSeconds: number;\n retryAfterSeconds: number;\n }>;\n signIn(phone: string, code: string): Promise<void>;\n}\n\nexport interface AccessInteraction {\n featureKey: string;\n reason: string;\n action: AccessInteractionAction;\n followTarget?: FollowTarget;\n phoneAuth?: PhoneAuthInteraction;\n perform(): Promise<AccessActionResult>;\n}\n\nexport interface AccessCompletedAction {\n type: 'completed';\n}\n\nexport interface AccessFrameAction {\n type: 'frame';\n url: string;\n completion: Promise<void>;\n cancel(): void;\n}\n\nexport type AccessActionResult = AccessCompletedAction | AccessFrameAction;\n\nexport type AccessPresentationResult = 'acted' | 'dismissed';\n\n/** Internal interaction seam used by the ViceMe layer and deterministic tests. */\nexport type AccessPresenter = (interaction: AccessInteraction) => Promise<AccessPresentationResult>;\n\nconst ELEMENT_NAME = 'viceme-access-layer';\n\ninterface AccessLayerElement extends HTMLElement {\n interaction: AccessInteraction;\n}\n\nfunction actionCopy(action: AccessInteractionAction): {\n title: string;\n description: string;\n label: string;\n} {\n switch (action) {\n case 'SIGN_IN':\n return {\n title: '登录后继续',\n description: '登录 ViceMe 后即可继续检查此功能权限。',\n label: '微信登录',\n };\n case 'FOLLOW':\n return {\n title: '',\n description: '',\n label: '关注',\n };\n case 'CHECKOUT':\n return {\n title: '购买后解锁',\n description: '完成支付后即可继续使用此功能。',\n label: '重新打开',\n };\n }\n}\n\nfunction ensureAccessLayerElement(): void {\n if (customElements.get(ELEMENT_NAME)) return;\n\n class ViceMeAccessLayerElement extends HTMLElement implements AccessLayerElement {\n interaction!: AccessInteraction;\n\n connectedCallback(): void {\n const copy = actionCopy(this.interaction.action);\n const shadow = this.attachShadow({ mode: 'open' });\n shadow.innerHTML = `\n <style>\n :host {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: grid;\n align-items: end;\n color: #18181b;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif;\n font-size: 16px;\n line-height: 1.5;\n }\n [data-viceme='backdrop'] {\n position: absolute;\n inset: 0;\n border: 0;\n border-radius: 0;\n background: rgb(0 0 0 / 56%);\n }\n [data-viceme='panel'] {\n position: relative;\n box-sizing: border-box;\n display: flex;\n width: 100%;\n max-height: min(78dvh, 36rem);\n flex-direction: column;\n overflow: auto;\n border-radius: 1.25rem 1.25rem 0 0;\n background: #ffffff;\n color: #18181b;\n padding: 1rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom));\n box-shadow: 0 -1rem 3rem rgb(0 0 0 / 18%);\n }\n [data-viceme='header'] {\n display: flex;\n align-items: center;\n }\n [data-viceme='title'] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 700;\n }\n [data-viceme='content'] { display: flex; min-height: 0; flex: 1; flex-direction: column; }\n [data-viceme='description'] { margin: 0.75rem 0 1.25rem; color: #71717a; line-height: 1.6; }\n [data-viceme='profile'] {\n display: none;\n margin: 0 0 1.25rem;\n border: 1px solid #e4e4e7;\n border-radius: 1rem;\n padding: 1.5rem;\n background: #ffffff;\n box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 6%);\n text-align: center;\n }\n [data-viceme='profile'][data-visible='true'] { display: block; }\n [data-viceme='avatar'] {\n display: block;\n width: 5.5rem;\n height: 5.5rem;\n margin: 0 auto 1rem;\n border-radius: 999px;\n object-fit: cover;\n background: #f4f4f5;\n }\n [data-viceme='avatar-fallback'] {\n display: grid;\n width: 5.5rem;\n height: 5.5rem;\n margin: 0 auto 1rem;\n place-items: center;\n border-radius: 999px;\n background: #f4f4f5;\n color: #18181b;\n font-size: 2rem;\n font-weight: 700;\n }\n [data-viceme='avatar'][hidden], [data-viceme='avatar-fallback'][hidden] { display: none; }\n [data-viceme='profile-name'] { margin: 0; font-size: 1.375rem; font-weight: 700; }\n [data-viceme='profile-description'] { margin: 0.25rem 0 0; color: #71717a; }\n [data-viceme='panel'][data-action='FOLLOW'] { min-height: 18rem; }\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='header'],\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='description'] { display: none; }\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='profile'][data-visible='true'] {\n display: flex;\n align-items: center;\n gap: 0.875rem;\n margin: 0;\n border: 0;\n padding: 0;\n background: transparent;\n box-shadow: none;\n text-align: left;\n }\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='avatar'],\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='avatar-fallback'] {\n width: 3.25rem;\n height: 3.25rem;\n margin: 0;\n flex: 0 0 3.25rem;\n font-size: 1.25rem;\n }\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='profile-name'] {\n font-size: 1.125rem;\n }\n [data-viceme='panel'][data-action='FOLLOW'] [data-viceme='profile-description'] {\n display: none;\n }\n [data-viceme='actions'] {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n margin-top: auto;\n padding-top: 0.5rem;\n }\n [data-viceme='phone-form'] {\n display: none;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 0.875rem;\n padding-top: 1rem;\n }\n [data-viceme='panel'][data-phone='true'] [data-viceme='description'],\n [data-viceme='panel'][data-phone='true'] [data-viceme='profile'],\n [data-viceme='panel'][data-phone='true'] > [data-viceme='content'] > [data-viceme='actions'] { display: none; }\n [data-viceme='panel'][data-phone='true'] [data-viceme='phone-form'] { display: flex; }\n [data-viceme='field'] { display: grid; gap: 0.375rem; }\n [data-viceme='field-label'] { color: #3f3f46; font-size: 0.875rem; font-weight: 600; }\n [data-viceme='input'] {\n box-sizing: border-box;\n width: 100%;\n min-height: 2.75rem;\n border: 1px solid #d4d4d8;\n border-radius: 0.75rem;\n padding: 0.625rem 0.75rem;\n background: #ffffff;\n color: #18181b;\n font: 400 1rem/1.5 -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif;\n }\n [data-viceme='input']:focus { border-color: #18181b; outline: 2px solid #18181b; outline-offset: 2px; }\n [data-viceme='code-row'] { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.625rem; }\n [data-viceme='send-code'] { min-width: 7.5rem; border: 1px solid #18181b; background: #ffffff; color: #18181b; }\n [data-viceme='phone-hint'] { margin: 0; color: #71717a; font-size: 0.75rem; }\n button {\n min-height: 2.75rem;\n border-radius: 0.75rem;\n padding: 0.625rem 1rem;\n font: 600 1rem/1.5 -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", sans-serif;\n cursor: pointer;\n }\n button:focus-visible, iframe:focus-visible { outline: 2px solid #18181b; outline-offset: 2px; }\n [data-viceme='action'] {\n width: min(11rem, 48%);\n border: 1px solid #18181b;\n background: #18181b;\n color: #ffffff;\n }\n [data-viceme='secondary-action'] {\n width: min(11rem, 48%);\n border: 1px solid #18181b;\n background: #ffffff;\n color: #18181b;\n }\n [data-viceme='secondary-action']:hover { background: #f4f4f5; }\n [data-viceme='action']:hover { background: #3f3f46; border-color: #3f3f46; }\n [data-viceme='actions'][data-single='true'] [data-viceme='action'] { width: 100%; }\n button:disabled { cursor: wait; opacity: 0.5; }\n button[hidden] { display: none; }\n [data-viceme='error'] { min-height: 1.25rem; margin: 0 0 0.75rem; color: #b91c1c; font-size: 0.875rem; }\n [data-viceme='frame'] {\n display: none;\n width: 100%;\n height: min(72dvh, 42rem);\n border: 0;\n border-radius: 0.75rem;\n background: #ffffff;\n }\n [data-viceme='panel'][data-frame='true'] { max-height: 92dvh; }\n [data-viceme='panel'][data-frame='true'] [data-viceme='content'] { display: none; }\n [data-viceme='panel'][data-frame='true'] [data-viceme='frame'] { display: block; margin-top: 0.75rem; }\n [data-viceme='panel'][data-action='SIGN_IN'][data-frame='true'] [data-viceme='frame'] {\n height: min(62dvh, 31rem);\n }\n @media (min-width: 48rem) {\n :host { place-items: center; padding: 1.5rem; }\n [data-viceme='panel'] {\n width: min(28rem, 100%);\n min-height: 22rem;\n border-radius: 1.25rem;\n padding: 1.25rem;\n box-shadow: 0 1.5rem 4rem rgb(0 0 0 / 24%);\n }\n [data-viceme='panel'][data-action='FOLLOW'] { min-height: 16rem; }\n [data-viceme='panel'][data-frame='true'] { width: min(52rem, 100%); }\n [data-viceme='panel'][data-action='SIGN_IN'][data-frame='true'] { width: min(30rem, 100%); }\n }\n @media (prefers-reduced-motion: no-preference) {\n [data-viceme='panel'] { animation: viceme-enter 160ms ease-out; }\n @keyframes viceme-enter { from { opacity: 0; transform: translateY(1rem); } }\n }\n </style>\n <button data-viceme=\"backdrop\" type=\"button\" tabindex=\"-1\" aria-label=\"关闭\"></button>\n <section data-viceme=\"panel\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"viceme-layer-title\">\n <div data-viceme=\"header\">\n <h2 data-viceme=\"title\" id=\"viceme-layer-title\"></h2>\n </div>\n <div data-viceme=\"content\">\n <p data-viceme=\"description\"></p>\n <section data-viceme=\"profile\" aria-label=\"关注对象\">\n <img data-viceme=\"avatar\" hidden />\n <span data-viceme=\"avatar-fallback\" aria-hidden=\"true\"></span>\n <p data-viceme=\"profile-name\"></p>\n <p data-viceme=\"profile-description\"></p>\n </section>\n <p data-viceme=\"error\" role=\"alert\" aria-live=\"polite\"></p>\n <div data-viceme=\"actions\">\n <button data-viceme=\"secondary-action\" data-viceme-cancel type=\"button\">取消</button>\n <button data-viceme=\"secondary-action\" data-viceme-phone-action type=\"button\">手机号登录</button>\n <button data-viceme=\"action\" type=\"button\"></button>\n </div>\n <form data-viceme=\"phone-form\">\n <label data-viceme=\"field\">\n <span data-viceme=\"field-label\">手机号</span>\n <input data-viceme=\"input\" data-viceme-phone type=\"tel\" inputmode=\"numeric\" autocomplete=\"tel\" maxlength=\"11\" placeholder=\"请输入中国大陆手机号\" />\n </label>\n <label data-viceme=\"field\">\n <span data-viceme=\"field-label\">验证码</span>\n <span data-viceme=\"code-row\">\n <input data-viceme=\"input\" data-viceme-code type=\"text\" inputmode=\"numeric\" autocomplete=\"one-time-code\" maxlength=\"6\" placeholder=\"6 位验证码\" />\n <button data-viceme=\"send-code\" type=\"button\">获取验证码</button>\n </span>\n </label>\n <p data-viceme=\"phone-hint\">未注册的手机号验证后将自动创建 ViceMe 账号。</p>\n <div data-viceme=\"actions\">\n <button data-viceme=\"secondary-action\" data-viceme-phone-back type=\"button\">返回</button>\n <button data-viceme=\"action\" data-viceme-phone-submit type=\"submit\">登录</button>\n </div>\n </form>\n </div>\n <iframe data-viceme=\"frame\" title=\"\" referrerpolicy=\"no-referrer\" allow=\"payment\"></iframe>\n </section>\n `;\n const panel = shadow.querySelector<HTMLElement>(\"[data-viceme='panel']\")!;\n panel.dataset.action = this.interaction.action;\n const title = shadow.querySelector<HTMLElement>(\"[data-viceme='title']\")!;\n const description = shadow.querySelector<HTMLElement>(\"[data-viceme='description']\")!;\n title.textContent = copy.title;\n description.textContent = copy.description;\n const action = shadow.querySelector<HTMLButtonElement>(\"[data-viceme='action']\")!;\n const mainActions = action.parentElement!;\n const cancelAction = shadow.querySelector<HTMLButtonElement>('[data-viceme-cancel]')!;\n const phoneAction = shadow.querySelector<HTMLButtonElement>('[data-viceme-phone-action]')!;\n const backdrop = shadow.querySelector<HTMLButtonElement>(\"[data-viceme='backdrop']\")!;\n const error = shadow.querySelector<HTMLElement>(\"[data-viceme='error']\")!;\n const frame = shadow.querySelector<HTMLIFrameElement>(\"[data-viceme='frame']\")!;\n const profile = shadow.querySelector<HTMLElement>(\"[data-viceme='profile']\")!;\n const avatar = shadow.querySelector<HTMLImageElement>(\"[data-viceme='avatar']\")!;\n const avatarFallback = shadow.querySelector<HTMLElement>(\"[data-viceme='avatar-fallback']\")!;\n const profileName = shadow.querySelector<HTMLElement>(\"[data-viceme='profile-name']\")!;\n const profileDescription = shadow.querySelector<HTMLElement>(\n \"[data-viceme='profile-description']\",\n )!;\n const phoneForm = shadow.querySelector<HTMLFormElement>(\"[data-viceme='phone-form']\")!;\n const phoneInput = shadow.querySelector<HTMLInputElement>('[data-viceme-phone]')!;\n const codeInput = shadow.querySelector<HTMLInputElement>('[data-viceme-code]')!;\n const sendCode = shadow.querySelector<HTMLButtonElement>(\"[data-viceme='send-code']\")!;\n const phoneBack = shadow.querySelector<HTMLButtonElement>('[data-viceme-phone-back]')!;\n const phoneSubmit = shadow.querySelector<HTMLButtonElement>('[data-viceme-phone-submit]')!;\n action.textContent = copy.label;\n action.hidden = this.interaction.action === 'CHECKOUT';\n cancelAction.hidden = this.interaction.action !== 'FOLLOW';\n phoneAction.hidden = !this.interaction.phoneAuth;\n mainActions.dataset.single = String(cancelAction.hidden && phoneAction.hidden);\n const idleActionLabel = copy.label;\n frame.title = copy.title;\n\n const target = this.interaction.followTarget;\n if (target) {\n panel.removeAttribute('aria-labelledby');\n panel.setAttribute('aria-label', `关注 ${target.displayName}`);\n profile.dataset.visible = 'true';\n profileName.textContent = target.displayName;\n profileDescription.textContent = '';\n avatarFallback.textContent = target.displayName.trim().slice(0, 1) || 'V';\n if (target.avatarUrl) {\n avatar.src = target.avatarUrl;\n avatar.alt = `${target.displayName}的头像`;\n avatar.hidden = false;\n avatarFallback.hidden = true;\n }\n }\n\n let activeFrame: AccessFrameAction | null = null;\n let countdownTimer: number | null = null;\n const clearCountdown = () => {\n if (countdownTimer !== null) window.clearInterval(countdownTimer);\n countdownTimer = null;\n };\n const close = (result: AccessPresentationResult) => {\n clearCountdown();\n this.dispatchEvent(new CustomEvent('viceme:access-layer-close', { detail: result }));\n };\n const dismissLayer = () => {\n activeFrame?.cancel();\n close('dismissed');\n };\n backdrop.addEventListener('click', dismissLayer);\n cancelAction.addEventListener('click', dismissLayer);\n this.addEventListener('keydown', (event) => {\n if (event.key === 'Escape') dismissLayer();\n if (event.key === 'Tab') {\n event.preventDefault();\n if (activeFrame) {\n frame.focus();\n return;\n }\n const focusable =\n panel.dataset.phone === 'true'\n ? [phoneInput, codeInput, sendCode, phoneBack, phoneSubmit]\n : [\n ...(cancelAction.hidden ? [] : [cancelAction]),\n ...(phoneAction.hidden ? [] : [phoneAction]),\n ...(action.hidden ? [] : [action]),\n ];\n const available = focusable.filter((element) => !element.disabled && !element.hidden);\n if (available.length === 0) return;\n const currentIndex = available.indexOf(\n shadow.activeElement as HTMLButtonElement | HTMLInputElement,\n );\n const direction = event.shiftKey ? -1 : 1;\n available[(currentIndex + direction + available.length) % available.length]?.focus();\n }\n });\n phoneInput.addEventListener('input', () => {\n phoneInput.value = phoneInput.value.replace(/\\D/g, '').slice(0, 11);\n });\n codeInput.addEventListener('input', () => {\n codeInput.value = codeInput.value.replace(/\\D/g, '').slice(0, 6);\n });\n phoneAction.addEventListener('click', () => {\n panel.dataset.phone = 'true';\n title.textContent = '手机号登录';\n error.textContent = '';\n phoneInput.focus();\n });\n phoneBack.addEventListener('click', () => {\n panel.dataset.phone = 'false';\n title.textContent = copy.title;\n error.textContent = '';\n phoneAction.focus();\n });\n sendCode.addEventListener('click', async () => {\n const phone = phoneInput.value;\n if (!/^1[3-9]\\d{9}$/.test(phone)) {\n error.textContent = '请输入正确的中国大陆手机号。';\n phoneInput.focus();\n return;\n }\n sendCode.disabled = true;\n sendCode.textContent = '发送中…';\n error.textContent = '';\n try {\n const result = await this.interaction.phoneAuth!.sendCode(phone);\n let remaining = result.retryAfterSeconds;\n sendCode.textContent = `${remaining} 秒后重试`;\n clearCountdown();\n countdownTimer = window.setInterval(() => {\n remaining -= 1;\n if (remaining <= 0) {\n clearCountdown();\n sendCode.disabled = false;\n sendCode.textContent = '重新获取';\n return;\n }\n sendCode.textContent = `${remaining} 秒后重试`;\n }, 1_000);\n codeInput.focus();\n } catch {\n sendCode.disabled = false;\n sendCode.textContent = '获取验证码';\n error.textContent = '验证码发送失败,请稍后重试。';\n }\n });\n phoneForm.addEventListener('submit', async (event) => {\n event.preventDefault();\n const phone = phoneInput.value;\n const code = codeInput.value;\n if (!/^1[3-9]\\d{9}$/.test(phone) || !/^\\d{6}$/.test(code)) {\n error.textContent = '请输入正确的手机号和 6 位验证码。';\n return;\n }\n phoneSubmit.disabled = true;\n phoneSubmit.textContent = '登录中…';\n error.textContent = '';\n try {\n await this.interaction.phoneAuth!.signIn(phone, code);\n close('acted');\n } catch {\n phoneSubmit.disabled = false;\n phoneSubmit.textContent = '登录';\n error.textContent = '手机号或验证码不正确,请重试。';\n }\n });\n const performAction = async () => {\n action.disabled = true;\n action.setAttribute('aria-busy', 'true');\n action.textContent = '正在打开…';\n error.textContent = '';\n try {\n const result = await this.interaction.perform();\n if (result.type === 'frame') {\n activeFrame = result;\n panel.dataset.frame = 'true';\n frame.src = result.url;\n frame.focus();\n await result.completion;\n }\n close('acted');\n } catch {\n activeFrame?.cancel();\n activeFrame = null;\n panel.dataset.frame = 'false';\n frame.removeAttribute('src');\n error.textContent = '操作未完成,请重试。';\n action.hidden = false;\n action.disabled = false;\n action.removeAttribute('aria-busy');\n action.textContent = idleActionLabel;\n action.focus();\n }\n };\n action.addEventListener('click', performAction);\n if (this.interaction.action === 'CHECKOUT') {\n queueMicrotask(() => void performAction());\n } else {\n queueMicrotask(() => action.focus());\n }\n }\n }\n\n customElements.define(ELEMENT_NAME, ViceMeAccessLayerElement);\n}\n\nexport const defaultAccessPresenter: AccessPresenter = async (interaction) => {\n if (typeof document === 'undefined' || typeof customElements === 'undefined') {\n return 'dismissed';\n }\n ensureAccessLayerElement();\n const element = document.createElement(ELEMENT_NAME) as AccessLayerElement;\n element.interaction = interaction;\n const previousOverflow = document.documentElement.style.overflow;\n const previousFocus =\n document.activeElement instanceof HTMLElement ? document.activeElement : null;\n document.documentElement.style.overflow = 'hidden';\n document.body.append(element);\n try {\n return await new Promise<AccessPresentationResult>((resolve) => {\n element.addEventListener(\n 'viceme:access-layer-close',\n (event) => resolve((event as CustomEvent<AccessPresentationResult>).detail),\n { once: true },\n );\n });\n } finally {\n element.remove();\n document.documentElement.style.overflow = previousOverflow;\n previousFocus?.focus();\n }\n};\n","import { ViceMeError } from './errors.ts';\nimport {\n defaultAccessPresenter,\n type AccessActionResult,\n type AccessFrameAction,\n type AccessInteractionAction,\n type AccessPresenter,\n} from './presentation.ts';\nimport type { SessionManager, WorkUser } from '../session/session.ts';\n\nexport interface AuthState {\n authenticated: boolean;\n user: WorkUser | null;\n}\n\nexport interface FollowState {\n following: boolean;\n followedAt: string | null;\n target: FollowTarget;\n}\n\nexport interface FollowTarget {\n kind: 'CREATOR' | 'USER';\n displayName: string;\n avatarUrl: string | null;\n description: string | null;\n}\n\nexport type AccessReason =\n | 'OWNER'\n | 'FOLLOWING'\n | 'PURCHASED'\n | 'AUTH_REQUIRED'\n | 'FOLLOW_REQUIRED'\n | 'PURCHASE_REQUIRED'\n | 'FEATURE_NOT_FOUND'\n | 'FEATURE_DISABLED'\n | 'POLICY_UNSUPPORTED';\n\nexport interface AccessDecision {\n allowed: boolean;\n reason: AccessReason;\n nextAction: 'SIGN_IN' | 'FOLLOW' | 'CHECKOUT' | null;\n}\n\nexport interface CheckoutOptions {\n locale?: 'zh-CN' | 'en-US';\n}\n\nexport interface CheckoutResult {\n checkoutUrl: string;\n alreadyOwned: boolean;\n}\n\nexport interface AuthCapability {\n getState(): Promise<AuthState>;\n signIn(): Promise<AuthState>;\n signOut(): Promise<void>;\n}\n\nexport interface FollowCapability {\n getState(): Promise<FollowState>;\n follow(): Promise<FollowState>;\n unfollow(): Promise<FollowState>;\n}\n\nexport interface AccessCapability {\n check(featureKey: string): Promise<AccessDecision>;\n checkMany(featureKeys: string[]): Promise<Record<string, AccessDecision>>;\n require(featureKey: string): Promise<AccessDecision>;\n refresh(): Promise<void>;\n}\n\nexport interface CheckoutCapability {\n open(options?: CheckoutOptions): Promise<CheckoutResult>;\n}\n\ninterface CapabilityDeps {\n session: SessionManager;\n workKey: string;\n presenter?: AccessPresenter;\n ready: () => Promise<void>;\n}\n\nfunction objectBody(value: unknown): Record<string, unknown> {\n if (typeof value !== 'object' || value === null) throw malformedResponse();\n return value as Record<string, unknown>;\n}\n\nfunction malformedResponse(): ViceMeError {\n return new ViceMeError({\n code: 'INTERNAL_ERROR',\n message: 'Malformed public API response.',\n retryable: true,\n });\n}\n\nfunction parseUser(value: unknown): WorkUser {\n const body = objectBody(value);\n if (\n typeof body.subject !== 'string' ||\n !(typeof body.nickname === 'string' || body.nickname === null) ||\n !(typeof body.avatarUrl === 'string' || body.avatarUrl === null)\n ) {\n throw malformedResponse();\n }\n return {\n subject: body.subject,\n nickname: body.nickname,\n avatarUrl: body.avatarUrl,\n };\n}\n\nfunction parseFollowState(value: unknown): FollowState {\n const body = objectBody(value);\n if (\n typeof body.following !== 'boolean' ||\n !(typeof body.followedAt === 'string' || body.followedAt === null)\n ) {\n throw malformedResponse();\n }\n const target = objectBody(body.target);\n if (\n !(target.kind === 'CREATOR' || target.kind === 'USER') ||\n typeof target.displayName !== 'string' ||\n !(typeof target.avatarUrl === 'string' || target.avatarUrl === null) ||\n !(typeof target.description === 'string' || target.description === null)\n ) {\n throw malformedResponse();\n }\n return {\n following: body.following,\n followedAt: body.followedAt,\n target: {\n kind: target.kind,\n displayName: target.displayName,\n avatarUrl: target.avatarUrl,\n description: target.description,\n },\n };\n}\n\nfunction parseDecision(value: unknown): AccessDecision {\n const body = objectBody(value);\n const reasons: ReadonlySet<string> = new Set([\n 'OWNER',\n 'FOLLOWING',\n 'PURCHASED',\n 'AUTH_REQUIRED',\n 'FOLLOW_REQUIRED',\n 'PURCHASE_REQUIRED',\n 'FEATURE_NOT_FOUND',\n 'FEATURE_DISABLED',\n 'POLICY_UNSUPPORTED',\n ]);\n const actions: ReadonlySet<unknown> = new Set([null, 'SIGN_IN', 'FOLLOW', 'CHECKOUT']);\n if (\n typeof body.allowed !== 'boolean' ||\n typeof body.reason !== 'string' ||\n !reasons.has(body.reason) ||\n !actions.has(body.nextAction)\n ) {\n throw malformedResponse();\n }\n return {\n allowed: body.allowed,\n reason: body.reason as AccessReason,\n nextAction: body.nextAction as AccessDecision['nextAction'],\n };\n}\n\nfunction parseOrigin(value: unknown): string {\n if (typeof value !== 'string') throw malformedResponse();\n try {\n const origin = new URL(value).origin;\n if (origin !== value) throw malformedResponse();\n return origin;\n } catch (error) {\n if (error instanceof ViceMeError) throw error;\n throw malformedResponse();\n }\n}\n\nfunction randomVerifier(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n return base64Url(bytes);\n}\n\nfunction base64Url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '');\n}\n\nasync function codeChallenge(verifier: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));\n return base64Url(new Uint8Array(digest));\n}\n\nfunction resolveWechatClientType(): 'h5' | 'pc' {\n if (typeof navigator === 'undefined') return 'pc';\n const userAgentData = (navigator as Navigator & { userAgentData?: { mobile?: boolean } })\n .userAgentData;\n const userAgent = navigator.userAgent;\n if (\n userAgentData?.mobile === true ||\n /Android|iPhone|iPad|iPod|Mobile|IEMobile|Opera Mini/i.test(userAgent) ||\n (/Macintosh/i.test(userAgent) && navigator.maxTouchPoints > 1)\n ) {\n return 'h5';\n }\n if (\n typeof window !== 'undefined' &&\n navigator.maxTouchPoints > 0 &&\n window.matchMedia('(pointer: coarse)').matches &&\n window.matchMedia('(max-width: 48rem)').matches\n ) {\n return 'h5';\n }\n return 'pc';\n}\n\nexport function createCapabilities(deps: CapabilityDeps): {\n auth: AuthCapability;\n follow: FollowCapability;\n access: AccessCapability;\n checkout: CheckoutCapability;\n} {\n const authenticate = async (code: string, codeVerifier: string): Promise<AuthState> => {\n const exchange = objectBody(\n (\n await deps.session.request({\n method: 'POST',\n path: '/v1/public/v1/auth/exchange',\n body: { code, codeVerifier },\n })\n ).body,\n );\n if (typeof exchange.token !== 'string' || typeof exchange.expiresAt !== 'number') {\n throw malformedResponse();\n }\n const user = parseUser(exchange.user);\n deps.session.authenticate({ token: exchange.token, expiresAt: exchange.expiresAt, user });\n return { authenticated: true, user };\n };\n\n const cancelled = () =>\n new ViceMeError({\n code: 'AUTH_CANCELLED',\n message: 'The interactive action was cancelled.',\n retryable: false,\n });\n\n const embeddedFrame = (\n url: string,\n completionOrigin: string,\n channel: string,\n type: 'auth' | 'checkout',\n complete: (data: Record<string, unknown>) => Promise<void>,\n ): AccessFrameAction => {\n if (typeof window === 'undefined') {\n throw new ViceMeError({\n code: 'CONFIG_INVALID',\n message: 'Interactive access requires a browser window.',\n retryable: false,\n });\n }\n let active = true;\n let settle!: () => void;\n let fail!: (error: unknown) => void;\n const cleanup = () => {\n if (!active) return;\n active = false;\n window.removeEventListener('message', receive);\n };\n const completion = new Promise<void>((resolve, reject) => {\n settle = resolve;\n fail = reject;\n });\n const receive = (event: MessageEvent) => {\n if (!active || event.origin !== completionOrigin) return;\n if (typeof event.data !== 'object' || event.data === null) return;\n const data = event.data as Record<string, unknown>;\n if (data.workKey !== deps.workKey || data.channel !== channel) return;\n if (data.type === `viceme:${type}:cancelled`) {\n cleanup();\n fail(cancelled());\n return;\n }\n if (data.type !== `viceme:${type}:complete`) return;\n cleanup();\n void complete(data).then(settle, fail);\n };\n window.addEventListener('message', receive);\n return {\n type: 'frame',\n url,\n completion,\n cancel() {\n cleanup();\n settle();\n },\n };\n };\n\n const startSignIn = async (): Promise<AccessActionResult> => {\n await deps.ready();\n const verifier = randomVerifier();\n const channel = randomVerifier();\n const response = await deps.session.request({\n method: 'POST',\n path: '/v1/public/v1/auth/wechat/authorize',\n body: {\n codeChallenge: await codeChallenge(verifier),\n channel,\n clientType: resolveWechatClientType(),\n },\n });\n const authorize = objectBody(response.body);\n if (typeof authorize.authorizationUrl !== 'string') throw malformedResponse();\n return embeddedFrame(\n authorize.authorizationUrl,\n parseOrigin(authorize.completionOrigin),\n channel,\n 'auth',\n async (data) => {\n if (typeof data.code !== 'string') throw malformedResponse();\n await authenticate(data.code, verifier);\n },\n );\n };\n\n const phoneAuth = {\n async sendCode(phone: string) {\n await deps.ready();\n const response = objectBody(\n (\n await deps.session.request({\n method: 'POST',\n path: '/v1/public/v1/auth/phone/verification-codes',\n body: { phone },\n })\n ).body,\n );\n if (\n typeof response.expiresInSeconds !== 'number' ||\n typeof response.retryAfterSeconds !== 'number'\n ) {\n throw malformedResponse();\n }\n return {\n expiresInSeconds: response.expiresInSeconds,\n retryAfterSeconds: response.retryAfterSeconds,\n };\n },\n async signIn(phone: string, code: string) {\n await deps.ready();\n const response = await deps.session.request({\n method: 'POST',\n path: '/v1/public/v1/auth/phone/login',\n body: { phone, code },\n });\n const exchange = objectBody(response.body);\n if (typeof exchange.token !== 'string' || typeof exchange.expiresAt !== 'number') {\n throw malformedResponse();\n }\n const user = parseUser(exchange.user);\n deps.session.authenticate({ token: exchange.token, expiresAt: exchange.expiresAt, user });\n },\n };\n\n const auth: AuthCapability = {\n async getState() {\n await deps.ready();\n const user = deps.session.snapshot?.user ?? null;\n return { authenticated: user !== null, user };\n },\n async signIn() {\n const presenter = deps.presenter ?? defaultAccessPresenter;\n const result = await presenter({\n featureKey: 'auth',\n reason: 'AUTH_REQUIRED',\n action: 'SIGN_IN',\n phoneAuth,\n perform: startSignIn,\n });\n if (result === 'dismissed') throw cancelled();\n return this.getState();\n },\n async signOut() {\n await deps.ready();\n await deps.session.signOut();\n },\n };\n\n const follow: FollowCapability = {\n async getState() {\n await deps.ready();\n return parseFollowState(\n (await deps.session.request({ method: 'GET', path: '/v1/public/v1/follow' })).body,\n );\n },\n async follow() {\n await deps.ready();\n return parseFollowState(\n (await deps.session.request({ method: 'PUT', path: '/v1/public/v1/follow' })).body,\n );\n },\n async unfollow() {\n await deps.ready();\n return parseFollowState(\n (await deps.session.request({ method: 'DELETE', path: '/v1/public/v1/follow' })).body,\n );\n },\n };\n\n const checkMany = async (featureKeys: string[]): Promise<Record<string, AccessDecision>> => {\n await deps.ready();\n const response = objectBody(\n (\n await deps.session.request({\n method: 'POST',\n path: '/v1/public/v1/access/check',\n body: { featureKeys },\n })\n ).body,\n );\n const raw = objectBody(response.decisions);\n return Object.fromEntries(\n Object.entries(raw).map(([key, value]) => [key, parseDecision(value)]),\n );\n };\n\n const startCheckout = async (\n options: CheckoutOptions = {},\n ): Promise<{ result: CheckoutResult; action: AccessActionResult }> => {\n await deps.ready();\n const channel = randomVerifier();\n const body = {\n locale: options.locale ?? 'zh-CN',\n channel,\n };\n const response = objectBody(\n (\n await deps.session.request({\n method: 'POST',\n path: '/v1/public/v1/checkout/sessions',\n body,\n })\n ).body,\n );\n if (typeof response.checkoutUrl !== 'string' || typeof response.alreadyOwned !== 'boolean') {\n throw malformedResponse();\n }\n const completionOrigin = parseOrigin(response.completionOrigin);\n const result = {\n checkoutUrl: response.checkoutUrl,\n alreadyOwned: response.alreadyOwned,\n };\n return {\n result,\n action: result.alreadyOwned\n ? { type: 'completed' }\n : embeddedFrame(result.checkoutUrl, completionOrigin, channel, 'checkout', async () => {}),\n };\n };\n\n const checkout: CheckoutCapability = {\n async open(options = {}) {\n const presenter = deps.presenter ?? defaultAccessPresenter;\n let checkoutResult: CheckoutResult | undefined;\n const presented = await presenter({\n featureKey: 'checkout',\n reason: 'PURCHASE_REQUIRED',\n action: 'CHECKOUT',\n perform: async () => {\n const prepared = await startCheckout(options);\n checkoutResult = prepared.result;\n return prepared.action;\n },\n });\n if (presented === 'dismissed' || !checkoutResult) throw cancelled();\n return checkoutResult;\n },\n };\n\n const access: AccessCapability = {\n async check(featureKey) {\n const decisions = await checkMany([featureKey]);\n const decision = decisions[featureKey];\n if (!decision) throw malformedResponse();\n return decision;\n },\n checkMany,\n async require(featureKey) {\n let decision = await this.check(featureKey);\n const presenter = deps.presenter ?? defaultAccessPresenter;\n for (\n let attempts = 0;\n !decision.allowed && decision.nextAction && attempts < 3;\n attempts += 1\n ) {\n const nextAction = decision.nextAction as AccessInteractionAction;\n const followTarget = nextAction === 'FOLLOW' ? (await follow.getState()).target : undefined;\n const result = await presenter({\n featureKey,\n reason: decision.reason,\n action: nextAction,\n ...(followTarget ? { followTarget } : {}),\n ...(nextAction === 'SIGN_IN' ? { phoneAuth } : {}),\n perform: async () => {\n if (nextAction === 'SIGN_IN') {\n return startSignIn();\n } else if (nextAction === 'FOLLOW') {\n await follow.follow();\n return { type: 'completed' };\n } else {\n return (await startCheckout()).action;\n }\n },\n });\n if (result === 'dismissed') return decision;\n decision = await this.check(featureKey);\n }\n return decision;\n },\n async refresh() {\n await deps.ready();\n },\n };\n\n return { auth, follow, access, checkout };\n}\n","/**\n * Headless ViceMe client.\n *\n * `ready()` and access checks remain headless. Interactive authentication and\n * checkout touch `window` only when the caller explicitly invokes them. `ready()` is\n * idempotent per instance (shares one promise), `destroy()` is idempotent and\n * synchronously cancels requests and subscriptions; every business method on a\n * destroyed client fails with `CLIENT_DESTROYED`.\n */\n\nimport { clientDestroyed } from './errors.ts';\nimport { Lifecycle, type ViceMeClientState } from './lifecycle.ts';\nimport type { ViceMeConfig, ViceMeRegion } from './config.ts';\nimport { SessionManager } from '../session/session.ts';\nimport type { Transport } from '../transport/transport.ts';\nimport { API_MAJOR, SDK_VERSION } from '../version.ts';\nimport {\n createCapabilities,\n type AccessCapability,\n type AuthCapability,\n type CheckoutCapability,\n} from './capabilities.ts';\nimport type { AccessPresenter } from './presentation.ts';\n\nexport interface ViceMeClient {\n readonly version: string;\n readonly workKey: string;\n readonly region: ViceMeRegion;\n readonly state: ViceMeClientState;\n readonly auth: AuthCapability;\n readonly access: AccessCapability;\n readonly checkout: CheckoutCapability;\n ready(): Promise<void>;\n hasCapability(name: string): boolean;\n destroy(): void;\n}\n\nexport interface ViceMeMountedInstance {\n readonly instanceKey: string;\n readonly capability: string;\n destroy(): void;\n}\n\n/** Marker so in-flight requests cancelled by `destroy()` map to CLIENT_DESTROYED. */\nclass DestroySignalReason extends DOMException {\n constructor() {\n super('ViceMe client destroyed.', 'AbortError');\n }\n}\n\nexport interface ViceMeClientDeps {\n config: ViceMeConfig;\n transport: Transport;\n /** Interaction override for the testing entry only. */\n presenter?: AccessPresenter;\n /** Injectable clock (testing only). */\n now?: () => number;\n}\n\nexport class ViceMeClientImpl implements ViceMeClient {\n readonly #lifecycle = new Lifecycle();\n readonly #session: SessionManager;\n readonly #config: ViceMeConfig;\n readonly #internalSignal = new AbortController();\n #readyPromise: Promise<void> | undefined;\n readonly auth: AuthCapability;\n readonly access: AccessCapability;\n readonly checkout: CheckoutCapability;\n\n constructor(deps: ViceMeClientDeps) {\n this.#config = deps.config;\n this.#session = new SessionManager({\n workKey: deps.config.workKey,\n transport: deps.transport,\n signal: this.#internalSignal.signal,\n ...(deps.now !== undefined ? { now: deps.now } : {}),\n });\n const capabilities = createCapabilities({\n session: this.#session,\n workKey: deps.config.workKey,\n presenter: deps.presenter,\n ready: () => this.ready(),\n });\n this.auth = capabilities.auth;\n this.access = capabilities.access;\n this.checkout = capabilities.checkout;\n const callerSignal = deps.config.signal;\n if (callerSignal) {\n // Propagate the caller's own abort reason when one was set.\n const abortInternal = () => {\n this.#internalSignal.abort(\n callerSignal.reason instanceof Error\n ? callerSignal.reason\n : new DOMException('Caller signal aborted.', 'AbortError'),\n );\n };\n // An already-aborted signal never fires the listener; check\n // synchronously so a pre-cancelled caller cannot issue session\n // requests or reach the network at all.\n if (callerSignal.aborted) abortInternal();\n else callerSignal.addEventListener('abort', abortInternal, { once: true });\n }\n }\n\n get version(): string {\n return SDK_VERSION;\n }\n\n get workKey(): string {\n return this.#config.workKey;\n }\n\n get region(): ViceMeRegion {\n return this.#config.region;\n }\n\n get state(): ViceMeClientState {\n return this.#lifecycle.state;\n }\n\n /** Internal: public API major, used by the loader registry namespace. */\n get apiMajor(): number {\n return API_MAJOR;\n }\n\n ready(): Promise<void> {\n if (this.#lifecycle.destroyed) return Promise.reject(clientDestroyed());\n this.#readyPromise ??= this.#initialize();\n return this.#readyPromise;\n }\n\n async #initialize(): Promise<void> {\n if (this.#lifecycle.destroyed) throw clientDestroyed();\n this.#lifecycle.transition('INITIALIZING');\n try {\n await this.#session.establish();\n if (this.#lifecycle.destroyed) throw clientDestroyed();\n this.#lifecycle.transition('READY');\n } catch (error) {\n // If the client was destroyed mid-flight, report CLIENT_DESTROYED and do\n // not attempt any further lifecycle transitions.\n if (this.#lifecycle.destroyed) throw clientDestroyed();\n this.#lifecycle.transition('FAILED');\n // Allow a later `ready()` retry instead of caching the failure forever.\n this.#readyPromise = undefined;\n this.#session.invalidate();\n throw error;\n }\n }\n\n hasCapability(name: string): boolean {\n if (this.#lifecycle.destroyed) return false;\n const capabilities = this.#session.snapshot?.work.capabilities;\n return capabilities !== undefined && capabilities.includes(name);\n }\n\n /** Names of capabilities enabled for this work (empty before `ready()`). */\n get capabilities(): readonly string[] {\n return this.#session.snapshot?.work.capabilities ?? [];\n }\n\n /**\n * Internal: mark one capability unavailable without taking down the client\n * (loader uses this when a feature chunk fails after the core is READY).\n */\n markDegraded(): void {\n if (this.#lifecycle.state === 'READY') this.#lifecycle.transition('DEGRADED');\n }\n\n /** Internal: session snapshot access for capability modules. */\n get sessionSnapshot() {\n return this.#session.snapshot;\n }\n\n destroy(): void {\n if (this.#lifecycle.destroyed) return;\n this.#lifecycle.transition('DESTROYED');\n this.#internalSignal.abort(new DestroySignalReason());\n this.#session.destroy();\n this.#lifecycle.clearListeners();\n this.#readyPromise = undefined;\n }\n}\n"],"names":["REGIONS","PUBLIC_API_BASE_URLS","BUILD_API_BASE_URLS","resolveApiBaseUrl","region","isValidWorkKey","value","isValidRegion","validatePublicConfig","input","configInvalid","raw","known","key","ALLOWED_TRANSITIONS","Lifecycle","#state","#listeners","next","ViceMeError","listener","clientDestroyed","parseSessionResponse","body","workKey","malformedSessionResponse","work","c","snapshot","SessionManager","#options","#now","#snapshot","#pending","options","#isExpired","expiresAt","response","request","ELEMENT_NAME","actionCopy","action","ensureAccessLayerElement","ViceMeAccessLayerElement","copy","shadow","panel","title","description","mainActions","cancelAction","phoneAction","backdrop","error","frame","profile","avatar","avatarFallback","profileName","profileDescription","phoneForm","phoneInput","codeInput","sendCode","phoneBack","phoneSubmit","idleActionLabel","target","activeFrame","countdownTimer","clearCountdown","close","result","dismissLayer","event","available","element","currentIndex","direction","phone","remaining","code","performAction","defaultAccessPresenter","interaction","previousOverflow","previousFocus","resolve","objectBody","malformedResponse","parseUser","parseFollowState","parseDecision","reasons","actions","parseOrigin","origin","randomVerifier","bytes","base64Url","binary","byte","codeChallenge","verifier","digest","resolveWechatClientType","userAgentData","userAgent","createCapabilities","deps","authenticate","codeVerifier","exchange","user","cancelled","embeddedFrame","url","completionOrigin","channel","type","complete","active","settle","fail","cleanup","receive","completion","reject","data","startSignIn","authorize","phoneAuth","auth","follow","checkMany","featureKeys","startCheckout","featureKey","decision","presenter","attempts","nextAction","followTarget","checkoutResult","prepared","DestroySignalReason","ViceMeClientImpl","#lifecycle","#session","#config","#internalSignal","#readyPromise","capabilities","callerSignal","abortInternal","SDK_VERSION","API_MAJOR","#initialize","name"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const r = {
|
|
2
|
+
cn: "https://viceme-shop-web-poc.preview.tencent-zeabur.cn/api",
|
|
3
|
+
global: "https://viceme-shop-web-poc.preview.tencent-zeabur.cn/api"
|
|
4
|
+
}, a = {
|
|
5
|
+
cn: "https://viceme-shop-web-poc.preview.tencent-zeabur.cn",
|
|
6
|
+
global: "https://viceme-shop-web-poc.preview.tencent-zeabur.cn"
|
|
7
|
+
}, c = /* @__PURE__ */ new Set([
|
|
8
|
+
"RATE_LIMITED",
|
|
9
|
+
"NETWORK_TIMEOUT",
|
|
10
|
+
"CHECKOUT_UNAVAILABLE",
|
|
11
|
+
"INTERNAL_ERROR"
|
|
12
|
+
]);
|
|
13
|
+
class s extends Error {
|
|
14
|
+
code;
|
|
15
|
+
retryable;
|
|
16
|
+
requestId;
|
|
17
|
+
capability;
|
|
18
|
+
constructor(e) {
|
|
19
|
+
super(e.message), this.name = "ViceMeError", this.code = e.code, this.retryable = e.retryable ?? c.has(e.code), this.requestId = e.requestId, this.capability = e.capability;
|
|
20
|
+
}
|
|
21
|
+
/** Safe, stable-shape serialization for logs and `viceme:error` events. */
|
|
22
|
+
toJSON() {
|
|
23
|
+
const e = { code: this.code, retryable: this.retryable };
|
|
24
|
+
return this.requestId !== void 0 && (e.requestId = this.requestId), this.capability !== void 0 && (e.capability = this.capability), e;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function o(t) {
|
|
28
|
+
return t instanceof s;
|
|
29
|
+
}
|
|
30
|
+
function i(t) {
|
|
31
|
+
return new s({ code: "CONFIG_INVALID", message: t, retryable: !1 });
|
|
32
|
+
}
|
|
33
|
+
function n() {
|
|
34
|
+
return new s({
|
|
35
|
+
code: "CLIENT_DESTROYED",
|
|
36
|
+
message: "ViceMe client has been destroyed.",
|
|
37
|
+
retryable: !1
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const p = "0.1.7-poc.1", b = 1;
|
|
41
|
+
export {
|
|
42
|
+
b as A,
|
|
43
|
+
a as B,
|
|
44
|
+
p as S,
|
|
45
|
+
s as V,
|
|
46
|
+
r as a,
|
|
47
|
+
n as b,
|
|
48
|
+
i as c,
|
|
49
|
+
o as i
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=version-mxCwx8AO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-mxCwx8AO.js","sources":["../../src/core/build-endpoints.ts","../../src/core/errors.ts","../../src/version.ts"],"sourcesContent":["declare const __VICEME_BUILD_CN_API_BASE_URL__: string | undefined;\ndeclare const __VICEME_BUILD_GLOBAL_API_BASE_URL__: string | undefined;\ndeclare const __VICEME_BUILD_CN_WIDGET_ORIGIN__: string | undefined;\ndeclare const __VICEME_BUILD_GLOBAL_WIDGET_ORIGIN__: string | undefined;\n\nexport const BUILD_API_BASE_URLS = {\n cn:\n typeof __VICEME_BUILD_CN_API_BASE_URL__ === 'string'\n ? __VICEME_BUILD_CN_API_BASE_URL__\n : 'https://api.viceme.cn',\n global:\n typeof __VICEME_BUILD_GLOBAL_API_BASE_URL__ === 'string'\n ? __VICEME_BUILD_GLOBAL_API_BASE_URL__\n : 'https://api.viceme.ai/v1',\n} as const;\n\nexport const BUILD_WIDGET_ORIGINS = {\n cn:\n typeof __VICEME_BUILD_CN_WIDGET_ORIGIN__ === 'string'\n ? __VICEME_BUILD_CN_WIDGET_ORIGIN__\n : 'https://viceme.cn',\n global:\n typeof __VICEME_BUILD_GLOBAL_WIDGET_ORIGIN__ === 'string'\n ? __VICEME_BUILD_GLOBAL_WIDGET_ORIGIN__\n : 'https://viceme.ai',\n} as const;\n","/**\n * Public error model.\n *\n * Consumers branch on the stable `code` only — never on `message` text.\n * Error payloads must never contain provider responses, tokens, cookies, or\n * internal stack traces; `toJSON()` exposes the safe diagnostic subset.\n */\n\nexport type ViceMeErrorCode =\n | 'CONFIG_INVALID'\n | 'WORK_NOT_FOUND'\n | 'CAPABILITY_DISABLED'\n | 'CLIENT_DESTROYED'\n | 'SESSION_EXPIRED'\n | 'AUTH_REQUIRED'\n | 'AUTH_CANCELLED'\n | 'RETURN_URL_NOT_ALLOWED'\n | 'RATE_LIMITED'\n | 'NETWORK_TIMEOUT'\n | 'CHECKOUT_UNAVAILABLE'\n | 'INTERNAL_ERROR';\n\nexport interface ViceMeErrorInit {\n code: ViceMeErrorCode;\n message: string;\n retryable?: boolean;\n /** Server-assigned request id echoed back for support correlation. */\n requestId?: string;\n /** Capability the error belongs to, when scoped to one. */\n capability?: string;\n}\n\nconst RETRYABLE_BY_DEFAULT: ReadonlySet<ViceMeErrorCode> = new Set([\n 'RATE_LIMITED',\n 'NETWORK_TIMEOUT',\n 'CHECKOUT_UNAVAILABLE',\n 'INTERNAL_ERROR',\n]);\n\nexport class ViceMeError extends Error {\n readonly code: ViceMeErrorCode;\n readonly retryable: boolean;\n readonly requestId?: string;\n readonly capability?: string;\n\n constructor(init: ViceMeErrorInit) {\n super(init.message);\n this.name = 'ViceMeError';\n this.code = init.code;\n this.retryable = init.retryable ?? RETRYABLE_BY_DEFAULT.has(init.code);\n this.requestId = init.requestId;\n this.capability = init.capability;\n }\n\n /** Safe, stable-shape serialization for logs and `viceme:error` events. */\n toJSON(): {\n code: ViceMeErrorCode;\n retryable: boolean;\n requestId?: string;\n capability?: string;\n } {\n const json: {\n code: ViceMeErrorCode;\n retryable: boolean;\n requestId?: string;\n capability?: string;\n } = { code: this.code, retryable: this.retryable };\n if (this.requestId !== undefined) json.requestId = this.requestId;\n if (this.capability !== undefined) json.capability = this.capability;\n return json;\n }\n}\n\nexport function isViceMeError(value: unknown): value is ViceMeError {\n return value instanceof ViceMeError;\n}\n\n/** Build a CONFIG_INVALID error with a stable, non-sensitive message. */\nexport function configInvalid(message: string): ViceMeError {\n return new ViceMeError({ code: 'CONFIG_INVALID', message, retryable: false });\n}\n\n/** Build a CLIENT_DESTROYED error for post-destroy calls. */\nexport function clientDestroyed(): ViceMeError {\n return new ViceMeError({\n code: 'CLIENT_DESTROYED',\n message: 'ViceMe client has been destroyed.',\n retryable: false,\n });\n}\n","/**\n * Single source of truth for the SDK runtime version.\n *\n * Kept in sync with `packages/sdk/package.json#version`; a unit test enforces\n * the match so the loader, release manifest, and npm metadata can never drift.\n */\nexport const SDK_VERSION = '0.1.7-poc.1';\n\n/** Public API major carried by this build (loader namespace `v1`). */\nexport const API_MAJOR = 1;\n"],"names":["BUILD_API_BASE_URLS","BUILD_WIDGET_ORIGINS","RETRYABLE_BY_DEFAULT","ViceMeError","init","json","isViceMeError","value","configInvalid","message","clientDestroyed","SDK_VERSION","API_MAJOR"],"mappings":"AAKO,MAAMA,IAAsB;AAAA,EACjC,IAEM;AAAA,EAEN,QAEM;AAER,GAEaC,IAAuB;AAAA,EAClC,IAEM;AAAA,EAEN,QAEM;AAER,GCOMC,wBAAyD,IAAI;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAMC,UAAoB,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAYC,GAAuB;AACjC,UAAMA,EAAK,OAAO,GAClB,KAAK,OAAO,eACZ,KAAK,OAAOA,EAAK,MACjB,KAAK,YAAYA,EAAK,aAAaF,EAAqB,IAAIE,EAAK,IAAI,GACrE,KAAK,YAAYA,EAAK,WACtB,KAAK,aAAaA,EAAK;AAAA,EACzB;AAAA;AAAA,EAGA,SAKE;AACA,UAAMC,IAKF,EAAE,MAAM,KAAK,MAAM,WAAW,KAAK,UAAA;AACvC,WAAI,KAAK,cAAc,WAAWA,EAAK,YAAY,KAAK,YACpD,KAAK,eAAe,WAAWA,EAAK,aAAa,KAAK,aACnDA;AAAA,EACT;AACF;AAEO,SAASC,EAAcC,GAAsC;AAClE,SAAOA,aAAiBJ;AAC1B;AAGO,SAASK,EAAcC,GAA8B;AAC1D,SAAO,IAAIN,EAAY,EAAE,MAAM,kBAAkB,SAAAM,GAAS,WAAW,IAAO;AAC9E;AAGO,SAASC,IAA+B;AAC7C,SAAO,IAAIP,EAAY;AAAA,IACrB,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,EAAA,CACZ;AACH;ACnFO,MAAMQ,IAAc,eAGdC,IAAY;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-endpoints.d.ts","sourceRoot":"","sources":["../../src/core/build-endpoints.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB;;;CAStB,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;CASvB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type AccessPresenter } from './presentation.ts';
|
|
2
|
+
import type { SessionManager, WorkUser } from '../session/session.ts';
|
|
3
|
+
export interface AuthState {
|
|
4
|
+
authenticated: boolean;
|
|
5
|
+
user: WorkUser | null;
|
|
6
|
+
}
|
|
7
|
+
export interface FollowState {
|
|
8
|
+
following: boolean;
|
|
9
|
+
followedAt: string | null;
|
|
10
|
+
target: FollowTarget;
|
|
11
|
+
}
|
|
12
|
+
export interface FollowTarget {
|
|
13
|
+
kind: 'CREATOR' | 'USER';
|
|
14
|
+
displayName: string;
|
|
15
|
+
avatarUrl: string | null;
|
|
16
|
+
description: string | null;
|
|
17
|
+
}
|
|
18
|
+
export type AccessReason = 'OWNER' | 'FOLLOWING' | 'PURCHASED' | 'AUTH_REQUIRED' | 'FOLLOW_REQUIRED' | 'PURCHASE_REQUIRED' | 'FEATURE_NOT_FOUND' | 'FEATURE_DISABLED' | 'POLICY_UNSUPPORTED';
|
|
19
|
+
export interface AccessDecision {
|
|
20
|
+
allowed: boolean;
|
|
21
|
+
reason: AccessReason;
|
|
22
|
+
nextAction: 'SIGN_IN' | 'FOLLOW' | 'CHECKOUT' | null;
|
|
23
|
+
}
|
|
24
|
+
export interface CheckoutOptions {
|
|
25
|
+
locale?: 'zh-CN' | 'en-US';
|
|
26
|
+
}
|
|
27
|
+
export interface CheckoutResult {
|
|
28
|
+
checkoutUrl: string;
|
|
29
|
+
alreadyOwned: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface AuthCapability {
|
|
32
|
+
getState(): Promise<AuthState>;
|
|
33
|
+
signIn(): Promise<AuthState>;
|
|
34
|
+
signOut(): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
export interface FollowCapability {
|
|
37
|
+
getState(): Promise<FollowState>;
|
|
38
|
+
follow(): Promise<FollowState>;
|
|
39
|
+
unfollow(): Promise<FollowState>;
|
|
40
|
+
}
|
|
41
|
+
export interface AccessCapability {
|
|
42
|
+
check(featureKey: string): Promise<AccessDecision>;
|
|
43
|
+
checkMany(featureKeys: string[]): Promise<Record<string, AccessDecision>>;
|
|
44
|
+
require(featureKey: string): Promise<AccessDecision>;
|
|
45
|
+
refresh(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export interface CheckoutCapability {
|
|
48
|
+
open(options?: CheckoutOptions): Promise<CheckoutResult>;
|
|
49
|
+
}
|
|
50
|
+
interface CapabilityDeps {
|
|
51
|
+
session: SessionManager;
|
|
52
|
+
workKey: string;
|
|
53
|
+
presenter?: AccessPresenter;
|
|
54
|
+
ready: () => Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
export declare function createCapabilities(deps: CapabilityDeps): {
|
|
57
|
+
auth: AuthCapability;
|
|
58
|
+
follow: FollowCapability;
|
|
59
|
+
access: AccessCapability;
|
|
60
|
+
checkout: CheckoutCapability;
|
|
61
|
+
};
|
|
62
|
+
export {};
|
|
63
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/core/capabilities.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,MAAM,YAAY,GACpB,OAAO,GACP,WAAW,GACX,WAAW,GACX,eAAe,GACf,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IACjC,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACnD,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAC1E,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACrD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC1D;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AA4ID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG;IACxD,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,kBAAkB,CAAC;CAC9B,CAiTA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless ViceMe client.
|
|
3
|
+
*
|
|
4
|
+
* `ready()` and access checks remain headless. Interactive authentication and
|
|
5
|
+
* checkout touch `window` only when the caller explicitly invokes them. `ready()` is
|
|
6
|
+
* idempotent per instance (shares one promise), `destroy()` is idempotent and
|
|
7
|
+
* synchronously cancels requests and subscriptions; every business method on a
|
|
8
|
+
* destroyed client fails with `CLIENT_DESTROYED`.
|
|
9
|
+
*/
|
|
10
|
+
import { type ViceMeClientState } from './lifecycle.ts';
|
|
11
|
+
import type { ViceMeConfig, ViceMeRegion } from './config.ts';
|
|
12
|
+
import type { Transport } from '../transport/transport.ts';
|
|
13
|
+
import { type AccessCapability, type AuthCapability, type CheckoutCapability } from './capabilities.ts';
|
|
14
|
+
import type { AccessPresenter } from './presentation.ts';
|
|
15
|
+
export interface ViceMeClient {
|
|
16
|
+
readonly version: string;
|
|
17
|
+
readonly workKey: string;
|
|
18
|
+
readonly region: ViceMeRegion;
|
|
19
|
+
readonly state: ViceMeClientState;
|
|
20
|
+
readonly auth: AuthCapability;
|
|
21
|
+
readonly access: AccessCapability;
|
|
22
|
+
readonly checkout: CheckoutCapability;
|
|
23
|
+
ready(): Promise<void>;
|
|
24
|
+
hasCapability(name: string): boolean;
|
|
25
|
+
destroy(): void;
|
|
26
|
+
}
|
|
27
|
+
export interface ViceMeMountedInstance {
|
|
28
|
+
readonly instanceKey: string;
|
|
29
|
+
readonly capability: string;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|
|
32
|
+
export interface ViceMeClientDeps {
|
|
33
|
+
config: ViceMeConfig;
|
|
34
|
+
transport: Transport;
|
|
35
|
+
/** Interaction override for the testing entry only. */
|
|
36
|
+
presenter?: AccessPresenter;
|
|
37
|
+
/** Injectable clock (testing only). */
|
|
38
|
+
now?: () => number;
|
|
39
|
+
}
|
|
40
|
+
export declare class ViceMeClientImpl implements ViceMeClient {
|
|
41
|
+
#private;
|
|
42
|
+
readonly auth: AuthCapability;
|
|
43
|
+
readonly access: AccessCapability;
|
|
44
|
+
readonly checkout: CheckoutCapability;
|
|
45
|
+
constructor(deps: ViceMeClientDeps);
|
|
46
|
+
get version(): string;
|
|
47
|
+
get workKey(): string;
|
|
48
|
+
get region(): ViceMeRegion;
|
|
49
|
+
get state(): ViceMeClientState;
|
|
50
|
+
/** Internal: public API major, used by the loader registry namespace. */
|
|
51
|
+
get apiMajor(): number;
|
|
52
|
+
ready(): Promise<void>;
|
|
53
|
+
hasCapability(name: string): boolean;
|
|
54
|
+
/** Names of capabilities enabled for this work (empty before `ready()`). */
|
|
55
|
+
get capabilities(): readonly string[];
|
|
56
|
+
/**
|
|
57
|
+
* Internal: mark one capability unavailable without taking down the client
|
|
58
|
+
* (loader uses this when a feature chunk fails after the core is READY).
|
|
59
|
+
*/
|
|
60
|
+
markDegraded(): void;
|
|
61
|
+
/** Internal: session snapshot access for capability modules. */
|
|
62
|
+
get sessionSnapshot(): import("../session/session.ts").WorkSessionSnapshot | undefined;
|
|
63
|
+
destroy(): void;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAa,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;CACjB;AASD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,uDAAuD;IACvD,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,gBAAiB,YAAW,YAAY;;IAMnD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;gBAE1B,IAAI,EAAE,gBAAgB;IAmClC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,IAAI,KAAK,IAAI,iBAAiB,CAE7B;IAED,yEAAyE;IACzE,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBtB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAMpC,4EAA4E;IAC5E,IAAI,YAAY,IAAI,SAAS,MAAM,EAAE,CAEpC;IAED;;;OAGG;IACH,YAAY,IAAI,IAAI;IAIpB,gEAAgE;IAChE,IAAI,eAAe,oEAElB;IAED,OAAO,IAAI,IAAI;CAQhB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public client configuration.
|
|
3
|
+
*
|
|
4
|
+
* Production `createViceMe()` accepts exactly `workKey`, `region`, and
|
|
5
|
+
* `signal`. Anything else (transport, clock, request ids, base URLs) is a
|
|
6
|
+
* testing-only concern and lives in `@viceme-ai/sdk/testing`, so Agents can
|
|
7
|
+
* never bake temporary or internal endpoints into user projects.
|
|
8
|
+
*/
|
|
9
|
+
export type ViceMeRegion = 'cn' | 'global';
|
|
10
|
+
export interface ViceMeConfig {
|
|
11
|
+
/** Public opaque work key (`wrk_…`). Locates a Work; it is not a secret. */
|
|
12
|
+
workKey: string;
|
|
13
|
+
/** Routes public API and CDN traffic. */
|
|
14
|
+
region: ViceMeRegion;
|
|
15
|
+
/** Optional abort signal owned by the host page. */
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Public API origins per region. These are the only production endpoints the
|
|
20
|
+
* SDK may contact; B1 confirms final hostnames and any change happens here in
|
|
21
|
+
* one place (never via a public `apiBaseUrl` option).
|
|
22
|
+
*/
|
|
23
|
+
export declare const PUBLIC_API_BASE_URLS: Readonly<Record<ViceMeRegion, string>>;
|
|
24
|
+
export declare function resolveApiBaseUrl(region: ViceMeRegion): string;
|
|
25
|
+
export declare function isValidWorkKey(value: unknown): value is string;
|
|
26
|
+
export declare function isValidRegion(value: unknown): value is ViceMeRegion;
|
|
27
|
+
/**
|
|
28
|
+
* Validate unknown input as a public client config. Throws a CONFIG_INVALID
|
|
29
|
+
* ViceMeError that never echoes values back beyond the offending field name.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validatePublicConfig(input: unknown): ViceMeConfig;
|
|
32
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,QAAQ,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB,oDAAoD;IACpD,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAID;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAGvE,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE9D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEnE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CA0BjE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public error model.
|
|
3
|
+
*
|
|
4
|
+
* Consumers branch on the stable `code` only — never on `message` text.
|
|
5
|
+
* Error payloads must never contain provider responses, tokens, cookies, or
|
|
6
|
+
* internal stack traces; `toJSON()` exposes the safe diagnostic subset.
|
|
7
|
+
*/
|
|
8
|
+
export type ViceMeErrorCode = 'CONFIG_INVALID' | 'WORK_NOT_FOUND' | 'CAPABILITY_DISABLED' | 'CLIENT_DESTROYED' | 'SESSION_EXPIRED' | 'AUTH_REQUIRED' | 'AUTH_CANCELLED' | 'RETURN_URL_NOT_ALLOWED' | 'RATE_LIMITED' | 'NETWORK_TIMEOUT' | 'CHECKOUT_UNAVAILABLE' | 'INTERNAL_ERROR';
|
|
9
|
+
export interface ViceMeErrorInit {
|
|
10
|
+
code: ViceMeErrorCode;
|
|
11
|
+
message: string;
|
|
12
|
+
retryable?: boolean;
|
|
13
|
+
/** Server-assigned request id echoed back for support correlation. */
|
|
14
|
+
requestId?: string;
|
|
15
|
+
/** Capability the error belongs to, when scoped to one. */
|
|
16
|
+
capability?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class ViceMeError extends Error {
|
|
19
|
+
readonly code: ViceMeErrorCode;
|
|
20
|
+
readonly retryable: boolean;
|
|
21
|
+
readonly requestId?: string;
|
|
22
|
+
readonly capability?: string;
|
|
23
|
+
constructor(init: ViceMeErrorInit);
|
|
24
|
+
/** Safe, stable-shape serialization for logs and `viceme:error` events. */
|
|
25
|
+
toJSON(): {
|
|
26
|
+
code: ViceMeErrorCode;
|
|
27
|
+
retryable: boolean;
|
|
28
|
+
requestId?: string;
|
|
29
|
+
capability?: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare function isViceMeError(value: unknown): value is ViceMeError;
|
|
33
|
+
/** Build a CONFIG_INVALID error with a stable, non-sensitive message. */
|
|
34
|
+
export declare function configInvalid(message: string): ViceMeError;
|
|
35
|
+
/** Build a CLIENT_DESTROYED error for post-destroy calls. */
|
|
36
|
+
export declare function clientDestroyed(): ViceMeError;
|
|
37
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,gBAAgB,GAChB,qBAAqB,GACrB,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,GACf,gBAAgB,GAChB,wBAAwB,GACxB,cAAc,GACd,iBAAiB,GACjB,sBAAsB,GACtB,gBAAgB,CAAC;AAErB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;gBAEjB,IAAI,EAAE,eAAe;IASjC,2EAA2E;IAC3E,MAAM,IAAI;QACR,IAAI,EAAE,eAAe,CAAC;QACtB,SAAS,EAAE,OAAO,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB;CAWF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAElE;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAE1D;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,IAAI,WAAW,CAM7C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client lifecycle state machine.
|
|
3
|
+
*
|
|
4
|
+
* ```text
|
|
5
|
+
* CREATED -> INITIALIZING -> READY -> DESTROYED
|
|
6
|
+
* INITIALIZING -> FAILED (retryable: FAILED -> INITIALIZING)
|
|
7
|
+
* READY -> DEGRADED (single capability unavailable; host page keeps working)
|
|
8
|
+
* DEGRADED -> READY (when all capabilities recover is a B1+ concern)
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* State is exposed read-only; consumers can never assign it directly.
|
|
12
|
+
*/
|
|
13
|
+
export type ViceMeClientState = 'CREATED' | 'INITIALIZING' | 'READY' | 'DEGRADED' | 'FAILED' | 'DESTROYED';
|
|
14
|
+
export type LifecycleListener = (state: ViceMeClientState) => void;
|
|
15
|
+
export declare class Lifecycle {
|
|
16
|
+
#private;
|
|
17
|
+
get state(): ViceMeClientState;
|
|
18
|
+
get destroyed(): boolean;
|
|
19
|
+
transition(next: ViceMeClientState): void;
|
|
20
|
+
/** Any operation on a destroyed client must fail closed with this guard. */
|
|
21
|
+
assertAlive(): void;
|
|
22
|
+
subscribe(listener: LifecycleListener): () => void;
|
|
23
|
+
clearListeners(): void;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/core/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,MAAM,iBAAiB,GAC3B,SAAS,GAAG,cAAc,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAW7E,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAEnE,qBAAa,SAAS;;IAIpB,IAAI,KAAK,IAAI,iBAAiB,CAE7B;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAazC,4EAA4E;IAC5E,WAAW,IAAI,IAAI;IAInB,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAOlD,cAAc,IAAI,IAAI;CAGvB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FollowTarget } from './capabilities.ts';
|
|
2
|
+
export type AccessInteractionAction = 'SIGN_IN' | 'FOLLOW' | 'CHECKOUT';
|
|
3
|
+
export interface PhoneAuthInteraction {
|
|
4
|
+
sendCode(phone: string): Promise<{
|
|
5
|
+
expiresInSeconds: number;
|
|
6
|
+
retryAfterSeconds: number;
|
|
7
|
+
}>;
|
|
8
|
+
signIn(phone: string, code: string): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export interface AccessInteraction {
|
|
11
|
+
featureKey: string;
|
|
12
|
+
reason: string;
|
|
13
|
+
action: AccessInteractionAction;
|
|
14
|
+
followTarget?: FollowTarget;
|
|
15
|
+
phoneAuth?: PhoneAuthInteraction;
|
|
16
|
+
perform(): Promise<AccessActionResult>;
|
|
17
|
+
}
|
|
18
|
+
export interface AccessCompletedAction {
|
|
19
|
+
type: 'completed';
|
|
20
|
+
}
|
|
21
|
+
export interface AccessFrameAction {
|
|
22
|
+
type: 'frame';
|
|
23
|
+
url: string;
|
|
24
|
+
completion: Promise<void>;
|
|
25
|
+
cancel(): void;
|
|
26
|
+
}
|
|
27
|
+
export type AccessActionResult = AccessCompletedAction | AccessFrameAction;
|
|
28
|
+
export type AccessPresentationResult = 'acted' | 'dismissed';
|
|
29
|
+
/** Internal interaction seam used by the ViceMe layer and deterministic tests. */
|
|
30
|
+
export type AccessPresenter = (interaction: AccessInteraction) => Promise<AccessPresentationResult>;
|
|
31
|
+
export declare const defaultAccessPresenter: AccessPresenter;
|
|
32
|
+
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../src/core/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAC/B,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,uBAAuB,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,GAAG,iBAAiB,CAAC;AAE3E,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,WAAW,CAAC;AAE7D,kFAAkF;AAClF,MAAM,MAAM,eAAe,GAAG,CAAC,WAAW,EAAE,iBAAiB,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAC;AAwepG,eAAO,MAAM,sBAAsB,EAAE,eAyBpC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface DanmakuPageAnchor {
|
|
2
|
+
/** Stable page-and-position key sent to the hosted danmaku runtime. */
|
|
3
|
+
anchorKey: string;
|
|
4
|
+
/** Human-readable 10% scroll bucket, useful for diagnostics. */
|
|
5
|
+
scrollBucket: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Build a stable page-position anchor without exposing the page URL.
|
|
9
|
+
*
|
|
10
|
+
* Canonical URLs and SPA hash routes participate in the local hash. Only the
|
|
11
|
+
* resulting opaque key leaves the host page.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readDanmakuPageAnchor(windowObject?: Window, documentObject?: Document): DanmakuPageAnchor;
|
|
14
|
+
//# sourceMappingURL=anchor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../src/danmaku/anchor.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,GAAE,MAAe,EAC7B,cAAc,GAAE,QAAmB,GAClC,iBAAiB,CAOnB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ViceMeClient } from '../core/client.ts';
|
|
2
|
+
import type { CapabilityMountHandle, CapabilityMountOptions } from '../loader/mount-handle.ts';
|
|
3
|
+
export { mount } from './mount.ts';
|
|
4
|
+
export { readDanmakuPageAnchor } from './anchor.ts';
|
|
5
|
+
export type { DanmakuPageAnchor } from './anchor.ts';
|
|
6
|
+
/** Explicit ESM/npm entry point; the CDN loader calls the same mount function. */
|
|
7
|
+
export declare function mountDanmaku(client: ViceMeClient, options: CapabilityMountOptions): Promise<CapabilityMountHandle>;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/danmaku/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAG/F,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,kFAAkF;AAClF,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAEhC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ViceMeClient } from '../core/client.ts';
|
|
2
|
+
import type { CapabilityMountHandle, CapabilityMountOptions } from '../loader/mount-handle.ts';
|
|
3
|
+
export declare function mount(client: ViceMeClient, options: CapabilityMountOptions): Promise<CapabilityMountHandle>;
|
|
4
|
+
//# sourceMappingURL=mount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/danmaku/mount.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAiB/F,wBAAsB,KAAK,CACzB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAyNhC"}
|