개요
Cordis는 시공간 조합성의 프로그래밍 패러다임을 도입한 메타 프레임워크입니다. 현재 활발히 개발 중이며, 플러그인 기반 아키텍처를 채택하여 Node.js에서 모듈화되고 확장 가능한 애플리케이션을 구축하는 데 사용됩니다.
README 미리보기
\n Cordis\n\n\nA Meta-Framework of Spatiotemporal Composability.\n\n**Cordis is under active development. The API is not yet stable and may change without notice.**\n\n- Paper: [_A Programming Paradigm for Spatiotemporal Composability_](https://github.com/cordiverse/paper)\n- Documentation: [cordis-primer](https://deepseek-harness.github.io/deepseek-harness/reference/cordis-primer)\n
FAQ (4)
문제 해결TypeScript exactOptionalPropertyTypes에서 "Type 'undefined' is not assignable to type 'Timeout'" 오류를 해결하는 방법
@cordisjs/plugin-include 1.0.4에서는 선택적 프로퍼티 타입에 undefined를 명시적으로 포함하세요. packages/include/src/index.ts에서 다음을:
private writeTask?: NodeJS.Timeout
다음과 같이 변경하세요:
private writeTask?: NodeJS.Timeout | undefined
이 변경은 타입에만 적용되며 런타임 동작은 변경되지 않습니다. undefined가 명시적으로 할당되는 다른 모든 선택적 프로퍼티에도 동일한 T | undefined 확장을 적용하세요. 업스트림 릴리스를 기다리는 사용자는 patch-package를 사용해 게시된 타입 선언을 패치할 수 있습니다.
문제 해결Cordis 플러그인이 Context가 dispose된 후에도 여전히 로드되고 dispose 이벤트가 트리거되지 않는 이유는 무엇인가요?
이것은 Cordis의 버그였습니다: 부모 컨텍스트가 dispose된 후 ctx.plugin()을 비동기적으로 호출하면 자식 플러그인이 여전히 설치될 수 있어, 그로 인한 부수 효과가 정리되지 않은 채 남을 수 있었습니다. 커밋 fc388fdbabb9642d3b5b1440573d96cda25604a3이 포함된 릴리스로 Cordis를 업그레이드하세요. 수정 이후에는 dispose된 컨텍스트에 등록된 플러그인이 활성화되지 않습니다. 임시 해결 방법으로, 비동기 플러그인 등록을 직접 가드하세요:
let disposed = false
ctx.on('dispose', () => {
disposed = true
})
setTimeout(() => {
if (disposed) return
ctx.plugin((ctx) => {
ctx.on('dispose', () => {
// cleanup
})
})
}, 100)문제 해결같은 include 목록에서 이전 패치가 삽입한 행을 Cordis 패치가 대상으로 할 때 "patch: entry not found" 오류를 어떻게 해결하나요?
이 문제는 @cordisjs/plugin-include가 패치를 적용하기 전에 entryMap을 한 번만 빌드하기 때문에 발생합니다. insert 패치로 추가된 행은 해당 맵에 추가되지 않으므로, 이후 패치에서 해당 ID를 확인할 수 없습니다. 해결 방법은 삽입 직후 삽입된 행을 인덱싱하는 PR #116(또는 이를 대체하는 journal 수정 사항)이 포함된 릴리스로 업그레이드하는 것입니다. 로더를 로컬에서 유지 관리하는 경우, 계속 진행하기 전에 insert 분기에서 buildMap(insert)를 호출하여 엔트리 맵에 병합하세요. 이때 재귀적인 그룹 엔트리도 포함해야 합니다. 임시 해결 방법: 삽입된 행에 최종 상태를 직접 지정합니다. 예: insert: [{ id: 'added', name: 'plugin-c', disabled: true }]. 또는 insert와 이후 수정을 두 개의 별도 include/patch 패스로 분할하여 맵이 그 사이에 다시 빌드되도록 합니다. 업데이트 명령: npm update @cordisjs/plugin-include.
문제 해결dispose()를 호출한 후에도 cordis fiber.state가 왜 계속 PENDING 또는 UNLOADING 상태로 남아 있나요?
이것은 cordis의 버그입니다: state는 _updateState()를 통해서만 재계산되는 캐시된 필드이며, _setEpoch() 내부의 조기 반환(early return)으로 인해 dispose 시점에 ACTIVE가 아니었던 모든 fiber에 대해 해당 갱신이 건너뛰어집니다. 이 문제는 정확히 두 가지 경우에 발생합니다: 필수 의존성이 제공되지 않아 PENDING 상태에 갇힌 fiber와, 로드 중 플러그인이 예외를 던진 fiber(UNLOADING에 갇힘). 해결 방법: (1) dispose 여부를 감지할 때 fiber.state 대신 fiber.uid === null을 확인하세요. uid는 dispose 시 null로 설정되며, 내부 _getState()는 이미 null uid를 FiberState.DISPOSED로 매핑합니다. (2) 또는 fiber.ts를 패치하여 dispose 이펙트가 마지막에 상태를 수렴하도록 하세요. while (this.inertia) { await this.inertia } 루프 다음에 this._updateState(() => {}) 호출 한 줄을 추가합니다. 이 변경을 적용하면 모든 경우가 DISPOSED로 수렴하고, dispose가 PENDING -> DISPOSED 내부/상태 이벤트를 올바르게 발생시키며, 전체 cordis 테스트 스위트(테스트 246개)가 통과합니다.