@treenity/core 1.0.48 → 3.0.0
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/dist/chain.d.ts +20 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +59 -0
- package/dist/chain.js.map +1 -0
- package/dist/client/handle.d.ts +13 -0
- package/dist/client/handle.d.ts.map +1 -0
- package/dist/client/handle.js +46 -0
- package/dist/client/handle.js.map +1 -0
- package/dist/client/index.d.ts +21 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/trpc.d.ts +13 -0
- package/dist/client/trpc.d.ts.map +1 -0
- package/dist/client/trpc.js +78 -0
- package/dist/client/trpc.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -0
- package/dist/comp/handle.d.ts +14 -0
- package/dist/comp/handle.d.ts.map +1 -0
- package/dist/comp/handle.js +21 -0
- package/dist/comp/handle.js.map +1 -0
- package/dist/comp/index.d.ts +42 -0
- package/dist/comp/index.d.ts.map +1 -0
- package/dist/comp/index.js +126 -0
- package/dist/comp/index.js.map +1 -0
- package/dist/comp/needs.d.ts +26 -0
- package/dist/comp/needs.d.ts.map +1 -0
- package/dist/comp/needs.js +101 -0
- package/dist/comp/needs.js.map +1 -0
- package/dist/comp/validate.d.ts +13 -0
- package/dist/comp/validate.d.ts.map +1 -0
- package/dist/comp/validate.js +117 -0
- package/dist/comp/validate.js.map +1 -0
- package/dist/comp.d.ts +2 -0
- package/dist/comp.d.ts.map +1 -0
- package/dist/comp.js +2 -0
- package/dist/comp.js.map +1 -0
- package/dist/contexts/schema/index.d.ts +7 -0
- package/dist/contexts/schema/index.d.ts.map +1 -0
- package/dist/contexts/schema/index.js +2 -0
- package/dist/contexts/schema/index.js.map +1 -0
- package/dist/contexts/schema.d.ts +2 -0
- package/dist/contexts/schema.d.ts.map +1 -0
- package/dist/contexts/schema.js +2 -0
- package/dist/contexts/schema.js.map +1 -0
- package/dist/contexts/service/index.d.ts +31 -0
- package/dist/contexts/service/index.d.ts.map +1 -0
- package/dist/contexts/service/index.js +16 -0
- package/dist/contexts/service/index.js.map +1 -0
- package/dist/contexts/service.d.ts +1 -14
- package/dist/contexts/service.d.ts.map +1 -1
- package/dist/contexts/service.js +2 -0
- package/dist/contexts/service.js.map +1 -0
- package/dist/contexts/telegram/index.d.ts +19 -0
- package/dist/contexts/telegram/index.d.ts.map +1 -0
- package/dist/contexts/telegram/index.js +89 -0
- package/dist/contexts/telegram/index.js.map +1 -0
- package/dist/contexts/text/index.d.ts +7 -0
- package/dist/contexts/text/index.d.ts.map +1 -0
- package/dist/contexts/text/index.js +9 -0
- package/dist/contexts/text/index.js.map +1 -0
- package/dist/contexts/text.d.ts +2 -0
- package/dist/contexts/text.d.ts.map +1 -0
- package/dist/contexts/text.js +2 -0
- package/dist/contexts/text.js.map +1 -0
- package/dist/core/component.d.ts +41 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/component.js +105 -0
- package/dist/core/component.js.map +1 -0
- package/dist/core/context.d.ts +5 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +3 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +8 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/path.d.ts +7 -0
- package/dist/core/path.d.ts.map +1 -0
- package/dist/core/path.js +37 -0
- package/dist/core/path.js.map +1 -0
- package/dist/core/registry.d.ts +16 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +100 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core.d.ts +2 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +2 -0
- package/dist/core.js.map +1 -0
- package/dist/log.d.ts +8 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +31 -0
- package/dist/log.js.map +1 -0
- package/dist/mod/discover.d.ts +4 -0
- package/dist/mod/discover.d.ts.map +1 -0
- package/dist/mod/discover.js +103 -0
- package/dist/mod/discover.js.map +1 -0
- package/dist/mod/examples/ticker/seed.d.ts +3 -0
- package/dist/mod/examples/ticker/seed.d.ts.map +1 -0
- package/dist/mod/examples/ticker/seed.js +16 -0
- package/dist/mod/examples/ticker/seed.js.map +1 -0
- package/dist/mod/examples/ticker/service.d.ts +2 -0
- package/dist/mod/examples/ticker/service.d.ts.map +1 -0
- package/dist/mod/examples/ticker/service.js +18 -0
- package/dist/mod/examples/ticker/service.js.map +1 -0
- package/dist/mod/examples/ticker/types.d.ts +16 -0
- package/dist/mod/examples/ticker/types.d.ts.map +1 -0
- package/dist/mod/examples/ticker/types.js +20 -0
- package/dist/mod/examples/ticker/types.js.map +1 -0
- package/dist/mod/examples/ticker/view.d.ts +2 -0
- package/dist/mod/examples/ticker/view.d.ts.map +1 -0
- package/dist/mod/examples/ticker/view.js +10 -0
- package/dist/mod/examples/ticker/view.js.map +1 -0
- package/dist/mod/index.d.ts +11 -0
- package/dist/mod/index.d.ts.map +1 -0
- package/dist/mod/index.js +8 -0
- package/dist/mod/index.js.map +1 -0
- package/dist/mod/loader.d.ts +18 -0
- package/dist/mod/loader.d.ts.map +1 -0
- package/dist/mod/loader.js +154 -0
- package/dist/mod/loader.js.map +1 -0
- package/dist/mod/optimistic.d.ts +34 -0
- package/dist/mod/optimistic.d.ts.map +1 -0
- package/dist/mod/optimistic.js +176 -0
- package/dist/mod/optimistic.js.map +1 -0
- package/dist/mod/prefab.d.ts +18 -0
- package/dist/mod/prefab.d.ts.map +1 -0
- package/dist/mod/prefab.js +42 -0
- package/dist/mod/prefab.js.map +1 -0
- package/dist/mod/tracking.d.ts +8 -0
- package/dist/mod/tracking.d.ts.map +1 -0
- package/dist/mod/tracking.js +44 -0
- package/dist/mod/tracking.js.map +1 -0
- package/dist/mod/types.d.ts +31 -0
- package/dist/mod/types.d.ts.map +1 -0
- package/dist/mod/types.js +5 -0
- package/dist/mod/types.js.map +1 -0
- package/dist/mod.d.ts +2 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +2 -0
- package/dist/mod.js.map +1 -0
- package/dist/mods/autostart/server.d.ts +2 -0
- package/dist/mods/autostart/server.d.ts.map +1 -0
- package/dist/mods/autostart/server.js +2 -0
- package/dist/mods/autostart/server.js.map +1 -0
- package/dist/mods/autostart/service.d.ts +14 -0
- package/dist/mods/autostart/service.d.ts.map +1 -0
- package/dist/mods/autostart/service.js +88 -0
- package/dist/mods/autostart/service.js.map +1 -0
- package/dist/mods/llm/index.d.ts +13 -0
- package/dist/mods/llm/index.d.ts.map +1 -0
- package/dist/mods/llm/index.js +43 -0
- package/dist/mods/llm/index.js.map +1 -0
- package/dist/mods/llm/server.d.ts +2 -0
- package/dist/mods/llm/server.d.ts.map +1 -0
- package/dist/mods/llm/server.js +2 -0
- package/dist/mods/llm/server.js.map +1 -0
- package/dist/mods/mcp/server.d.ts +3 -0
- package/dist/mods/mcp/server.d.ts.map +1 -0
- package/dist/mods/mcp/server.js +3 -0
- package/dist/mods/mcp/server.js.map +1 -0
- package/dist/mods/mcp/service.d.ts +2 -0
- package/dist/mods/mcp/service.d.ts.map +1 -0
- package/dist/mods/mcp/service.js +17 -0
- package/dist/mods/mcp/service.js.map +1 -0
- package/dist/mods/mcp/types.d.ts +5 -0
- package/dist/mods/mcp/types.d.ts.map +1 -0
- package/dist/mods/mcp/types.js +7 -0
- package/dist/mods/mcp/types.js.map +1 -0
- package/dist/mods/treenity/agent-port.d.ts +2 -0
- package/dist/mods/treenity/agent-port.d.ts.map +1 -0
- package/dist/mods/treenity/agent-port.js +76 -0
- package/dist/mods/treenity/agent-port.js.map +1 -0
- package/dist/mods/treenity/groups.d.ts +2 -0
- package/dist/mods/treenity/groups.d.ts.map +1 -0
- package/dist/mods/treenity/groups.js +18 -0
- package/dist/mods/treenity/groups.js.map +1 -0
- package/dist/mods/treenity/mod-type.d.ts +2 -0
- package/dist/mods/treenity/mod-type.d.ts.map +1 -0
- package/dist/mods/treenity/mod-type.js +9 -0
- package/dist/mods/treenity/mod-type.js.map +1 -0
- package/dist/mods/treenity/seed.d.ts +2 -0
- package/dist/mods/treenity/seed.d.ts.map +1 -0
- package/dist/mods/treenity/seed.js +53 -0
- package/dist/mods/treenity/seed.js.map +1 -0
- package/dist/mods/treenity/server.d.ts +5 -0
- package/dist/mods/treenity/server.d.ts.map +1 -0
- package/dist/mods/treenity/server.js +5 -0
- package/dist/mods/treenity/server.js.map +1 -0
- package/dist/mods/treenity/system.d.ts +36 -0
- package/dist/mods/treenity/system.d.ts.map +1 -0
- package/dist/mods/treenity/system.js +61 -0
- package/dist/mods/treenity/system.js.map +1 -0
- package/dist/mods/uix/client.d.ts +3 -0
- package/dist/mods/uix/client.d.ts.map +1 -0
- package/dist/mods/uix/client.js +96 -0
- package/dist/mods/uix/client.js.map +1 -0
- package/dist/mods/uix/compile.d.ts +7 -0
- package/dist/mods/uix/compile.d.ts.map +1 -0
- package/dist/mods/uix/compile.js +94 -0
- package/dist/mods/uix/compile.js.map +1 -0
- package/dist/mods/uix/jsx-parser.d.ts +2 -0
- package/dist/mods/uix/jsx-parser.d.ts.map +1 -0
- package/dist/mods/uix/jsx-parser.js +565 -0
- package/dist/mods/uix/jsx-parser.js.map +1 -0
- package/dist/mods/uix/verify.d.ts +7 -0
- package/dist/mods/uix/verify.d.ts.map +1 -0
- package/dist/mods/uix/verify.js +59 -0
- package/dist/mods/uix/verify.js.map +1 -0
- package/dist/schema/catalog.d.ts +23 -0
- package/dist/schema/catalog.d.ts.map +1 -0
- package/dist/schema/catalog.js +82 -0
- package/dist/schema/catalog.js.map +1 -0
- package/dist/schema/extract-schemas.d.ts +5 -0
- package/dist/schema/extract-schemas.d.ts.map +1 -0
- package/dist/schema/extract-schemas.js +444 -0
- package/dist/schema/extract-schemas.js.map +1 -0
- package/dist/schema/load.d.ts +2 -0
- package/dist/schema/load.d.ts.map +1 -0
- package/dist/schema/load.js +23 -0
- package/dist/schema/load.js.map +1 -0
- package/dist/schema/test-fixture.types.d.ts +2 -0
- package/dist/schema/test-fixture.types.d.ts.map +1 -0
- package/dist/schema/test-fixture.types.js +19 -0
- package/dist/schema/test-fixture.types.js.map +1 -0
- package/dist/schema/test-opaque.d.ts +3 -0
- package/dist/schema/test-opaque.d.ts.map +1 -0
- package/dist/schema/test-opaque.js +43 -0
- package/dist/schema/test-opaque.js.map +1 -0
- package/dist/schema/types.d.ts +37 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +3 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/server/actions.d.ts +35 -0
- package/dist/server/actions.d.ts.map +1 -0
- package/dist/server/actions.js +170 -0
- package/dist/server/actions.js.map +1 -0
- package/dist/server/agent.d.ts +6 -0
- package/dist/server/agent.d.ts.map +1 -0
- package/dist/server/agent.js +15 -0
- package/dist/server/agent.js.map +1 -0
- package/dist/server/auth.d.ts +39 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +335 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/client.d.ts +183 -0
- package/dist/server/client.d.ts.map +1 -0
- package/dist/server/client.js +22 -0
- package/dist/server/client.js.map +1 -0
- package/dist/server/cookies.d.ts +5 -0
- package/dist/server/cookies.d.ts.map +1 -0
- package/dist/server/cookies.js +24 -0
- package/dist/server/cookies.js.map +1 -0
- package/dist/server/doc-index.d.ts +38 -0
- package/dist/server/doc-index.d.ts.map +1 -0
- package/dist/server/doc-index.js +244 -0
- package/dist/server/doc-index.js.map +1 -0
- package/dist/server/errors.d.ts +7 -0
- package/dist/server/errors.d.ts.map +1 -0
- package/dist/server/errors.js +11 -0
- package/dist/server/errors.js.map +1 -0
- package/dist/server/factory.d.ts +23 -0
- package/dist/server/factory.d.ts.map +1 -0
- package/dist/server/factory.js +70 -0
- package/dist/server/factory.js.map +1 -0
- package/dist/server/main.d.ts +6 -0
- package/dist/server/main.d.ts.map +1 -0
- package/dist/server/main.js +45 -0
- package/dist/server/main.js.map +1 -0
- package/dist/server/mcp.d.ts +5 -0
- package/dist/server/mcp.d.ts.map +1 -0
- package/dist/server/mcp.js +280 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/server/migrate.d.ts +3 -0
- package/dist/server/migrate.d.ts.map +1 -0
- package/dist/server/migrate.js +56 -0
- package/dist/server/migrate.js.map +1 -0
- package/dist/server/mod-catalog.d.ts +14 -0
- package/dist/server/mod-catalog.d.ts.map +1 -0
- package/dist/server/mod-catalog.js +40 -0
- package/dist/server/mod-catalog.js.map +1 -0
- package/dist/server/mods-mount.d.ts +4 -0
- package/dist/server/mods-mount.d.ts.map +1 -0
- package/dist/server/mods-mount.js +169 -0
- package/dist/server/mods-mount.js.map +1 -0
- package/dist/server/mount-adapters.d.ts +9 -0
- package/dist/server/mount-adapters.d.ts.map +1 -0
- package/dist/server/mount-adapters.js +75 -0
- package/dist/server/mount-adapters.js.map +1 -0
- package/dist/server/mount.d.ts +3 -0
- package/dist/server/mount.d.ts.map +1 -0
- package/dist/server/mount.js +195 -0
- package/dist/server/mount.js.map +1 -0
- package/dist/server/prefab.d.ts +18 -0
- package/dist/server/prefab.d.ts.map +1 -0
- package/dist/server/prefab.js +70 -0
- package/dist/server/prefab.js.map +1 -0
- package/dist/server/seed/index.d.ts +6 -0
- package/dist/server/seed/index.d.ts.map +1 -0
- package/dist/server/seed/index.js +16 -0
- package/dist/server/seed/index.js.map +1 -0
- package/dist/server/server.d.ts +28 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +117 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/sub.d.ts +34 -0
- package/dist/server/sub.d.ts.map +1 -0
- package/dist/server/sub.js +174 -0
- package/dist/server/sub.js.map +1 -0
- package/dist/server/trpc.d.ts +192 -0
- package/dist/server/trpc.d.ts.map +1 -0
- package/dist/server/trpc.js +319 -0
- package/dist/server/trpc.js.map +1 -0
- package/dist/server/types-mount.d.ts +3 -0
- package/dist/server/types-mount.d.ts.map +1 -0
- package/dist/server/types-mount.js +144 -0
- package/dist/server/types-mount.js.map +1 -0
- package/dist/server/validate.d.ts +3 -0
- package/dist/server/validate.d.ts.map +1 -0
- package/dist/server/validate.js +20 -0
- package/dist/server/validate.js.map +1 -0
- package/dist/server/volatile.d.ts +11 -0
- package/dist/server/volatile.d.ts.map +1 -0
- package/dist/server/volatile.js +26 -0
- package/dist/server/volatile.js.map +1 -0
- package/dist/server/watch.d.ts +23 -0
- package/dist/server/watch.d.ts.map +1 -0
- package/dist/server/watch.js +178 -0
- package/dist/server/watch.js.map +1 -0
- package/dist/tree/cache.d.ts +3 -0
- package/dist/tree/cache.d.ts.map +1 -0
- package/dist/tree/cache.js +48 -0
- package/dist/tree/cache.js.map +1 -0
- package/dist/tree/fs.d.ts +3 -0
- package/dist/tree/fs.d.ts.map +1 -0
- package/dist/tree/fs.js +274 -0
- package/dist/tree/fs.js.map +1 -0
- package/dist/tree/index.d.ts +38 -0
- package/dist/tree/index.d.ts.map +1 -0
- package/dist/tree/index.js +182 -0
- package/dist/tree/index.js.map +1 -0
- package/dist/tree/inflight.d.ts +2 -0
- package/dist/tree/inflight.d.ts.map +1 -0
- package/dist/tree/inflight.js +15 -0
- package/dist/tree/inflight.js.map +1 -0
- package/dist/tree/json-codec.d.ts +2 -0
- package/dist/tree/json-codec.d.ts.map +1 -0
- package/dist/tree/json-codec.js +13 -0
- package/dist/tree/json-codec.js.map +1 -0
- package/dist/tree/mimefs.d.ts +13 -0
- package/dist/tree/mimefs.d.ts.map +1 -0
- package/dist/tree/mimefs.js +124 -0
- package/dist/tree/mimefs.js.map +1 -0
- package/dist/tree/mongo.d.ts +5 -0
- package/dist/tree/mongo.d.ts.map +1 -0
- package/dist/tree/mongo.js +110 -0
- package/dist/tree/mongo.js.map +1 -0
- package/dist/tree/patch.d.ts +30 -0
- package/dist/tree/patch.d.ts.map +1 -0
- package/dist/tree/patch.js +112 -0
- package/dist/tree/patch.js.map +1 -0
- package/dist/tree/query.d.ts +12 -0
- package/dist/tree/query.d.ts.map +1 -0
- package/dist/tree/query.js +61 -0
- package/dist/tree/query.js.map +1 -0
- package/dist/tree/repath.d.ts +3 -0
- package/dist/tree/repath.d.ts.map +1 -0
- package/dist/tree/repath.js +38 -0
- package/dist/tree/repath.js.map +1 -0
- package/dist/tree-chain.d.ts +18 -0
- package/dist/tree-chain.d.ts.map +1 -0
- package/dist/tree-chain.js +109 -0
- package/dist/tree-chain.js.map +1 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +2 -0
- package/dist/tree.js.map +1 -0
- package/dist/uri.d.ts +11 -0
- package/dist/uri.d.ts.map +1 -0
- package/dist/uri.js +79 -0
- package/dist/uri.js.map +1 -0
- package/package.json +39 -40
- package/src/chain.test.ts +190 -0
- package/src/chain.ts +82 -0
- package/src/client/client.test.ts +192 -0
- package/src/client/handle.ts +53 -0
- package/src/client/index.ts +18 -0
- package/src/client/trpc.ts +91 -0
- package/src/client.ts +1 -0
- package/src/comp/CLAUDE.md +14 -0
- package/src/comp/handle.ts +36 -0
- package/src/comp/index.test.ts +129 -0
- package/src/comp/index.ts +175 -0
- package/src/comp/needs.test.ts +499 -0
- package/src/comp/needs.ts +113 -0
- package/src/comp/validate.test.ts +304 -0
- package/src/comp/validate.ts +125 -0
- package/src/comp.ts +1 -0
- package/src/contexts/schema/index.ts +7 -0
- package/src/contexts/schema.ts +1 -0
- package/src/contexts/service/index.test.ts +323 -0
- package/src/contexts/service/index.ts +43 -0
- package/src/contexts/service.ts +1 -0
- package/src/contexts/telegram/index.ts +115 -0
- package/src/contexts/text/index.test.ts +31 -0
- package/src/contexts/text/index.ts +18 -0
- package/src/contexts/text.ts +1 -0
- package/src/core/component.ts +151 -0
- package/src/core/context.ts +14 -0
- package/src/core/index.test.ts +203 -0
- package/src/core/index.ts +9 -0
- package/src/core/path.ts +35 -0
- package/src/core/registry.ts +115 -0
- package/src/core.ts +1 -0
- package/src/log.test.ts +70 -0
- package/src/log.ts +28 -0
- package/src/mod/discover.test.ts +133 -0
- package/src/mod/discover.ts +100 -0
- package/src/mod/docs/00-index.md +19 -0
- package/src/mod/docs/01-primitives.md +38 -0
- package/src/mod/docs/02-core-api.md +68 -0
- package/src/mod/docs/03-registry.md +30 -0
- package/src/mod/docs/04-store.md +62 -0
- package/src/mod/docs/05-comp.md +111 -0
- package/src/mod/docs/06-actions.md +193 -0
- package/src/mod/docs/07-realtime.md +100 -0
- package/src/mod/docs/08-services.md +33 -0
- package/src/mod/docs/09-mounts.md +43 -0
- package/src/mod/docs/10-acl.md +60 -0
- package/src/mod/docs/11-server.md +62 -0
- package/src/mod/docs/12-conventions.md +65 -0
- package/src/mod/docs/13-example.md +132 -0
- package/src/mod/docs/14-mod-format.md +304 -0
- package/src/mod/docs/15-documenting-types.md +156 -0
- package/src/mod/examples/ticker/seed.ts +19 -0
- package/src/mod/examples/ticker/service.ts +20 -0
- package/src/mod/examples/ticker/ticker.test.ts +18 -0
- package/src/mod/examples/ticker/types.ts +22 -0
- package/src/mod/examples/ticker/view.tsx +19 -0
- package/src/mod/index.ts +12 -0
- package/src/mod/loader.test.ts +168 -0
- package/src/mod/loader.ts +174 -0
- package/src/mod/optimistic.test.ts +446 -0
- package/src/mod/optimistic.ts +210 -0
- package/src/mod/prefab.ts +62 -0
- package/src/mod/tracking.test.ts +59 -0
- package/src/mod/tracking.ts +51 -0
- package/src/mod/types.ts +40 -0
- package/src/mod.ts +1 -0
- package/src/mods/autostart/CLAUDE.md +6 -0
- package/src/mods/autostart/autostart.test.ts +85 -0
- package/src/mods/autostart/server.ts +1 -0
- package/src/mods/autostart/service.ts +98 -0
- package/src/mods/llm/CLAUDE.md +6 -0
- package/src/mods/llm/index.ts +57 -0
- package/src/mods/llm/llm.test.ts +109 -0
- package/src/mods/llm/server.ts +1 -0
- package/src/mods/mcp/CLAUDE.md +6 -0
- package/src/mods/mcp/server.ts +2 -0
- package/src/mods/mcp/service.ts +19 -0
- package/src/mods/mcp/types.ts +7 -0
- package/src/mods/treenity/agent-port.ts +93 -0
- package/src/mods/treenity/groups.ts +19 -0
- package/src/mods/treenity/mod-type.ts +10 -0
- package/src/mods/treenity/seed.ts +56 -0
- package/src/mods/treenity/server.ts +4 -0
- package/src/mods/treenity/system.ts +70 -0
- package/src/mods/uix/CLAUDE.md +7 -0
- package/src/mods/uix/client.ts +117 -0
- package/src/mods/uix/compile.test.ts +228 -0
- package/src/mods/uix/compile.ts +110 -0
- package/src/mods/uix/jsx-parser.test.ts +554 -0
- package/src/mods/uix/jsx-parser.ts +489 -0
- package/src/mods/uix/lazy-load.test.ts +261 -0
- package/src/mods/uix/uix-repomix.md +3509 -0
- package/src/mods/uix/verify.ts +68 -0
- package/src/schema/CLAUDE.md +13 -0
- package/src/schema/catalog.ts +101 -0
- package/src/schema/extract-schemas.test.ts +84 -0
- package/src/schema/extract-schemas.ts +462 -0
- package/src/schema/generated/autostart.json +44 -0
- package/src/schema/generated/board.column.json +25 -0
- package/src/schema/generated/board.task.json +147 -0
- package/src/schema/generated/brahman.action.back.json +12 -0
- package/src/schema/generated/brahman.action.broadcast.json +31 -0
- package/src/schema/generated/brahman.action.call.json +57 -0
- package/src/schema/generated/brahman.action.emittext.json +23 -0
- package/src/schema/generated/brahman.action.eval.json +23 -0
- package/src/schema/generated/brahman.action.file.json +28 -0
- package/src/schema/generated/brahman.action.forward.json +29 -0
- package/src/schema/generated/brahman.action.getvalue.json +28 -0
- package/src/schema/generated/brahman.action.ifelse.json +42 -0
- package/src/schema/generated/brahman.action.keywordselect.json +46 -0
- package/src/schema/generated/brahman.action.message.json +127 -0
- package/src/schema/generated/brahman.action.onerror.json +29 -0
- package/src/schema/generated/brahman.action.page.json +22 -0
- package/src/schema/generated/brahman.action.params.json +36 -0
- package/src/schema/generated/brahman.action.question.json +43 -0
- package/src/schema/generated/brahman.action.remove.json +12 -0
- package/src/schema/generated/brahman.action.resethistory.json +12 -0
- package/src/schema/generated/brahman.action.resetsession.json +12 -0
- package/src/schema/generated/brahman.action.selectlang.json +20 -0
- package/src/schema/generated/brahman.action.setvalue.json +27 -0
- package/src/schema/generated/brahman.action.tag.json +27 -0
- package/src/schema/generated/brahman.bot.json +68 -0
- package/src/schema/generated/brahman.page.json +25 -0
- package/src/schema/generated/brahman.session.json +29 -0
- package/src/schema/generated/brahman.user.json +58 -0
- package/src/schema/generated/cafe.contact.json +56 -0
- package/src/schema/generated/cafe.mail.json +29 -0
- package/src/schema/generated/default.json +15 -0
- package/src/schema/generated/doc.page.json +23 -0
- package/src/schema/generated/examples.demo.generator.json +16 -0
- package/src/schema/generated/examples.demo.sensor.json +35 -0
- package/src/schema/generated/groups.json +20 -0
- package/src/schema/generated/launcher.json +91 -0
- package/src/schema/generated/mcp.server.json +15 -0
- package/src/schema/generated/mindmap.map.json +22 -0
- package/src/schema/generated/sim.agent.json +24 -0
- package/src/schema/generated/sim.ai.json +24 -0
- package/src/schema/generated/sim.config.json +38 -0
- package/src/schema/generated/sim.descriptive.json +26 -0
- package/src/schema/generated/sim.events.json +47 -0
- package/src/schema/generated/sim.item.json +20 -0
- package/src/schema/generated/sim.memory.json +17 -0
- package/src/schema/generated/sim.nearby.json +17 -0
- package/src/schema/generated/sim.position.json +25 -0
- package/src/schema/generated/sim.round.json +64 -0
- package/src/schema/generated/sim.world.json +32 -0
- package/src/schema/generated/t.agent.port.json +74 -0
- package/src/schema/generated/t.llm.json +20 -0
- package/src/schema/generated/t.mod.json +27 -0
- package/src/schema/generated/t3d.animator.json +46 -0
- package/src/schema/generated/t3d.audio.json +58 -0
- package/src/schema/generated/t3d.camera.json +50 -0
- package/src/schema/generated/t3d.collider.json +84 -0
- package/src/schema/generated/t3d.light.json +90 -0
- package/src/schema/generated/t3d.line.json +47 -0
- package/src/schema/generated/t3d.lod.json +28 -0
- package/src/schema/generated/t3d.material.json +131 -0
- package/src/schema/generated/t3d.mesh.json +65 -0
- package/src/schema/generated/t3d.object.json +64 -0
- package/src/schema/generated/t3d.particles.json +109 -0
- package/src/schema/generated/t3d.rigidbody.json +81 -0
- package/src/schema/generated/t3d.scene.json +7 -0
- package/src/schema/generated/t3d.script.json +23 -0
- package/src/schema/generated/t3d.text.json +86 -0
- package/src/schema/generated/t3d.trail.json +45 -0
- package/src/schema/generated/task.json +96 -0
- package/src/schema/generated/test.fixture.json +43 -0
- package/src/schema/generated/ticker.config.json +43 -0
- package/src/schema/generated/ticker.price.json +20 -0
- package/src/schema/generated/todo.item.json +25 -0
- package/src/schema/generated/todo.list.json +33 -0
- package/src/schema/generated/treenity.system.json +259 -0
- package/src/schema/generated/whisper.audio.json +25 -0
- package/src/schema/generated/whisper.checklist.json +17 -0
- package/src/schema/generated/whisper.config.json +30 -0
- package/src/schema/generated/whisper.inbox.json +24 -0
- package/src/schema/generated/whisper.meta.json +35 -0
- package/src/schema/generated/whisper.text.json +16 -0
- package/src/schema/load.ts +24 -0
- package/src/schema/schema.test.ts +86 -0
- package/src/schema/test-fixture.types.ts +21 -0
- package/src/schema/test-opaque.ts +42 -0
- package/src/schema/types.ts +33 -0
- package/src/server/CLAUDE.md +26 -0
- package/src/server/actions.test.ts +272 -0
- package/src/server/actions.ts +274 -0
- package/src/server/agent-sub.test.ts +90 -0
- package/src/server/agent.test.ts +305 -0
- package/src/server/agent.ts +17 -0
- package/src/server/api.test.ts +454 -0
- package/src/server/auth.test.ts +441 -0
- package/src/server/auth.ts +386 -0
- package/src/server/client.ts +24 -0
- package/src/server/conditions.test.ts +128 -0
- package/src/server/cookies.ts +25 -0
- package/src/server/coverage.test.ts +827 -0
- package/src/server/doc-index.ts +286 -0
- package/src/server/e2e.test.ts +966 -0
- package/src/server/errors.ts +11 -0
- package/src/server/factory.ts +99 -0
- package/src/server/main.ts +56 -0
- package/src/server/mcp.ts +326 -0
- package/src/server/migrate.test.ts +123 -0
- package/src/server/migrate.ts +62 -0
- package/src/server/mod-catalog.ts +59 -0
- package/src/server/mods-mount.ts +179 -0
- package/src/server/mount-adapters.ts +82 -0
- package/src/server/mount.parametrized.test.ts +52 -0
- package/src/server/mount.query.test.ts +127 -0
- package/src/server/mount.test.ts +497 -0
- package/src/server/mount.ts +208 -0
- package/src/server/prefab.test.ts +415 -0
- package/src/server/prefab.ts +104 -0
- package/src/server/seed/index.ts +24 -0
- package/src/server/server.ts +153 -0
- package/src/server/stress.test.ts +844 -0
- package/src/server/sub.test.ts +55 -0
- package/src/server/sub.ts +224 -0
- package/src/server/trpc.ts +369 -0
- package/src/server/types-mount.ts +142 -0
- package/src/server/validate.test.ts +91 -0
- package/src/server/validate.ts +22 -0
- package/src/server/volatile.test.ts +140 -0
- package/src/server/volatile.ts +32 -0
- package/src/server/watch.test.ts +594 -0
- package/src/server/watch.ts +202 -0
- package/src/server/workflow.test.ts +82 -0
- package/src/tree/CLAUDE.md +13 -0
- package/src/tree/cache.test.ts +213 -0
- package/src/tree/cache.ts +51 -0
- package/src/tree/fs.test.ts +247 -0
- package/src/tree/fs.ts +251 -0
- package/src/tree/index.test.ts +164 -0
- package/src/tree/index.ts +216 -0
- package/src/tree/inflight.ts +15 -0
- package/src/tree/json-codec.ts +16 -0
- package/src/tree/mimefs.test.ts +289 -0
- package/src/tree/mimefs.ts +142 -0
- package/src/tree/mongo.ts +125 -0
- package/src/tree/patch.test.ts +192 -0
- package/src/tree/patch.ts +133 -0
- package/src/tree/query.test.ts +110 -0
- package/src/tree/query.ts +70 -0
- package/src/tree/repath.test.ts +86 -0
- package/src/tree/repath.ts +53 -0
- package/src/tree-chain.test.ts +723 -0
- package/src/tree-chain.ts +144 -0
- package/src/tree.ts +1 -0
- package/src/uri.test.ts +86 -0
- package/src/uri.ts +82 -0
- package/CHANGELOG.md +0 -314
- package/README.md +0 -18
- package/dist/context.d.ts +0 -41
- package/dist/context.d.ts.map +0 -1
- package/dist/context.mjs +0 -81
- package/dist/context.mjs.map +0 -1
- package/dist/contexts/node-engine.d.ts +0 -12
- package/dist/contexts/node-engine.d.ts.map +0 -1
- package/dist/contexts/node-engine.mjs +0 -7
- package/dist/contexts/node-engine.mjs.map +0 -1
- package/dist/contexts/noflo/types.d.ts +0 -20
- package/dist/contexts/noflo/types.d.ts.map +0 -1
- package/dist/contexts/object.d.ts +0 -11
- package/dist/contexts/object.d.ts.map +0 -1
- package/dist/contexts/object.mjs +0 -15
- package/dist/contexts/object.mjs.map +0 -1
- package/dist/contexts/proto.d.ts +0 -11
- package/dist/contexts/proto.d.ts.map +0 -1
- package/dist/contexts/proto.mjs +0 -7
- package/dist/contexts/proto.mjs.map +0 -1
- package/dist/contexts/react-context.d.ts +0 -21
- package/dist/contexts/react-context.d.ts.map +0 -1
- package/dist/contexts/react-context.mjs +0 -24
- package/dist/contexts/react-context.mjs.map +0 -1
- package/dist/contexts/service.mjs +0 -7
- package/dist/contexts/service.mjs.map +0 -1
- package/dist/get-type-cache.d.ts +0 -2
- package/dist/get-type-cache.d.ts.map +0 -1
- package/dist/get-type-cache.mjs +0 -7
- package/dist/get-type-cache.mjs.map +0 -1
- package/dist/index.d.ts +0 -13
- package/dist/index.d.ts.map +0 -1
- package/dist/index.mjs +0 -10
- package/dist/index.mjs.map +0 -1
- package/dist/link/link.d.ts +0 -25
- package/dist/link/link.d.ts.map +0 -1
- package/dist/link/link.mjs +0 -72
- package/dist/link/link.mjs.map +0 -1
- package/dist/link/link.test.d.ts +0 -2
- package/dist/link/link.test.d.ts.map +0 -1
- package/dist/loading.d.ts +0 -9
- package/dist/loading.d.ts.map +0 -1
- package/dist/meta-type.d.ts +0 -58
- package/dist/meta-type.d.ts.map +0 -1
- package/dist/meta-type.mjs +0 -104
- package/dist/meta-type.mjs.map +0 -1
- package/dist/meta.d.ts +0 -20
- package/dist/meta.d.ts.map +0 -1
- package/dist/meta.mjs +0 -16
- package/dist/meta.mjs.map +0 -1
- package/dist/node/index.d.ts +0 -2
- package/dist/node/index.d.ts.map +0 -1
- package/dist/node/types.d.ts +0 -37
- package/dist/node/types.d.ts.map +0 -1
- package/dist/test/context.test.d.ts +0 -2
- package/dist/test/context.test.d.ts.map +0 -1
- package/dist/types.d.ts +0 -14
- package/dist/types.d.ts.map +0 -1
- package/dist/types.mjs +0 -16
- package/dist/types.mjs.map +0 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import { chain, refVal, runPathWithRefs, TypedRef } from './chain';
|
|
4
|
+
|
|
5
|
+
// ── basic ──
|
|
6
|
+
|
|
7
|
+
test('sync field', async () => {
|
|
8
|
+
assert.equal(await chain({ name: 'Alice' }).name, 'Alice')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('sync method', async () => {
|
|
12
|
+
assert.equal(await chain({ greet: (n: string) => `hello ${n}` }).greet('Bob'), 'hello Bob')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('async field', async () => {
|
|
16
|
+
assert.equal(await chain({ fetch: async () => 42 }).fetch(), 42)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('deep sync chain', async () => {
|
|
20
|
+
const obj = { user: { profile: { name: 'Alice' } } }
|
|
21
|
+
assert.equal(await chain(obj).user.profile.name, 'Alice')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('deep async chain', async () => {
|
|
25
|
+
const obj = {
|
|
26
|
+
user: async (id: string) => ({
|
|
27
|
+
id,
|
|
28
|
+
posts: async () => [{ title: 'Hello' }, { title: 'World' }],
|
|
29
|
+
}),
|
|
30
|
+
}
|
|
31
|
+
const posts = await chain(obj).user('123').posts()
|
|
32
|
+
assert.deepEqual(posts, [{ title: 'Hello' }, { title: 'World' }])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('method chaining returns new chain', async () => {
|
|
36
|
+
const obj = {
|
|
37
|
+
add: (n: number) => ({
|
|
38
|
+
multiply: (m: number) => n * m,
|
|
39
|
+
}),
|
|
40
|
+
}
|
|
41
|
+
assert.equal(await chain(obj).add(3).multiply(4), 12)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('this binding preserved', async () => {
|
|
45
|
+
const obj = { value: 42, get() { return this.value } }
|
|
46
|
+
assert.equal(await chain(obj).get(), 42)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('null in chain throws', async () => {
|
|
50
|
+
await assert.rejects(
|
|
51
|
+
async () => { await chain({ user: null } as any).user.name },
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('same chain reusable', async () => {
|
|
56
|
+
let callCount = 0
|
|
57
|
+
const obj = { fetch: async () => { callCount++; return callCount } }
|
|
58
|
+
const c = chain(obj).fetch()
|
|
59
|
+
assert.equal(await c, 1)
|
|
60
|
+
assert.equal(await c, 2) // no caching — executes again
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('async error propagates', async () => {
|
|
64
|
+
const obj = { fail: async () => { throw new Error('boom') } }
|
|
65
|
+
await assert.rejects(async () => { await chain(obj).fail() })
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// ── demo tracker component types ──
|
|
69
|
+
|
|
70
|
+
class LivePrices {
|
|
71
|
+
static $type = 'demo.live-prices'
|
|
72
|
+
feederUrl = 'ws://localhost:8090'
|
|
73
|
+
async subscribe({ slugs }: { slugs: string[] }) {
|
|
74
|
+
return slugs.map(s => ({ slug: s, bid: 0.6, ask: 0.65 }))
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class Scanner {
|
|
79
|
+
static $type = 'demo.scanner'
|
|
80
|
+
intervalMs = 900_000
|
|
81
|
+
livePrices: TypedRef<LivePrices> = refVal(LivePrices, '/demo/live-prices')
|
|
82
|
+
depositTracker: TypedRef<DepositTracker> = refVal(DepositTracker, '/demo/deposits')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class DepositTracker {
|
|
86
|
+
static $type = 'demo.deposit-tracker'
|
|
87
|
+
async run() { return { added: 12, ts: Date.now() } }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
class Profile {
|
|
91
|
+
static $type = 'demo.profile'
|
|
92
|
+
address = ''
|
|
93
|
+
async fetch({ address }: { address: string }) {
|
|
94
|
+
return { address, name: 'whale.eth', totalPnl: 50_000 }
|
|
95
|
+
}
|
|
96
|
+
async trades({ page = 1 } = {}) {
|
|
97
|
+
return { page, items: [{ hash: '0xabc', amount: 1000 }] }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── refVal ──
|
|
102
|
+
|
|
103
|
+
test('refVal stores $type and $ref', () => {
|
|
104
|
+
const ref = refVal(LivePrices, '/demo/live-prices')
|
|
105
|
+
assert.equal(ref.$type, 'ref')
|
|
106
|
+
assert.equal(ref.$ref, '/demo/live-prices')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test('refVal default path is empty', () => {
|
|
110
|
+
const ref = refVal(LivePrices)
|
|
111
|
+
assert.equal(ref.$ref, '')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// ── server executor: auto-resolves refs ──
|
|
115
|
+
|
|
116
|
+
function makeStore(entries: [string, any][]) {
|
|
117
|
+
const m = new Map(entries)
|
|
118
|
+
return (ref: { $ref: string }) => {
|
|
119
|
+
const node = m.get(ref.$ref)
|
|
120
|
+
if (!node) throw new Error(`Ref not found: ${ref.$ref}`)
|
|
121
|
+
return Promise.resolve(node)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
test('runPathWithRefs: follows ref to node', async () => {
|
|
126
|
+
const live = new LivePrices()
|
|
127
|
+
const scanner = new Scanner()
|
|
128
|
+
|
|
129
|
+
const result = await runPathWithRefs(
|
|
130
|
+
scanner,
|
|
131
|
+
['livePrices', 'subscribe', [{ slugs: ['btc-win'] }]],
|
|
132
|
+
makeStore([['/demo/live-prices', live]]),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
assert.deepEqual(result, [{ slug: 'btc-win', bid: 0.6, ask: 0.65 }])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('runPathWithRefs: multiple refs in one session', async () => {
|
|
139
|
+
const live = new LivePrices()
|
|
140
|
+
const deposits = new DepositTracker()
|
|
141
|
+
const scanner = new Scanner()
|
|
142
|
+
const resolve = makeStore([
|
|
143
|
+
['/demo/live-prices', live],
|
|
144
|
+
['/demo/deposits', deposits],
|
|
145
|
+
])
|
|
146
|
+
|
|
147
|
+
const prices = await runPathWithRefs(scanner, ['livePrices', 'subscribe', [{ slugs: ['x'] }]], resolve)
|
|
148
|
+
const run = await runPathWithRefs(scanner, ['depositTracker', 'run', []], resolve)
|
|
149
|
+
|
|
150
|
+
assert.ok(Array.isArray(prices))
|
|
151
|
+
assert.equal(run.added, 12)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('runPathWithRefs: nested refs (ref → node → ref → node)', async () => {
|
|
155
|
+
const profile = new Profile()
|
|
156
|
+
// live node has a nested ref to profile
|
|
157
|
+
const liveNode = { profile: { $type: 'ref', $ref: '/demo/profiles/0xabc' } }
|
|
158
|
+
const scanner = { live: { $type: 'ref', $ref: '/demo/live' } }
|
|
159
|
+
|
|
160
|
+
const result = await runPathWithRefs(
|
|
161
|
+
scanner,
|
|
162
|
+
['live', 'profile', 'fetch', [{ address: '0xabc' }]],
|
|
163
|
+
makeStore([
|
|
164
|
+
['/demo/live', liveNode],
|
|
165
|
+
['/demo/profiles/0xabc', profile],
|
|
166
|
+
]),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
assert.deepEqual(result, { address: '0xabc', name: 'whale.eth', totalPnl: 50_000 })
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('runPathWithRefs: missing ref throws', async () => {
|
|
173
|
+
const scanner = new Scanner()
|
|
174
|
+
await assert.rejects(
|
|
175
|
+
() => runPathWithRefs(scanner, ['livePrices', 'subscribe', [{ slugs: [] }]], makeStore([])),
|
|
176
|
+
)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('runPathWithRefs: profile trades pagination', async () => {
|
|
180
|
+
const profile = new Profile()
|
|
181
|
+
const node = { target: { $type: 'ref', $ref: '/profile' } }
|
|
182
|
+
|
|
183
|
+
const result = await runPathWithRefs(
|
|
184
|
+
node,
|
|
185
|
+
['target', 'trades', [{ page: 2 }]],
|
|
186
|
+
makeStore([['/profile', profile]]),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
assert.deepEqual(result, { page: 2, items: [{ hash: '0xabc', amount: 1000 }] })
|
|
190
|
+
})
|
package/src/chain.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Minimal call-chain: records property/call path, resolves lazily on await.
|
|
2
|
+
// Ref resolution is opt-in via runPathWithRefs — chain itself is pure.
|
|
3
|
+
|
|
4
|
+
import { isRef } from '#core';
|
|
5
|
+
|
|
6
|
+
export type PathSection = string | unknown[]
|
|
7
|
+
|
|
8
|
+
// ── Types (mirrors call-chain library, no dep needed) ──
|
|
9
|
+
|
|
10
|
+
type Primitive = undefined | null | boolean | string | number | symbol | bigint | void
|
|
11
|
+
|
|
12
|
+
type ValuePromise<T> = T extends Primitive
|
|
13
|
+
? Promise<T>
|
|
14
|
+
: T extends Promise<any>
|
|
15
|
+
? T
|
|
16
|
+
: Chain<T>
|
|
17
|
+
|
|
18
|
+
export type Chain<T> = Promise<T> & {
|
|
19
|
+
[K in keyof T]: T[K] extends (...args: infer A) => infer R
|
|
20
|
+
? (...args: A) => ValuePromise<Awaited<NonNullable<R>>>
|
|
21
|
+
: ValuePromise<Awaited<NonNullable<T[K]>>>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// TypedRef: runtime $ref + phantom type T for call-chain to follow
|
|
25
|
+
// _T is a phantom type — exists only for TypeScript inference, erased at runtime
|
|
26
|
+
export interface TypedRef<_T> {
|
|
27
|
+
readonly $type: 'ref'
|
|
28
|
+
$ref: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Pass registered class (has .$type stamped by registerType) for TypeScript type inference.
|
|
32
|
+
// Runtime only stores $ref — no class reference kept.
|
|
33
|
+
export function refVal<T>(Comp: (new () => T) & { $type?: string }, defaultPath = ''): TypedRef<T> {
|
|
34
|
+
void Comp // type-only at runtime; $type from registerType could be stored if needed
|
|
35
|
+
return { $type: 'ref', $ref: defaultPath }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── Core ──
|
|
39
|
+
|
|
40
|
+
export async function runPath(target: any, path: PathSection[]): Promise<any> {
|
|
41
|
+
let cur = target, prev = target
|
|
42
|
+
for (const step of path) {
|
|
43
|
+
if (cur == null) throw new Error(`null at step: ${JSON.stringify(step)}`)
|
|
44
|
+
if (typeof step === 'string') { prev = cur; cur = cur[step] }
|
|
45
|
+
else { cur = cur.apply(prev, step as any[]) }
|
|
46
|
+
if (cur?.then) cur = await cur
|
|
47
|
+
}
|
|
48
|
+
return cur
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Server executor: same as runPath but auto-follows TypedRef fields
|
|
52
|
+
export async function runPathWithRefs(
|
|
53
|
+
target: any,
|
|
54
|
+
path: PathSection[],
|
|
55
|
+
resolveRef: (ref: { $ref: string }) => Promise<any>,
|
|
56
|
+
): Promise<any> {
|
|
57
|
+
let cur = target, prev = target
|
|
58
|
+
for (const step of path) {
|
|
59
|
+
if (cur == null) throw new Error(`null at step: ${JSON.stringify(step)}`)
|
|
60
|
+
if (typeof step === 'string') {
|
|
61
|
+
prev = cur
|
|
62
|
+
cur = cur[step]
|
|
63
|
+
if (isRef(cur)) cur = await resolveRef(cur)
|
|
64
|
+
} else {
|
|
65
|
+
cur = cur.apply(prev, step as any[])
|
|
66
|
+
}
|
|
67
|
+
if (cur?.then) cur = await cur
|
|
68
|
+
}
|
|
69
|
+
return cur
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const make = (target: any, path: PathSection[]): any =>
|
|
73
|
+
new Proxy((() => {}) as any, {
|
|
74
|
+
get: (_, p: string | symbol) => {
|
|
75
|
+
if (p === 'then') return (res: any, rej: any) => runPath(target, path).then(res, rej)
|
|
76
|
+
if (typeof p === 'symbol') return undefined
|
|
77
|
+
return make(target, [...path, p as string])
|
|
78
|
+
},
|
|
79
|
+
apply: (_, __, args) => make(target, [...path, args]),
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
export const chain = <T>(target: T): Chain<T> => make(target, []) as Chain<T>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Treenity Client SDK — e2e tests
|
|
2
|
+
// Tests createTrpcTransport + createRepathTree + t.mount.tree.trpc
|
|
3
|
+
|
|
4
|
+
import { registerType } from '#comp';
|
|
5
|
+
import { createNode, R, S, W } from '#core';
|
|
6
|
+
import { withMounts } from '#server/mount';
|
|
7
|
+
import '#server/mount-adapters';
|
|
8
|
+
import { createTreenityServer } from '#server/server';
|
|
9
|
+
import { createMemoryTree } from '#tree';
|
|
10
|
+
import { createRepathTree } from '#tree/repath';
|
|
11
|
+
import assert from 'node:assert/strict';
|
|
12
|
+
import type { Socket } from 'node:net';
|
|
13
|
+
import { afterEach, before, beforeEach, describe, it } from 'node:test';
|
|
14
|
+
import { createTrpcTransport } from './trpc';
|
|
15
|
+
|
|
16
|
+
// ── Helpers ──
|
|
17
|
+
|
|
18
|
+
function listen(server: import('node:http').Server): Promise<number> {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
server.listen(0, '127.0.0.1', () => {
|
|
21
|
+
resolve((server.address() as { port: number }).port);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ── Test type ──
|
|
27
|
+
|
|
28
|
+
class Counter {
|
|
29
|
+
count = 0;
|
|
30
|
+
increment() { this.count++; }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('Treenity Client SDK', () => {
|
|
34
|
+
let ts: ReturnType<typeof createTreenityServer>;
|
|
35
|
+
let url: string;
|
|
36
|
+
const sockets = new Set<Socket>();
|
|
37
|
+
|
|
38
|
+
before(() => {
|
|
39
|
+
registerType('counter', Counter);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
beforeEach(async () => {
|
|
43
|
+
const bootstrap = createMemoryTree();
|
|
44
|
+
await bootstrap.set({
|
|
45
|
+
...createNode('/', 'root'),
|
|
46
|
+
$acl: [{ g: 'public', p: R | W | S }],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
ts = createTreenityServer(bootstrap);
|
|
50
|
+
ts.server.on('connection', (s: Socket) => {
|
|
51
|
+
sockets.add(s);
|
|
52
|
+
s.on('close', () => sockets.delete(s));
|
|
53
|
+
});
|
|
54
|
+
const port = await listen(ts.server);
|
|
55
|
+
url = `http://127.0.0.1:${port}`;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
afterEach(async () => {
|
|
59
|
+
for (const s of sockets) s.destroy();
|
|
60
|
+
sockets.clear();
|
|
61
|
+
await new Promise<void>((r) => ts.server.close(() => r()));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// ── createTrpcTransport ──
|
|
65
|
+
|
|
66
|
+
describe('createTrpcTransport', () => {
|
|
67
|
+
it('tree.get + tree.set roundtrip', async () => {
|
|
68
|
+
const { tree } = createTrpcTransport({ url });
|
|
69
|
+
await tree.set(createNode('/hello', 'doc', { title: 'World' }));
|
|
70
|
+
const node = await tree.get('/hello');
|
|
71
|
+
|
|
72
|
+
assert.ok(node);
|
|
73
|
+
assert.equal(node.$type, 't.doc');
|
|
74
|
+
assert.equal((node as any).title, 'World');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('tree.getChildren returns children', async () => {
|
|
78
|
+
const { tree } = createTrpcTransport({ url });
|
|
79
|
+
await tree.set(createNode('/items', 'dir'));
|
|
80
|
+
await tree.set(createNode('/items/a', 'doc'));
|
|
81
|
+
await tree.set(createNode('/items/b', 'doc'));
|
|
82
|
+
|
|
83
|
+
const { items } = await tree.getChildren('/items');
|
|
84
|
+
assert.equal(items.length, 2);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('tree.remove deletes node', async () => {
|
|
88
|
+
const { tree } = createTrpcTransport({ url });
|
|
89
|
+
await tree.set(createNode('/tmp', 'doc'));
|
|
90
|
+
await tree.remove('/tmp');
|
|
91
|
+
|
|
92
|
+
assert.equal(await tree.get('/tmp'), undefined);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('execute calls action', async () => {
|
|
96
|
+
const { tree, execute } = createTrpcTransport({ url });
|
|
97
|
+
await tree.set(createNode('/c', 'counter', { count: 0 }));
|
|
98
|
+
|
|
99
|
+
await execute('/c', 'increment');
|
|
100
|
+
|
|
101
|
+
const node = await tree.get('/c');
|
|
102
|
+
assert.equal((node as any).count, 1);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ── createRepathTree over tRPC ──
|
|
107
|
+
|
|
108
|
+
describe('createRepathTree + tRPC', () => {
|
|
109
|
+
it('translates paths over the wire', async () => {
|
|
110
|
+
const { tree: remote } = createTrpcTransport({ url });
|
|
111
|
+
|
|
112
|
+
// Write via server at absolute path
|
|
113
|
+
await remote.set(createNode('/data/item', 'doc', { v: 42 }));
|
|
114
|
+
|
|
115
|
+
// Mount remote's /data at local /mnt
|
|
116
|
+
const mounted = createRepathTree(remote, '/mnt', '/data');
|
|
117
|
+
const node = await mounted.get('/mnt/item');
|
|
118
|
+
|
|
119
|
+
assert.ok(node);
|
|
120
|
+
assert.equal(node.$path, '/mnt/item');
|
|
121
|
+
assert.equal((node as any).v, 42);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('set through repath writes to correct remote path', async () => {
|
|
125
|
+
const { tree: remote } = createTrpcTransport({ url });
|
|
126
|
+
const mounted = createRepathTree(remote, '/mnt', '/store');
|
|
127
|
+
|
|
128
|
+
await mounted.set(createNode('/mnt/new', 'doc', { x: 1 }));
|
|
129
|
+
|
|
130
|
+
// Verify via direct remote access
|
|
131
|
+
const node = await remote.get('/store/new');
|
|
132
|
+
assert.ok(node);
|
|
133
|
+
assert.equal(node.$path, '/store/new');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// ── t.mount.tree.trpc ──
|
|
138
|
+
|
|
139
|
+
describe('t.mount.tree.trpc', () => {
|
|
140
|
+
it('mounts remote tree with path translation', async () => {
|
|
141
|
+
// Set up content on the remote server
|
|
142
|
+
const { tree: remote } = createTrpcTransport({ url });
|
|
143
|
+
await remote.set(createNode('/strategies/alpha', 'doc', { score: 99 }));
|
|
144
|
+
|
|
145
|
+
// Create a local bootstrap with mount pointing to remote
|
|
146
|
+
const local = createMemoryTree();
|
|
147
|
+
await local.set({
|
|
148
|
+
...createNode('/', 'root'),
|
|
149
|
+
$acl: [{ g: 'public', p: R | W | S }],
|
|
150
|
+
});
|
|
151
|
+
await local.set({
|
|
152
|
+
$path: '/remote',
|
|
153
|
+
$type: 'dir',
|
|
154
|
+
mount: { $type: 't.mount.tree.trpc' },
|
|
155
|
+
connection: { $type: 'connection', url, path: '/strategies' },
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const store = withMounts(local);
|
|
159
|
+
const node = await store.get('/remote/alpha');
|
|
160
|
+
|
|
161
|
+
assert.ok(node);
|
|
162
|
+
assert.equal(node.$path, '/remote/alpha');
|
|
163
|
+
assert.equal((node as any).score, 99);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('getChildren through mount', async () => {
|
|
167
|
+
const { tree: remote } = createTrpcTransport({ url });
|
|
168
|
+
await remote.set(createNode('/items', 'dir'));
|
|
169
|
+
await remote.set(createNode('/items/x', 'doc'));
|
|
170
|
+
await remote.set(createNode('/items/y', 'doc'));
|
|
171
|
+
|
|
172
|
+
const local = createMemoryTree();
|
|
173
|
+
await local.set({
|
|
174
|
+
...createNode('/', 'root'),
|
|
175
|
+
$acl: [{ g: 'public', p: R | W | S }],
|
|
176
|
+
});
|
|
177
|
+
await local.set({
|
|
178
|
+
$path: '/fed',
|
|
179
|
+
$type: 'dir',
|
|
180
|
+
mount: { $type: 't.mount.tree.trpc' },
|
|
181
|
+
connection: { $type: 'connection', url, path: '/items' },
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const store = withMounts(local);
|
|
185
|
+
const { items } = await store.getChildren('/fed');
|
|
186
|
+
|
|
187
|
+
assert.equal(items.length, 2);
|
|
188
|
+
const paths = items.map(n => n.$path).sort();
|
|
189
|
+
assert.deepEqual(paths, ['/fed/x', '/fed/y']);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Client node handle — typed access to remote nodes.
|
|
2
|
+
// nc(path).get(Type).method() — actions, no fetch needed.
|
|
3
|
+
// nc(path).fetch(Type) — async fetch + typed proxy.
|
|
4
|
+
// nc(path).sub(Type, cb) — reactive subscription with typed data.
|
|
5
|
+
|
|
6
|
+
import { type Class, type TypeProxy } from '#comp';
|
|
7
|
+
import { makeTypedProxy, type ExecuteFn } from '#comp/handle';
|
|
8
|
+
import type { NodeData } from '#core';
|
|
9
|
+
import type { TreenityClient } from './index';
|
|
10
|
+
|
|
11
|
+
export function createNodeClient(client: TreenityClient) {
|
|
12
|
+
const execute: ExecuteFn = (input) =>
|
|
13
|
+
client.execute(input.path, input.action, input.data, { type: input.type, key: input.key });
|
|
14
|
+
|
|
15
|
+
return (path: string) => ({
|
|
16
|
+
/** Typed actions proxy — calls execute over network, no fetch needed */
|
|
17
|
+
get<T extends object>(cls: Class<T>, key?: string): TypeProxy<T> {
|
|
18
|
+
return makeTypedProxy<T>(undefined, cls, path, execute, undefined, key);
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/** Fetch node + typed proxy (data fields + action methods) */
|
|
22
|
+
async fetch<T extends object>(cls: Class<T>, key?: string): Promise<TypeProxy<T>> {
|
|
23
|
+
const node = await client.tree.get(path);
|
|
24
|
+
return makeTypedProxy<T>(node, cls, path, execute, undefined, key);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/** Subscribe — callback with typed proxy on each change */
|
|
28
|
+
async sub<T extends object>(cls: Class<T>, cb: (data: TypeProxy<T>) => void, key?: string) {
|
|
29
|
+
let cached: NodeData | undefined;
|
|
30
|
+
|
|
31
|
+
function notify() {
|
|
32
|
+
cb(makeTypedProxy<T>(cached, cls, path, execute, undefined, key));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { node, unsubscribe } = await client.watchPath(path, (event) => {
|
|
36
|
+
if (event.type === 'set') {
|
|
37
|
+
cached = { $path: event.path, ...event.node } as NodeData;
|
|
38
|
+
notify();
|
|
39
|
+
}
|
|
40
|
+
if (event.type === 'patch' && cached) {
|
|
41
|
+
// Re-fetch on patch (optimize with applyPatch later)
|
|
42
|
+
client.tree.get(path).then(fresh => {
|
|
43
|
+
if (fresh) { cached = fresh; notify(); }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
cached = node as NodeData | undefined;
|
|
49
|
+
if (cached) notify();
|
|
50
|
+
return { unsubscribe };
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Treenity Client SDK — transport-agnostic tree client interface.
|
|
2
|
+
// Transports: trpc (now), ws (future), http (future).
|
|
3
|
+
|
|
4
|
+
import type { Tree } from '#tree';
|
|
5
|
+
|
|
6
|
+
export type WatchSub = { unsubscribe(): void };
|
|
7
|
+
|
|
8
|
+
export type TreenityClient = {
|
|
9
|
+
tree: Tree;
|
|
10
|
+
execute(path: string, action: string, data?: unknown, opts?: { type?: string; key?: string }): Promise<unknown>;
|
|
11
|
+
/** Global SSE stream — all events for this user */
|
|
12
|
+
watch(onEvent: (e: any) => void): WatchSub;
|
|
13
|
+
/** Watch specific path — registers watch + filters events. Returns initial node + subscription. */
|
|
14
|
+
watchPath(path: string, onEvent: (e: any) => void): Promise<{ node: any; unsubscribe(): void }>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { createTrpcTransport } from './trpc';
|
|
18
|
+
export { createNodeClient } from './handle';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// tRPC transport for Treenity Client.
|
|
2
|
+
// HTTP batch for queries/mutations, SSE for subscriptions.
|
|
3
|
+
|
|
4
|
+
import type { NodeData } from '#core';
|
|
5
|
+
import type { TreeRouter } from '#server/trpc';
|
|
6
|
+
import { defaultPatch } from '#tree/patch';
|
|
7
|
+
import { createTRPCClient, httpBatchLink, httpSubscriptionLink, splitLink } from '@trpc/client';
|
|
8
|
+
import type { TreenityClient, WatchSub } from './index';
|
|
9
|
+
|
|
10
|
+
export type TrpcTransportOpts = {
|
|
11
|
+
url: string;
|
|
12
|
+
getToken?: () => string | null;
|
|
13
|
+
token?: string;
|
|
14
|
+
fetch?: (input: any, init?: any) => Promise<Response>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function createTrpcTransport(opts: TrpcTransportOpts): TreenityClient & { trpc: ReturnType<typeof createTRPCClient<TreeRouter>> } {
|
|
18
|
+
const getToken = opts.getToken ?? (() => opts.token ?? null);
|
|
19
|
+
|
|
20
|
+
const trpc = createTRPCClient<TreeRouter>({
|
|
21
|
+
links: [
|
|
22
|
+
splitLink({
|
|
23
|
+
condition: (op) => op.type === 'subscription',
|
|
24
|
+
true: httpSubscriptionLink({
|
|
25
|
+
url: `${opts.url}/trpc/`,
|
|
26
|
+
connectionParams: () => {
|
|
27
|
+
const t = getToken();
|
|
28
|
+
return t ? { token: t } : {};
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
false: httpBatchLink({
|
|
32
|
+
url: `${opts.url}/trpc/`,
|
|
33
|
+
headers: () => {
|
|
34
|
+
const t = getToken();
|
|
35
|
+
return t ? { Authorization: `Bearer ${t}` } : {};
|
|
36
|
+
},
|
|
37
|
+
...(opts.fetch && { fetch: opts.fetch }),
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Shared SSE connection for watchPath — lazy, one per transport
|
|
44
|
+
let eventSub: WatchSub | null = null;
|
|
45
|
+
const pathCbs = new Map<string, Set<(e: any) => void>>();
|
|
46
|
+
|
|
47
|
+
function ensureSSE() {
|
|
48
|
+
if (eventSub) return;
|
|
49
|
+
eventSub = trpc.events.subscribe(undefined as void, {
|
|
50
|
+
onData: (event: any) => {
|
|
51
|
+
if ('path' in event) pathCbs.get(event.path)?.forEach(cb => cb(event));
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
tree: {
|
|
58
|
+
get: (path) => trpc.get.query({ path }) as Promise<NodeData | undefined>,
|
|
59
|
+
getChildren: (path, opts) => trpc.getChildren.query({ path, ...opts }),
|
|
60
|
+
set: (node) => trpc.set.mutate({ node: node as Record<string, unknown> }),
|
|
61
|
+
remove: (path) => trpc.remove.mutate({ path }).then(() => true),
|
|
62
|
+
// TODO: add tRPC patch endpoint for single-RPC atomic patch
|
|
63
|
+
patch: (path, ops) => defaultPatch(
|
|
64
|
+
(p) => trpc.get.query({ path: p }) as Promise<NodeData | undefined>,
|
|
65
|
+
(n) => trpc.set.mutate({ node: n as Record<string, unknown> }).then(() => {}),
|
|
66
|
+
path, ops,
|
|
67
|
+
),
|
|
68
|
+
},
|
|
69
|
+
execute: (path, action, data, o) =>
|
|
70
|
+
trpc.execute.mutate({ path, action, data, type: o?.type, key: o?.key }),
|
|
71
|
+
watch: (onEvent) =>
|
|
72
|
+
trpc.events.subscribe(undefined as void, { onData: onEvent }),
|
|
73
|
+
|
|
74
|
+
watchPath: async (path, onEvent) => {
|
|
75
|
+
const node = await trpc.get.query({ path, watch: true });
|
|
76
|
+
ensureSSE();
|
|
77
|
+
if (!pathCbs.has(path)) pathCbs.set(path, new Set());
|
|
78
|
+
pathCbs.get(path)!.add(onEvent);
|
|
79
|
+
return {
|
|
80
|
+
node,
|
|
81
|
+
unsubscribe() {
|
|
82
|
+
const set = pathCbs.get(path);
|
|
83
|
+
if (set) { set.delete(onEvent); if (!set.size) pathCbs.delete(path); }
|
|
84
|
+
if (!pathCbs.size && eventSub) { eventSub.unsubscribe(); eventSub = null; }
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
trpc,
|
|
90
|
+
};
|
|
91
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './client/index.ts';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## comp
|
|
2
|
+
Component registration layer (L2). Bridges core primitives and server.
|
|
3
|
+
|
|
4
|
+
### Файлы
|
|
5
|
+
- index.ts — registerType, findCompByType, Actions<T>, TypeProxy<T> = Raw<T> & Actions<T>
|
|
6
|
+
- needs.ts — sibling dependency injection: registerNeeds/resolveNeeds
|
|
7
|
+
- ports.ts — action port graph: pre/post conditions as queryable edges
|
|
8
|
+
- planner.ts — backward+forward chaining planner on the port graph
|
|
9
|
+
|
|
10
|
+
### Конвенции
|
|
11
|
+
- registerType auto-registers all public methods as action:{name}
|
|
12
|
+
- Components never access siblings directly — use `needs` for injection
|
|
13
|
+
- Ports declared via static metadata, planner resolves execution order
|
|
14
|
+
- ExecCtx = {node, tree, signal, nc, deps} — context during action execution
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Shared typed proxy factory — L0, no server deps.
|
|
2
|
+
// Used by: server (serverNodeHandle), client (createNodeClient), React (hooks).
|
|
3
|
+
|
|
4
|
+
import { type Class, type TypeProxy } from './index';
|
|
5
|
+
import { getComponent, type NodeData, normalizeType } from '#core';
|
|
6
|
+
|
|
7
|
+
export type ExecuteInput = { path: string; type?: string; key?: string; action: string; data?: unknown };
|
|
8
|
+
export type ExecuteFn = (input: ExecuteInput) => Promise<unknown>;
|
|
9
|
+
export type StreamFn = (input: ExecuteInput) => AsyncIterable<unknown>;
|
|
10
|
+
|
|
11
|
+
const AsyncGenFn = Object.getPrototypeOf(async function* () {}).constructor;
|
|
12
|
+
|
|
13
|
+
/** Create TypeProxy from node data + class. Actions call execute/stream, fields read from comp. */
|
|
14
|
+
export function makeTypedProxy<T extends object>(
|
|
15
|
+
node: NodeData | undefined,
|
|
16
|
+
cls: Class<T>,
|
|
17
|
+
path: string,
|
|
18
|
+
execute: ExecuteFn,
|
|
19
|
+
stream?: StreamFn,
|
|
20
|
+
key?: string,
|
|
21
|
+
): TypeProxy<T> {
|
|
22
|
+
const type = normalizeType(cls);
|
|
23
|
+
const comp = node ? getComponent(node, cls, key) : undefined;
|
|
24
|
+
|
|
25
|
+
return new Proxy(comp ?? {} as T, {
|
|
26
|
+
get: (_t, prop: string) => {
|
|
27
|
+
const fn = (cls.prototype as any)[prop];
|
|
28
|
+
if (typeof fn === 'function') {
|
|
29
|
+
if (stream && fn instanceof AsyncGenFn)
|
|
30
|
+
return (data?: unknown) => stream({ path, type, key, action: prop, data });
|
|
31
|
+
return (data?: unknown) => execute({ path, type, key, action: prop, data });
|
|
32
|
+
}
|
|
33
|
+
return (comp as any)?.[prop];
|
|
34
|
+
},
|
|
35
|
+
}) as TypeProxy<T>;
|
|
36
|
+
}
|