/** 밖에 사는 대상 하나 — 화면이 이름을 보이고 갈 곳을 정할 수 있게. */ export interface ExternalRef { id: string; /** 사람이 읽는 이름. 없으면 화면이 id 를 보인다(지어내지 않는다). */ name?: string; /** * 그 제품에서 이것을 열 수 있는 자리 — 없으면 화면이 링크를 만들지 않는다. * * 막다른 링크를 만들지 않는 것이 이 칸의 요점이다. 눌러서 아무 일도 안 일어나면 사람은 그것을 * 결함으로 읽는다. */ href?: string; /** 그 id 가 실제로 있나 — **없으면 없다고 말한다.** 답에서 빼지 않는다. */ missing?: boolean; } /** * 밖에서 이 대상을 가리키는 것들 — 들어오는 관계 한 묶음. * * `tense` 를 **제품이 선언한다**(계약의 `RelationTense`). 실적·상태 구간은 지난 일이고 정비 계획· * 지시는 앞의 일이다 — 「걸린 것이 열」이 두 뜻이 되는 자리이므로 묶음이 스스로 말해야 한다. */ export interface ExternalIncoming { /** 관계의 이름(i18n 키) — 계약의 `via` 와 같은 규칙. 제품은 자기 접두를 쓴다. */ via: string; /** 어디서 오나 — 사람이 읽는 축 이름이 아니라 그 제품의 축 키다. */ from: string; /** 언제의 일인가. 안 주면 「선언이 말하지 않았다」다 — `standing` 으로 바꾸지 않는다. */ tense?: 'past' | 'future' | 'standing'; ids: string[]; /** 전체 수 — `ids` 가 잘렸어도 몇인지 말한다. */ total: number; } /** * 한 external 대상을 푸는 제품 쪽 구현. * * 둘 다 선택이다. 이름만 대 줄 수 있는 제품과 들어오는 관계만 낼 수 있는 제품이 다 있다 — 하나만 * 꽂아도 그만큼은 답해진다. */ /** What the relation being resolved belongs to. Required — a resolver that answers without it answers for the wrong twin. */ export interface ExternalResolveContext { instanceId: string; } export interface ExternalResolver { /** 계약의 `target.entity` 와 **같은 낱말**. 다르면 아무 관계에도 안 붙는다. */ entity: string; /** * 이 id 들이 무엇인가 — **어느 트윈의 관계인지와 함께** 묻는다. * * 인스턴스를 넘기는 이유(2026-09-18): 밖의 id 는 도메인에서 유일하지 않다. 구역 id(`areaId`)는 * 공간 안에서만 유일하므로, 도메인만으로 찾으면 다른 공간의 같은 id 가 답이 되어 **남의 공간 이름**이 * 이 자리의 부모로 보인다. 부르는 쪽은 인스턴스를 알고 있다. */ resolve?(domainId: string, ids: readonly string[], context: ExternalResolveContext): Promise; /** 이 대상을 가리키는 것들. */ incoming?(domainId: string, instanceId: string, axis: string, itemId: string): Promise; } /** * 해소기를 꽂는다 — **부팅에서 한 번.** * * 같은 `entity` 를 두 번 꽂으면 뒤엣것이 이긴다. 그것이 개발 중 재적재의 정상 동작이고, 운영에서 * 일어나면 두 제품이 같은 대상을 자기 것이라 말하는 것이므로 **경고를 남긴다** — 조용히 덮으면 * 어느 쪽이 답하고 있는지 아무도 모른다. */ export declare function registerExternalResolver(r: ExternalResolver, warn?: (msg: string) => void): void; /** 지금 꽂혀 있는 것들 — 「무엇을 풀 수 있나」를 밖에서 잴 수 있게. */ export declare function externalResolverEntities(): string[]; /** 시험이 재기동을 넣을 수 있게. */ export declare function clearExternalResolvers(): void; /** * 그 id 들을 푼다 — **못 풀면 못 푼다고 말한다.** * * 해소기가 터져도 360 전체를 죽이지 않는다. 한 관계가 답을 못 하는 것과 화면이 안 뜨는 것은 다른 * 사고이고, 뒤엣것이 훨씬 나쁘다. */ export declare function resolveExternal(entity: string, domainId: string, ids: readonly string[], context: ExternalResolveContext, warn?: (msg: string) => void): Promise<{ refs?: ExternalRef[]; unresolved?: 'no-resolver' | 'failed'; }>; /** * 밖에서 이 대상을 가리키는 것들을 모은다. * * 꽂힌 것이 없으면 **빈 배열이지 오류가 아니다** — 밖에서 가리키는 것이 없는 대상이 정상이다. * 다만 「해소기가 없어서 모른다」와 「없다」는 다르므로, 그 구별은 `externalResolverEntities()` 로 * 밖에서 잰다. */ export declare function externalIncoming(domainId: string, instanceId: string, axis: string, itemId: string, warn?: (msg: string) => void): Promise;