@pwfabric/runtime 0.0.0-stage → 1.0.0-rc.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/LICENSE +90 -0
- package/README.md +43 -2
- package/dist/a11y/announcer.d.ts +65 -0
- package/dist/a11y/announcer.js +140 -0
- package/dist/a11y/announcer.js.map +1 -0
- package/dist/a11y/contrast.d.ts +54 -0
- package/dist/a11y/contrast.js +93 -0
- package/dist/a11y/contrast.js.map +1 -0
- package/dist/a11y/focus.d.ts +123 -0
- package/dist/a11y/focus.js +282 -0
- package/dist/a11y/focus.js.map +1 -0
- package/dist/a11y/index.d.ts +21 -0
- package/dist/a11y/index.js +18 -0
- package/dist/a11y/index.js.map +1 -0
- package/dist/a11y/keyboard.d.ts +144 -0
- package/dist/a11y/keyboard.js +317 -0
- package/dist/a11y/keyboard.js.map +1 -0
- package/dist/adapters/default-image.d.ts +25 -0
- package/dist/adapters/default-image.js +37 -0
- package/dist/adapters/default-image.js.map +1 -0
- package/dist/adapters/index.d.ts +27 -0
- package/dist/adapters/index.js +28 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/next-image.d.ts +38 -0
- package/dist/adapters/next-image.js +124 -0
- package/dist/adapters/next-image.js.map +1 -0
- package/dist/adapters/types.d.ts +61 -0
- package/dist/adapters/types.js +11 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/analytics/index.d.ts +14 -0
- package/dist/analytics/index.js +15 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/tracker.d.ts +65 -0
- package/dist/analytics/tracker.js +251 -0
- package/dist/analytics/tracker.js.map +1 -0
- package/dist/analytics/types.d.ts +130 -0
- package/dist/analytics/types.js +11 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/auth/index.d.ts +15 -0
- package/dist/auth/index.js +14 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/provider.d.ts +132 -0
- package/dist/auth/provider.js +473 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/auth/types.d.ts +117 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/binding/collection.d.ts +190 -0
- package/dist/binding/collection.js +358 -0
- package/dist/binding/collection.js.map +1 -0
- package/dist/binding/datasource.d.ts +319 -0
- package/dist/binding/datasource.js +556 -0
- package/dist/binding/datasource.js.map +1 -0
- package/dist/binding/engine.d.ts +65 -0
- package/dist/binding/engine.js +268 -0
- package/dist/binding/engine.js.map +1 -0
- package/dist/binding/expression.d.ts +150 -0
- package/dist/binding/expression.js +787 -0
- package/dist/binding/expression.js.map +1 -0
- package/dist/binding/index.d.ts +19 -0
- package/dist/binding/index.js +14 -0
- package/dist/binding/index.js.map +1 -0
- package/dist/binding/two-way.d.ts +149 -0
- package/dist/binding/two-way.js +462 -0
- package/dist/binding/two-way.js.map +1 -0
- package/dist/binding/types.d.ts +119 -0
- package/dist/binding/types.js +9 -0
- package/dist/binding/types.js.map +1 -0
- package/dist/blocks/component-types.d.ts +81 -0
- package/dist/blocks/component-types.js +11 -0
- package/dist/blocks/component-types.js.map +1 -0
- package/dist/blocks/composition-rules.d.ts +168 -0
- package/dist/blocks/composition-rules.js +391 -0
- package/dist/blocks/composition-rules.js.map +1 -0
- package/dist/blocks/hooks.d.ts +31 -0
- package/dist/blocks/hooks.js +42 -0
- package/dist/blocks/hooks.js.map +1 -0
- package/dist/blocks/index.d.ts +14 -0
- package/dist/blocks/index.js +23 -0
- package/dist/blocks/index.js.map +1 -0
- package/dist/blocks/registry.d.ts +84 -0
- package/dist/blocks/registry.js +136 -0
- package/dist/blocks/registry.js.map +1 -0
- package/dist/blocks/rule-engine.d.ts +131 -0
- package/dist/blocks/rule-engine.js +321 -0
- package/dist/blocks/rule-engine.js.map +1 -0
- package/dist/blocks/surface-event-context.d.ts +13 -0
- package/dist/blocks/surface-event-context.js +14 -0
- package/dist/blocks/surface-event-context.js.map +1 -0
- package/dist/blocks/surface-id-context.d.ts +13 -0
- package/dist/blocks/surface-id-context.js +15 -0
- package/dist/blocks/surface-id-context.js.map +1 -0
- package/dist/bus.d.ts +41 -0
- package/dist/bus.js +158 -0
- package/dist/bus.js.map +1 -0
- package/dist/cache/index.d.ts +9 -0
- package/dist/cache/index.js +10 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory.d.ts +32 -0
- package/dist/cache/memory.js +138 -0
- package/dist/cache/memory.js.map +1 -0
- package/dist/cache/types.d.ts +62 -0
- package/dist/cache/types.js +9 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/capability/index.d.ts +72 -0
- package/dist/capability/index.js +87 -0
- package/dist/capability/index.js.map +1 -0
- package/dist/capability/kernel-capabilities.d.ts +31 -0
- package/dist/capability/kernel-capabilities.js +36 -0
- package/dist/capability/kernel-capabilities.js.map +1 -0
- package/dist/capability/platform-capabilities.d.ts +71 -0
- package/dist/capability/platform-capabilities.js +267 -0
- package/dist/capability/platform-capabilities.js.map +1 -0
- package/dist/capability/type-mapping.d.ts +70 -0
- package/dist/capability/type-mapping.js +107 -0
- package/dist/capability/type-mapping.js.map +1 -0
- package/dist/capability/validation.d.ts +46 -0
- package/dist/capability/validation.js +54 -0
- package/dist/capability/validation.js.map +1 -0
- package/dist/connectors/declared-connector.d.ts +48 -0
- package/dist/connectors/declared-connector.js +333 -0
- package/dist/connectors/declared-connector.js.map +1 -0
- package/dist/connectors/engine-registry.d.ts +50 -0
- package/dist/connectors/engine-registry.js +135 -0
- package/dist/connectors/engine-registry.js.map +1 -0
- package/dist/connectors/index.d.ts +14 -0
- package/dist/connectors/index.js +14 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/module-loader.d.ts +70 -0
- package/dist/connectors/module-loader.js +143 -0
- package/dist/connectors/module-loader.js.map +1 -0
- package/dist/connectors/types.d.ts +174 -0
- package/dist/connectors/types.js +23 -0
- package/dist/connectors/types.js.map +1 -0
- package/dist/context.d.ts +27 -0
- package/dist/context.js +38 -0
- package/dist/context.js.map +1 -0
- package/dist/data/DataCapabilityProvider.d.ts +39 -0
- package/dist/data/DataCapabilityProvider.js +58 -0
- package/dist/data/DataCapabilityProvider.js.map +1 -0
- package/dist/data/index.d.ts +17 -0
- package/dist/data/index.js +18 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/manager.d.ts +40 -0
- package/dist/data/manager.js +442 -0
- package/dist/data/manager.js.map +1 -0
- package/dist/data/types.d.ts +218 -0
- package/dist/data/types.js +2 -0
- package/dist/data/types.js.map +1 -0
- package/dist/entity/aggregate.d.ts +8 -0
- package/dist/entity/aggregate.js +24 -0
- package/dist/entity/aggregate.js.map +1 -0
- package/dist/entity/apply-query.d.ts +58 -0
- package/dist/entity/apply-query.js +264 -0
- package/dist/entity/apply-query.js.map +1 -0
- package/dist/entity/behavior.d.ts +94 -0
- package/dist/entity/behavior.js +78 -0
- package/dist/entity/behavior.js.map +1 -0
- package/dist/entity/connector.d.ts +141 -0
- package/dist/entity/connector.js +89 -0
- package/dist/entity/connector.js.map +1 -0
- package/dist/entity/connectors/index.d.ts +12 -0
- package/dist/entity/connectors/index.js +11 -0
- package/dist/entity/connectors/index.js.map +1 -0
- package/dist/entity/connectors/static.d.ts +51 -0
- package/dist/entity/connectors/static.js +245 -0
- package/dist/entity/connectors/static.js.map +1 -0
- package/dist/entity/entity-datasource.d.ts +50 -0
- package/dist/entity/entity-datasource.js +33 -0
- package/dist/entity/entity-datasource.js.map +1 -0
- package/dist/entity/facade.d.ts +70 -0
- package/dist/entity/facade.js +70 -0
- package/dist/entity/facade.js.map +1 -0
- package/dist/entity/http-connector.d.ts +123 -0
- package/dist/entity/http-connector.js +295 -0
- package/dist/entity/http-connector.js.map +1 -0
- package/dist/entity/index.d.ts +38 -0
- package/dist/entity/index.js +31 -0
- package/dist/entity/index.js.map +1 -0
- package/dist/entity/postgres-connector.d.ts +64 -0
- package/dist/entity/postgres-connector.js +239 -0
- package/dist/entity/postgres-connector.js.map +1 -0
- package/dist/entity/registry.d.ts +59 -0
- package/dist/entity/registry.js +90 -0
- package/dist/entity/registry.js.map +1 -0
- package/dist/entity/store.d.ts +66 -0
- package/dist/entity/store.js +349 -0
- package/dist/entity/store.js.map +1 -0
- package/dist/entity/types.d.ts +180 -0
- package/dist/entity/types.js +10 -0
- package/dist/entity/types.js.map +1 -0
- package/dist/execution-context.d.ts +88 -0
- package/dist/execution-context.js +146 -0
- package/dist/execution-context.js.map +1 -0
- package/dist/executor.d.ts +27 -0
- package/dist/executor.js +33 -0
- package/dist/executor.js.map +1 -0
- package/dist/forms/form-entity-bridge.d.ts +94 -0
- package/dist/forms/form-entity-bridge.js +96 -0
- package/dist/forms/form-entity-bridge.js.map +1 -0
- package/dist/forms/form-write-target.d.ts +34 -0
- package/dist/forms/form-write-target.js +81 -0
- package/dist/forms/form-write-target.js.map +1 -0
- package/dist/forms/index.d.ts +22 -0
- package/dist/forms/index.js +25 -0
- package/dist/forms/index.js.map +1 -0
- package/dist/forms/named-control-values.d.ts +27 -0
- package/dist/forms/named-control-values.js +42 -0
- package/dist/forms/named-control-values.js.map +1 -0
- package/dist/forms/processor.d.ts +55 -0
- package/dist/forms/processor.js +154 -0
- package/dist/forms/processor.js.map +1 -0
- package/dist/forms/types.d.ts +174 -0
- package/dist/forms/types.js +33 -0
- package/dist/forms/types.js.map +1 -0
- package/dist/forms/validator.d.ts +61 -0
- package/dist/forms/validator.js +218 -0
- package/dist/forms/validator.js.map +1 -0
- package/dist/graph/index.d.ts +10 -0
- package/dist/graph/index.js +9 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/resolver.d.ts +66 -0
- package/dist/graph/resolver.js +243 -0
- package/dist/graph/resolver.js.map +1 -0
- package/dist/graph/types.d.ts +125 -0
- package/dist/graph/types.js +9 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/hooks/useInstalledAtoms.d.ts +96 -0
- package/dist/hooks/useInstalledAtoms.js +92 -0
- package/dist/hooks/useInstalledAtoms.js.map +1 -0
- package/dist/i18n/index.d.ts +15 -0
- package/dist/i18n/index.js +14 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/translator.d.ts +76 -0
- package/dist/i18n/translator.js +357 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/i18n/types.d.ts +93 -0
- package/dist/i18n/types.js +9 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel.d.ts +47 -0
- package/dist/kernel.js +258 -0
- package/dist/kernel.js.map +1 -0
- package/dist/perf/budget.d.ts +92 -0
- package/dist/perf/budget.js +122 -0
- package/dist/perf/budget.js.map +1 -0
- package/dist/perf/index.d.ts +16 -0
- package/dist/perf/index.js +13 -0
- package/dist/perf/index.js.map +1 -0
- package/dist/perf/render-timer.d.ts +90 -0
- package/dist/perf/render-timer.js +136 -0
- package/dist/perf/render-timer.js.map +1 -0
- package/dist/perf/reporter.d.ts +126 -0
- package/dist/perf/reporter.js +241 -0
- package/dist/perf/reporter.js.map +1 -0
- package/dist/perf/web-vitals.d.ts +111 -0
- package/dist/perf/web-vitals.js +268 -0
- package/dist/perf/web-vitals.js.map +1 -0
- package/dist/registry.d.ts +63 -0
- package/dist/registry.js +126 -0
- package/dist/registry.js.map +1 -0
- package/dist/render/BehaviorSurfaceProvider.d.ts +65 -0
- package/dist/render/BehaviorSurfaceProvider.js +185 -0
- package/dist/render/BehaviorSurfaceProvider.js.map +1 -0
- package/dist/render/BlockErrorBoundary.d.ts +26 -0
- package/dist/render/BlockErrorBoundary.js +41 -0
- package/dist/render/BlockErrorBoundary.js.map +1 -0
- package/dist/render/DataBoundSurfaceRenderer.d.ts +78 -0
- package/dist/render/DataBoundSurfaceRenderer.js +998 -0
- package/dist/render/DataBoundSurfaceRenderer.js.map +1 -0
- package/dist/render/DynamicBlockWrapper.d.ts +23 -0
- package/dist/render/DynamicBlockWrapper.js +117 -0
- package/dist/render/DynamicBlockWrapper.js.map +1 -0
- package/dist/render/appearance-resolver.d.ts +50 -0
- package/dist/render/appearance-resolver.js +78 -0
- package/dist/render/appearance-resolver.js.map +1 -0
- package/dist/render/capability-gate.d.ts +69 -0
- package/dist/render/capability-gate.js +94 -0
- package/dist/render/capability-gate.js.map +1 -0
- package/dist/render/conditional-states-css.d.ts +41 -0
- package/dist/render/conditional-states-css.js +82 -0
- package/dist/render/conditional-states-css.js.map +1 -0
- package/dist/render/connections-context.d.ts +31 -0
- package/dist/render/connections-context.js +34 -0
- package/dist/render/connections-context.js.map +1 -0
- package/dist/render/dark-theme-css.d.ts +36 -0
- package/dist/render/dark-theme-css.js +67 -0
- package/dist/render/dark-theme-css.js.map +1 -0
- package/dist/render/data-binding-types.d.ts +191 -0
- package/dist/render/data-binding-types.js +11 -0
- package/dist/render/data-binding-types.js.map +1 -0
- package/dist/render/data-cache.d.ts +30 -0
- package/dist/render/data-cache.js +37 -0
- package/dist/render/data-cache.js.map +1 -0
- package/dist/render/derive-dark-theme.d.ts +17 -0
- package/dist/render/derive-dark-theme.js +18 -0
- package/dist/render/derive-dark-theme.js.map +1 -0
- package/dist/render/dynamic-artifact-context.d.ts +77 -0
- package/dist/render/dynamic-artifact-context.js +89 -0
- package/dist/render/dynamic-artifact-context.js.map +1 -0
- package/dist/render/dynamic-block-loader.d.ts +80 -0
- package/dist/render/dynamic-block-loader.js +197 -0
- package/dist/render/dynamic-block-loader.js.map +1 -0
- package/dist/render/endpoint.d.ts +18 -0
- package/dist/render/endpoint.js +109 -0
- package/dist/render/endpoint.js.map +1 -0
- package/dist/render/entity-facade-context.d.ts +34 -0
- package/dist/render/entity-facade-context.js +37 -0
- package/dist/render/entity-facade-context.js.map +1 -0
- package/dist/render/group-states-css.d.ts +41 -0
- package/dist/render/group-states-css.js +73 -0
- package/dist/render/group-states-css.js.map +1 -0
- package/dist/render/hooks/useSurfaceEvents.d.ts +8 -0
- package/dist/render/hooks/useSurfaceEvents.js +9 -0
- package/dist/render/hooks/useSurfaceEvents.js.map +1 -0
- package/dist/render/hooks/useSurfaceId.d.ts +8 -0
- package/dist/render/hooks/useSurfaceId.js +9 -0
- package/dist/render/hooks/useSurfaceId.js.map +1 -0
- package/dist/render/index.d.ts +48 -0
- package/dist/render/index.js +61 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/interaction-rule-engine.d.ts +12 -0
- package/dist/render/interaction-rule-engine.js +47 -0
- package/dist/render/interaction-rule-engine.js.map +1 -0
- package/dist/render/keyframes-css.d.ts +31 -0
- package/dist/render/keyframes-css.js +44 -0
- package/dist/render/keyframes-css.js.map +1 -0
- package/dist/render/query-state.d.ts +3 -0
- package/dist/render/query-state.js +70 -0
- package/dist/render/query-state.js.map +1 -0
- package/dist/render/renderer.d.ts +44 -0
- package/dist/render/renderer.js +937 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/render/resolve-expressions.d.ts +37 -0
- package/dist/render/resolve-expressions.js +309 -0
- package/dist/render/resolve-expressions.js.map +1 -0
- package/dist/render/responsive-style-css.d.ts +42 -0
- package/dist/render/responsive-style-css.js +123 -0
- package/dist/render/responsive-style-css.js.map +1 -0
- package/dist/render/responsive.d.ts +49 -0
- package/dist/render/responsive.js +99 -0
- package/dist/render/responsive.js.map +1 -0
- package/dist/render/scoped-css.d.ts +71 -0
- package/dist/render/scoped-css.js +102 -0
- package/dist/render/scoped-css.js.map +1 -0
- package/dist/render/shell-selection.d.ts +69 -0
- package/dist/render/shell-selection.js +117 -0
- package/dist/render/shell-selection.js.map +1 -0
- package/dist/render/states-css.d.ts +32 -0
- package/dist/render/states-css.js +63 -0
- package/dist/render/states-css.js.map +1 -0
- package/dist/render/surface-data-context.d.ts +18 -0
- package/dist/render/surface-data-context.js +21 -0
- package/dist/render/surface-data-context.js.map +1 -0
- package/dist/render/surface-event-bus.d.ts +19 -0
- package/dist/render/surface-event-bus.js +68 -0
- package/dist/render/surface-event-bus.js.map +1 -0
- package/dist/render/surface-event-context.d.ts +11 -0
- package/dist/render/surface-event-context.js +12 -0
- package/dist/render/surface-event-context.js.map +1 -0
- package/dist/render/surface-id-context.d.ts +8 -0
- package/dist/render/surface-id-context.js +9 -0
- package/dist/render/surface-id-context.js.map +1 -0
- package/dist/render/theme-utils.d.ts +14 -0
- package/dist/render/theme-utils.js +15 -0
- package/dist/render/theme-utils.js.map +1 -0
- package/dist/render/types.d.ts +282 -0
- package/dist/render/types.js +9 -0
- package/dist/render/types.js.map +1 -0
- package/dist/render/visibility-css.d.ts +42 -0
- package/dist/render/visibility-css.js +119 -0
- package/dist/render/visibility-css.js.map +1 -0
- package/dist/render/width-scope.d.ts +34 -0
- package/dist/render/width-scope.js +44 -0
- package/dist/render/width-scope.js.map +1 -0
- package/dist/render/write-only-sources.d.ts +33 -0
- package/dist/render/write-only-sources.js +99 -0
- package/dist/render/write-only-sources.js.map +1 -0
- package/dist/routing/index.d.ts +14 -0
- package/dist/routing/index.js +15 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/router.d.ts +42 -0
- package/dist/routing/router.js +218 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/routing/types.d.ts +124 -0
- package/dist/routing/types.js +9 -0
- package/dist/routing/types.js.map +1 -0
- package/dist/seo/generator.d.ts +39 -0
- package/dist/seo/generator.js +236 -0
- package/dist/seo/generator.js.map +1 -0
- package/dist/seo/index.d.ts +14 -0
- package/dist/seo/index.js +15 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/seo/types.d.ts +181 -0
- package/dist/seo/types.js +9 -0
- package/dist/seo/types.js.map +1 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.js +16 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/manager.d.ts +33 -0
- package/dist/state/manager.js +81 -0
- package/dist/state/manager.js.map +1 -0
- package/dist/state/store.d.ts +40 -0
- package/dist/state/store.js +145 -0
- package/dist/state/store.js.map +1 -0
- package/dist/state/types.d.ts +107 -0
- package/dist/state/types.js +9 -0
- package/dist/state/types.js.map +1 -0
- package/dist/surface/expression.d.ts +65 -0
- package/dist/surface/expression.js +179 -0
- package/dist/surface/expression.js.map +1 -0
- package/dist/surface/index.d.ts +32 -0
- package/dist/surface/index.js +25 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/surface/interpreter.d.ts +96 -0
- package/dist/surface/interpreter.js +231 -0
- package/dist/surface/interpreter.js.map +1 -0
- package/dist/surface/layout.d.ts +54 -0
- package/dist/surface/layout.js +288 -0
- package/dist/surface/layout.js.map +1 -0
- package/dist/surface/output.d.ts +90 -0
- package/dist/surface/output.js +104 -0
- package/dist/surface/output.js.map +1 -0
- package/dist/surface/primitives.d.ts +180 -0
- package/dist/surface/primitives.js +339 -0
- package/dist/surface/primitives.js.map +1 -0
- package/dist/surface/renderer.d.ts +96 -0
- package/dist/surface/renderer.js +190 -0
- package/dist/surface/renderer.js.map +1 -0
- package/dist/surface/schemas.d.ts +181 -0
- package/dist/surface/schemas.js +142 -0
- package/dist/surface/schemas.js.map +1 -0
- package/dist/surface/transforms.d.ts +144 -0
- package/dist/surface/transforms.js +120 -0
- package/dist/surface/transforms.js.map +1 -0
- package/dist/surface/types.d.ts +160 -0
- package/dist/surface/types.js +51 -0
- package/dist/surface/types.js.map +1 -0
- package/dist/surface/validation.d.ts +123 -0
- package/dist/surface/validation.js +147 -0
- package/dist/surface/validation.js.map +1 -0
- package/dist/validator.d.ts +55 -0
- package/dist/validator.js +100 -0
- package/dist/validator.js.map +1 -0
- package/package.json +106 -3
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Store
|
|
3
|
+
*
|
|
4
|
+
* Uniform CRUD and query interface backed by connectors.
|
|
5
|
+
* The store handles validation and delegates persistence to connectors.
|
|
6
|
+
*
|
|
7
|
+
* @module @pwfabric/runtime/entity/store
|
|
8
|
+
*/
|
|
9
|
+
import { aggregateThrough } from './aggregate.js';
|
|
10
|
+
// ============================================================
|
|
11
|
+
// DEFAULT ENTITY STORE
|
|
12
|
+
// ============================================================
|
|
13
|
+
/**
|
|
14
|
+
* Default implementation of EntityStore.
|
|
15
|
+
* Validates through the registry and delegates persistence to connectors.
|
|
16
|
+
*
|
|
17
|
+
* Accepts an optional SurfaceEventBus. When provided, successful
|
|
18
|
+
* CRUD operations emit entity:created / entity:updated / entity:deleted events on
|
|
19
|
+
* the bus so that the rest of the surface can react declaratively.
|
|
20
|
+
*
|
|
21
|
+
* The bus is surface-scoped — the caller injects the bus for a
|
|
22
|
+
* specific surface, keeping the store surface-aware without making it globally coupled.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* The id of a record a connector just created. A record service may answer
|
|
26
|
+
* with the record itself (`{ id, … }`) or wrap it (`{ data: { id, … } }`, the
|
|
27
|
+
* shape the data protocol specifies); both are read.
|
|
28
|
+
*/
|
|
29
|
+
function createdIdOf(body) {
|
|
30
|
+
const own = body?.['id'];
|
|
31
|
+
if (typeof own === 'string' || typeof own === 'number')
|
|
32
|
+
return String(own);
|
|
33
|
+
const inner = body?.['data'];
|
|
34
|
+
if (inner && typeof inner === 'object' && !Array.isArray(inner)) {
|
|
35
|
+
const id = inner['id'];
|
|
36
|
+
if (typeof id === 'string' || typeof id === 'number')
|
|
37
|
+
return String(id);
|
|
38
|
+
}
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
export class DefaultEntityStore {
|
|
42
|
+
registry;
|
|
43
|
+
connectors;
|
|
44
|
+
eventBus;
|
|
45
|
+
constructor(registry, connectors, eventBus) {
|
|
46
|
+
this.registry = registry;
|
|
47
|
+
this.connectors = connectors;
|
|
48
|
+
this.eventBus = eventBus ?? undefined;
|
|
49
|
+
}
|
|
50
|
+
async create(entityType, data) {
|
|
51
|
+
// Validate entity type exists
|
|
52
|
+
if (!this.registry.has(entityType)) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
error: {
|
|
56
|
+
type: 'not_found',
|
|
57
|
+
message: `Entity type '${entityType}' is not registered`,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Validate data against schema
|
|
62
|
+
const validation = this.registry.validate(entityType, data);
|
|
63
|
+
if (!validation.valid) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
error: {
|
|
67
|
+
type: 'validation',
|
|
68
|
+
message: 'Validation failed',
|
|
69
|
+
details: validation.errors,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Resolve connector
|
|
74
|
+
const connector = this.connectors.resolve(entityType);
|
|
75
|
+
if (!connector) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: {
|
|
79
|
+
type: 'connector',
|
|
80
|
+
message: `No connector found for entity type '${entityType}'`,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Delegate to connector
|
|
85
|
+
const result = await connector.create(entityType, validation.data);
|
|
86
|
+
if (!result.success) {
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
error: {
|
|
90
|
+
type: 'connector',
|
|
91
|
+
message: result.error,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const mutationResult = {
|
|
96
|
+
success: true,
|
|
97
|
+
data: result.data,
|
|
98
|
+
id: createdIdOf(result.data),
|
|
99
|
+
};
|
|
100
|
+
// emit entity:created on the surface-scoped bus
|
|
101
|
+
if (this.eventBus) {
|
|
102
|
+
this.eventBus.emit({
|
|
103
|
+
type: 'entity:created',
|
|
104
|
+
surfaceId: 'system',
|
|
105
|
+
payload: {
|
|
106
|
+
entityType,
|
|
107
|
+
instanceId: mutationResult.id,
|
|
108
|
+
data: mutationResult.data,
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
},
|
|
111
|
+
timestamp: Date.now(),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return mutationResult;
|
|
115
|
+
}
|
|
116
|
+
async read(entityType, instanceId) {
|
|
117
|
+
// Validate entity type exists
|
|
118
|
+
if (!this.registry.has(entityType)) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
error: {
|
|
122
|
+
type: 'not_found',
|
|
123
|
+
message: `Entity type '${entityType}' is not registered`,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Resolve connector
|
|
128
|
+
const connector = this.connectors.resolve(entityType);
|
|
129
|
+
if (!connector) {
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
error: {
|
|
133
|
+
type: 'connector',
|
|
134
|
+
message: `No connector found for entity type '${entityType}'`,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// Delegate to connector
|
|
139
|
+
const result = await connector.read(entityType, instanceId);
|
|
140
|
+
if (!result.success) {
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
error: {
|
|
144
|
+
type: 'not_found',
|
|
145
|
+
message: result.error,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
success: true,
|
|
151
|
+
data: result.data,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async update(entityType, instanceId, data) {
|
|
155
|
+
// Validate entity type exists
|
|
156
|
+
if (!this.registry.has(entityType)) {
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: {
|
|
160
|
+
type: 'not_found',
|
|
161
|
+
message: `Entity type '${entityType}' is not registered`,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// Read existing record to merge with updates for validation
|
|
166
|
+
const connector = this.connectors.resolve(entityType);
|
|
167
|
+
if (!connector) {
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
error: {
|
|
171
|
+
type: 'connector',
|
|
172
|
+
message: `No connector found for entity type '${entityType}'`,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const existing = await connector.read(entityType, instanceId);
|
|
177
|
+
if (!existing.success) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: {
|
|
181
|
+
type: 'not_found',
|
|
182
|
+
message: existing.error,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// Merge existing data with updates for full validation
|
|
187
|
+
const merged = { ...existing.data, ...data };
|
|
188
|
+
const validation = this.registry.validate(entityType, merged);
|
|
189
|
+
if (!validation.valid) {
|
|
190
|
+
return {
|
|
191
|
+
success: false,
|
|
192
|
+
error: {
|
|
193
|
+
type: 'validation',
|
|
194
|
+
message: 'Validation failed',
|
|
195
|
+
details: validation.errors,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// Delegate to connector
|
|
200
|
+
const result = await connector.update(entityType, instanceId, data);
|
|
201
|
+
if (!result.success) {
|
|
202
|
+
return {
|
|
203
|
+
success: false,
|
|
204
|
+
error: {
|
|
205
|
+
type: 'connector',
|
|
206
|
+
message: result.error,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const updateResult = {
|
|
211
|
+
success: true,
|
|
212
|
+
data: result.data,
|
|
213
|
+
id: instanceId,
|
|
214
|
+
};
|
|
215
|
+
// emit entity:updated on the surface-scoped bus
|
|
216
|
+
if (this.eventBus) {
|
|
217
|
+
this.eventBus.emit({
|
|
218
|
+
type: 'entity:updated',
|
|
219
|
+
surfaceId: 'system',
|
|
220
|
+
payload: {
|
|
221
|
+
entityType,
|
|
222
|
+
instanceId,
|
|
223
|
+
data: updateResult.data,
|
|
224
|
+
changeset: data,
|
|
225
|
+
timestamp: Date.now(),
|
|
226
|
+
},
|
|
227
|
+
timestamp: Date.now(),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
return updateResult;
|
|
231
|
+
}
|
|
232
|
+
async delete(entityType, instanceId) {
|
|
233
|
+
// Validate entity type exists
|
|
234
|
+
if (!this.registry.has(entityType)) {
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error: {
|
|
238
|
+
type: 'not_found',
|
|
239
|
+
message: `Entity type '${entityType}' is not registered`,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// Resolve connector
|
|
244
|
+
const connector = this.connectors.resolve(entityType);
|
|
245
|
+
if (!connector) {
|
|
246
|
+
return {
|
|
247
|
+
success: false,
|
|
248
|
+
error: {
|
|
249
|
+
type: 'connector',
|
|
250
|
+
message: `No connector found for entity type '${entityType}'`,
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
// Delegate to connector
|
|
255
|
+
const result = await connector.delete(entityType, instanceId);
|
|
256
|
+
if (!result.success) {
|
|
257
|
+
return {
|
|
258
|
+
success: false,
|
|
259
|
+
error: {
|
|
260
|
+
type: 'not_found',
|
|
261
|
+
message: result.error,
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const deleteResult = {
|
|
266
|
+
success: true,
|
|
267
|
+
data: result.data,
|
|
268
|
+
id: instanceId,
|
|
269
|
+
};
|
|
270
|
+
// emit entity:deleted on the surface-scoped bus
|
|
271
|
+
if (this.eventBus) {
|
|
272
|
+
this.eventBus.emit({
|
|
273
|
+
type: 'entity:deleted',
|
|
274
|
+
surfaceId: 'system',
|
|
275
|
+
payload: {
|
|
276
|
+
entityType,
|
|
277
|
+
instanceId,
|
|
278
|
+
timestamp: Date.now(),
|
|
279
|
+
},
|
|
280
|
+
timestamp: Date.now(),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
return deleteResult;
|
|
284
|
+
}
|
|
285
|
+
async query(entityType, query) {
|
|
286
|
+
// Validate entity type exists
|
|
287
|
+
if (!this.registry.has(entityType)) {
|
|
288
|
+
return {
|
|
289
|
+
items: [],
|
|
290
|
+
total: 0,
|
|
291
|
+
offset: 0,
|
|
292
|
+
limit: query.pagination?.limit ?? 50,
|
|
293
|
+
hasMore: false,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
// Resolve connector
|
|
297
|
+
const connector = this.connectors.resolve(entityType);
|
|
298
|
+
if (!connector) {
|
|
299
|
+
return {
|
|
300
|
+
items: [],
|
|
301
|
+
total: 0,
|
|
302
|
+
offset: 0,
|
|
303
|
+
limit: query.pagination?.limit ?? 50,
|
|
304
|
+
hasMore: false,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
// Delegate to connector
|
|
308
|
+
const result = await connector.query(entityType, query);
|
|
309
|
+
if (!result.success) {
|
|
310
|
+
return {
|
|
311
|
+
items: [],
|
|
312
|
+
total: 0,
|
|
313
|
+
offset: 0,
|
|
314
|
+
limit: query.pagination?.limit ?? 50,
|
|
315
|
+
hasMore: false,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
return result.result;
|
|
319
|
+
}
|
|
320
|
+
async aggregate(entityType, aggregate) {
|
|
321
|
+
// NOT the same as query. An empty list is an honest answer to "could not
|
|
322
|
+
// list"; `{ value: 0 }` is not an honest answer to "could not count" —
|
|
323
|
+
// a 403 would read as "0 people are coming". Reject, and the renderer
|
|
324
|
+
// binds `fallback` and `__errors.<id>` like any failed source.
|
|
325
|
+
if (!this.registry.has(entityType)) {
|
|
326
|
+
throw new Error(`Entity type '${String(entityType)}' is not registered`);
|
|
327
|
+
}
|
|
328
|
+
const connector = this.connectors.resolve(entityType);
|
|
329
|
+
if (!connector)
|
|
330
|
+
throw new Error(`No connector for entity type '${String(entityType)}'`);
|
|
331
|
+
const result = await aggregateThrough(connector, entityType, aggregate);
|
|
332
|
+
if (!result.success)
|
|
333
|
+
throw new Error(result.error);
|
|
334
|
+
return result.result;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// ============================================================
|
|
338
|
+
// FACTORY FUNCTION
|
|
339
|
+
// ============================================================
|
|
340
|
+
/**
|
|
341
|
+
* Create an entity store.
|
|
342
|
+
*
|
|
343
|
+
* Pass an optional `eventBus` to enable surface-scoped event
|
|
344
|
+
* emission on successful CRUD operations (entity:created, entity:updated, entity:deleted).
|
|
345
|
+
*/
|
|
346
|
+
export function createEntityStore(registry, connectors, eventBus) {
|
|
347
|
+
return new DefaultEntityStore(registry, connectors, eventBus);
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/entity/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Entity Store\n *\n * Uniform CRUD and query interface backed by connectors.\n * The store handles validation and delegates persistence to connectors.\n *\n * @module @pwfabric/runtime/entity/store\n */\n\nimport type {\n EntityTypeId,\n EntityInstanceId,\n EntityQuery,\n EntityQueryResult,\n EntityMutationResult,\n EntityReadResult,\n EntityAggregate,\n EntityAggregateResult,\n} from './types.js'\nimport { aggregateThrough } from './aggregate.js'\nimport type { EntityRegistry } from './registry.js'\nimport type { ConnectorRegistry } from './connector.js'\nimport type { SurfaceEventBus } from '@pwfabric/contracts'\n\n// ============================================================\n// ENTITY STORE INTERFACE\n// ============================================================\n\n/**\n * Entity store interface for CRUD operations\n */\nexport interface EntityStore {\n /**\n * Create a new entity instance\n */\n create(entityType: EntityTypeId, data: Record<string, unknown>): Promise<EntityMutationResult>\n\n /**\n * Read a single entity instance\n */\n read(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityReadResult>\n\n /**\n * Update an existing entity instance\n */\n update(\n entityType: EntityTypeId,\n instanceId: EntityInstanceId,\n data: Record<string, unknown>\n ): Promise<EntityMutationResult>\n\n /**\n * Delete an entity instance\n */\n delete(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityMutationResult>\n\n /**\n * Query entity instances\n */\n query(entityType: EntityTypeId, query: EntityQuery): Promise<EntityQueryResult>\n\n /**\n * One number over the collection. Server-side when the connector\n * can; otherwise the connector's rows are reduced in memory. REJECTS when\n * the number cannot be served — unlike `query`, whose honest failure is an\n * empty list, a counter's `0` would be a lie.\n *\n * OPTIONAL so a host-written `EntityStore` keeps compiling; the facade\n * lists and reduces through `query` when a store has none.\n */\n aggregate?(entityType: EntityTypeId, aggregate: EntityAggregate): Promise<EntityAggregateResult>\n}\n\n// ============================================================\n// DEFAULT ENTITY STORE\n// ============================================================\n\n/**\n * Default implementation of EntityStore.\n * Validates through the registry and delegates persistence to connectors.\n *\n * Accepts an optional SurfaceEventBus. When provided, successful\n * CRUD operations emit entity:created / entity:updated / entity:deleted events on\n * the bus so that the rest of the surface can react declaratively.\n *\n * The bus is surface-scoped — the caller injects the bus for a\n * specific surface, keeping the store surface-aware without making it globally coupled.\n */\n/**\n * The id of a record a connector just created. A record service may answer\n * with the record itself (`{ id, … }`) or wrap it (`{ data: { id, … } }`, the\n * shape the data protocol specifies); both are read.\n */\nfunction createdIdOf(body: Record<string, unknown> | undefined): EntityInstanceId {\n const own = body?.['id']\n if (typeof own === 'string' || typeof own === 'number') return String(own) as EntityInstanceId\n const inner = body?.['data']\n if (inner && typeof inner === 'object' && !Array.isArray(inner)) {\n const id = (inner as Record<string, unknown>)['id']\n if (typeof id === 'string' || typeof id === 'number') return String(id) as EntityInstanceId\n }\n return '' as EntityInstanceId\n}\n\nexport class DefaultEntityStore implements EntityStore {\n private readonly registry: EntityRegistry\n private readonly connectors: ConnectorRegistry\n private readonly eventBus: SurfaceEventBus | undefined\n\n constructor(registry: EntityRegistry, connectors: ConnectorRegistry, eventBus?: SurfaceEventBus) {\n this.registry = registry\n this.connectors = connectors\n this.eventBus = eventBus ?? undefined\n }\n\n async create(\n entityType: EntityTypeId,\n data: Record<string, unknown>\n ): Promise<EntityMutationResult> {\n // Validate entity type exists\n if (!this.registry.has(entityType)) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: `Entity type '${entityType}' is not registered`,\n },\n }\n }\n\n // Validate data against schema\n const validation = this.registry.validate(entityType, data)\n if (!validation.valid) {\n return {\n success: false,\n error: {\n type: 'validation',\n message: 'Validation failed',\n details: validation.errors,\n },\n }\n }\n\n // Resolve connector\n const connector = this.connectors.resolve(entityType)\n if (!connector) {\n return {\n success: false,\n error: {\n type: 'connector',\n message: `No connector found for entity type '${entityType}'`,\n },\n }\n }\n\n // Delegate to connector\n const result = await connector.create(entityType, validation.data)\n if (!result.success) {\n return {\n success: false,\n error: {\n type: 'connector',\n message: result.error,\n },\n }\n }\n\n const mutationResult: EntityMutationResult = {\n success: true,\n data: result.data,\n id: createdIdOf(result.data),\n }\n\n // emit entity:created on the surface-scoped bus\n if (this.eventBus) {\n this.eventBus.emit({\n type: 'entity:created',\n surfaceId: 'system',\n payload: {\n entityType,\n instanceId: mutationResult.id,\n data: mutationResult.data,\n timestamp: Date.now(),\n },\n timestamp: Date.now(),\n })\n }\n\n return mutationResult\n }\n\n async read(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityReadResult> {\n // Validate entity type exists\n if (!this.registry.has(entityType)) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: `Entity type '${entityType}' is not registered`,\n },\n }\n }\n\n // Resolve connector\n const connector = this.connectors.resolve(entityType)\n if (!connector) {\n return {\n success: false,\n error: {\n type: 'connector',\n message: `No connector found for entity type '${entityType}'`,\n },\n }\n }\n\n // Delegate to connector\n const result = await connector.read(entityType, instanceId)\n if (!result.success) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: result.error,\n },\n }\n }\n\n return {\n success: true,\n data: result.data,\n }\n }\n\n async update(\n entityType: EntityTypeId,\n instanceId: EntityInstanceId,\n data: Record<string, unknown>\n ): Promise<EntityMutationResult> {\n // Validate entity type exists\n if (!this.registry.has(entityType)) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: `Entity type '${entityType}' is not registered`,\n },\n }\n }\n\n // Read existing record to merge with updates for validation\n const connector = this.connectors.resolve(entityType)\n if (!connector) {\n return {\n success: false,\n error: {\n type: 'connector',\n message: `No connector found for entity type '${entityType}'`,\n },\n }\n }\n\n const existing = await connector.read(entityType, instanceId)\n if (!existing.success) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: existing.error,\n },\n }\n }\n\n // Merge existing data with updates for full validation\n const merged = { ...existing.data, ...data }\n const validation = this.registry.validate(entityType, merged)\n if (!validation.valid) {\n return {\n success: false,\n error: {\n type: 'validation',\n message: 'Validation failed',\n details: validation.errors,\n },\n }\n }\n\n // Delegate to connector\n const result = await connector.update(entityType, instanceId, data)\n if (!result.success) {\n return {\n success: false,\n error: {\n type: 'connector',\n message: result.error,\n },\n }\n }\n\n const updateResult: EntityMutationResult = {\n success: true,\n data: result.data,\n id: instanceId,\n }\n\n // emit entity:updated on the surface-scoped bus\n if (this.eventBus) {\n this.eventBus.emit({\n type: 'entity:updated',\n surfaceId: 'system',\n payload: {\n entityType,\n instanceId,\n data: updateResult.data,\n changeset: data,\n timestamp: Date.now(),\n },\n timestamp: Date.now(),\n })\n }\n\n return updateResult\n }\n\n async delete(\n entityType: EntityTypeId,\n instanceId: EntityInstanceId\n ): Promise<EntityMutationResult> {\n // Validate entity type exists\n if (!this.registry.has(entityType)) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: `Entity type '${entityType}' is not registered`,\n },\n }\n }\n\n // Resolve connector\n const connector = this.connectors.resolve(entityType)\n if (!connector) {\n return {\n success: false,\n error: {\n type: 'connector',\n message: `No connector found for entity type '${entityType}'`,\n },\n }\n }\n\n // Delegate to connector\n const result = await connector.delete(entityType, instanceId)\n if (!result.success) {\n return {\n success: false,\n error: {\n type: 'not_found',\n message: result.error,\n },\n }\n }\n\n const deleteResult: EntityMutationResult = {\n success: true,\n data: result.data,\n id: instanceId,\n }\n\n // emit entity:deleted on the surface-scoped bus\n if (this.eventBus) {\n this.eventBus.emit({\n type: 'entity:deleted',\n surfaceId: 'system',\n payload: {\n entityType,\n instanceId,\n timestamp: Date.now(),\n },\n timestamp: Date.now(),\n })\n }\n\n return deleteResult\n }\n\n async query(entityType: EntityTypeId, query: EntityQuery): Promise<EntityQueryResult> {\n // Validate entity type exists\n if (!this.registry.has(entityType)) {\n return {\n items: [],\n total: 0,\n offset: 0,\n limit: query.pagination?.limit ?? 50,\n hasMore: false,\n }\n }\n\n // Resolve connector\n const connector = this.connectors.resolve(entityType)\n if (!connector) {\n return {\n items: [],\n total: 0,\n offset: 0,\n limit: query.pagination?.limit ?? 50,\n hasMore: false,\n }\n }\n\n // Delegate to connector\n const result = await connector.query(entityType, query)\n if (!result.success) {\n return {\n items: [],\n total: 0,\n offset: 0,\n limit: query.pagination?.limit ?? 50,\n hasMore: false,\n }\n }\n\n return result.result\n }\n\n async aggregate(entityType: EntityTypeId, aggregate: EntityAggregate): Promise<EntityAggregateResult> {\n // NOT the same as query. An empty list is an honest answer to \"could not\n // list\"; `{ value: 0 }` is not an honest answer to \"could not count\" —\n // a 403 would read as \"0 people are coming\". Reject, and the renderer\n // binds `fallback` and `__errors.<id>` like any failed source.\n if (!this.registry.has(entityType)) {\n throw new Error(`Entity type '${String(entityType)}' is not registered`)\n }\n const connector = this.connectors.resolve(entityType)\n if (!connector) throw new Error(`No connector for entity type '${String(entityType)}'`)\n const result = await aggregateThrough(connector, entityType, aggregate)\n if (!result.success) throw new Error(result.error)\n return result.result\n }\n}\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\n/**\n * Create an entity store.\n *\n * Pass an optional `eventBus` to enable surface-scoped event\n * emission on successful CRUD operations (entity:created, entity:updated, entity:deleted).\n */\nexport function createEntityStore(\n registry: EntityRegistry,\n connectors: ConnectorRegistry,\n eventBus?: SurfaceEventBus\n): EntityStore {\n return new DefaultEntityStore(registry, connectors, eventBus)\n}\n"]}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity System Types
|
|
3
|
+
*
|
|
4
|
+
* Entity system type definitions for schema-based entity types,
|
|
5
|
+
* CRUD operations, queries, and validation.
|
|
6
|
+
*
|
|
7
|
+
* @module @pwfabric/runtime/entity/types
|
|
8
|
+
*/
|
|
9
|
+
import type { z } from 'zod';
|
|
10
|
+
/**
|
|
11
|
+
* Branded string type for entity type identifiers
|
|
12
|
+
*/
|
|
13
|
+
export type EntityTypeId = string & {
|
|
14
|
+
readonly __brand: 'EntityTypeId';
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Branded string type for entity instance identifiers
|
|
18
|
+
*/
|
|
19
|
+
export type EntityInstanceId = string & {
|
|
20
|
+
readonly __brand: 'EntityInstanceId';
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Supported field types for entity definitions
|
|
24
|
+
*/
|
|
25
|
+
export type EntityFieldType = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'enum' | 'json' | 'reference';
|
|
26
|
+
/**
|
|
27
|
+
* Definition of a single field within an entity
|
|
28
|
+
*/
|
|
29
|
+
export interface EntityFieldDefinition {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly type: EntityFieldType;
|
|
32
|
+
readonly required: boolean;
|
|
33
|
+
readonly unique?: boolean;
|
|
34
|
+
readonly defaultValue?: unknown;
|
|
35
|
+
readonly enumValues?: readonly string[];
|
|
36
|
+
readonly referenceTarget?: EntityTypeId;
|
|
37
|
+
readonly validation?: z.ZodType;
|
|
38
|
+
readonly label?: string;
|
|
39
|
+
readonly description?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Supported relation types between entities
|
|
43
|
+
*/
|
|
44
|
+
export type EntityRelationType = 'has-one' | 'has-many' | 'belongs-to' | 'many-to-many';
|
|
45
|
+
/**
|
|
46
|
+
* Definition of a relation between entity types
|
|
47
|
+
*/
|
|
48
|
+
export interface EntityRelationDefinition {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
readonly type: EntityRelationType;
|
|
51
|
+
readonly target: EntityTypeId;
|
|
52
|
+
readonly foreignKey?: string;
|
|
53
|
+
readonly through?: EntityTypeId;
|
|
54
|
+
readonly cascade?: 'none' | 'delete' | 'nullify';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Complete definition of an entity type including fields, relations, and schema
|
|
58
|
+
*/
|
|
59
|
+
export interface EntityDefinition {
|
|
60
|
+
readonly id: EntityTypeId;
|
|
61
|
+
readonly name: string;
|
|
62
|
+
readonly description?: string;
|
|
63
|
+
readonly fields: readonly EntityFieldDefinition[];
|
|
64
|
+
readonly relations: readonly EntityRelationDefinition[];
|
|
65
|
+
readonly primaryKey: string;
|
|
66
|
+
readonly timestamps?: boolean;
|
|
67
|
+
readonly softDelete?: boolean;
|
|
68
|
+
readonly schema: z.ZodObject<z.ZodRawShape>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Entity query specification with optional filter, sort, and pagination
|
|
72
|
+
*/
|
|
73
|
+
export interface EntityQuery {
|
|
74
|
+
readonly filter?: EntityFilter;
|
|
75
|
+
readonly sort?: readonly EntitySortField[];
|
|
76
|
+
readonly pagination?: EntityPagination;
|
|
77
|
+
readonly include?: readonly string[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Filter condition for entity queries
|
|
81
|
+
*/
|
|
82
|
+
export interface EntityFilter {
|
|
83
|
+
readonly field: string;
|
|
84
|
+
readonly operator: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains' | 'startsWith';
|
|
85
|
+
readonly value: unknown;
|
|
86
|
+
readonly and?: readonly EntityFilter[];
|
|
87
|
+
readonly or?: readonly EntityFilter[];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Sort field specification
|
|
91
|
+
*/
|
|
92
|
+
export interface EntitySortField {
|
|
93
|
+
readonly field: string;
|
|
94
|
+
readonly direction: 'asc' | 'desc';
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Pagination parameters
|
|
98
|
+
*/
|
|
99
|
+
export interface EntityPagination {
|
|
100
|
+
readonly offset: number;
|
|
101
|
+
readonly limit: number;
|
|
102
|
+
}
|
|
103
|
+
/** One number over a collection: `count` needs no field, the rest reduce `field`. */
|
|
104
|
+
export type EntityAggregateFn = 'count' | 'sum' | 'avg';
|
|
105
|
+
/**
|
|
106
|
+
* An aggregate request — the source-level `aggregate` key. `filter`
|
|
107
|
+
* narrows the rows first, in the `EntityQuery.filter` shape.
|
|
108
|
+
*/
|
|
109
|
+
export interface EntityAggregate {
|
|
110
|
+
readonly fn: EntityAggregateFn;
|
|
111
|
+
readonly field?: string;
|
|
112
|
+
readonly filter?: EntityFilter;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* What an aggregate answers: `value` is the number (`null` when a numeric
|
|
116
|
+
* fn found nothing to reduce), `count` the rows the filter kept.
|
|
117
|
+
*/
|
|
118
|
+
export interface EntityAggregateResult {
|
|
119
|
+
readonly fn: EntityAggregateFn;
|
|
120
|
+
readonly field?: string;
|
|
121
|
+
readonly value: number | null;
|
|
122
|
+
readonly count: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Result of a paginated entity query
|
|
126
|
+
*/
|
|
127
|
+
export interface EntityQueryResult<T = Record<string, unknown>> {
|
|
128
|
+
readonly items: readonly T[];
|
|
129
|
+
readonly total: number;
|
|
130
|
+
readonly offset: number;
|
|
131
|
+
readonly limit: number;
|
|
132
|
+
readonly hasMore: boolean;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Result of a create or update mutation
|
|
136
|
+
*/
|
|
137
|
+
export type EntityMutationResult = {
|
|
138
|
+
readonly success: true;
|
|
139
|
+
readonly data: Record<string, unknown>;
|
|
140
|
+
readonly id: EntityInstanceId;
|
|
141
|
+
} | {
|
|
142
|
+
readonly success: false;
|
|
143
|
+
readonly error: EntityOperationError;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Result of a read operation
|
|
147
|
+
*/
|
|
148
|
+
export type EntityReadResult = {
|
|
149
|
+
readonly success: true;
|
|
150
|
+
readonly data: Record<string, unknown>;
|
|
151
|
+
} | {
|
|
152
|
+
readonly success: false;
|
|
153
|
+
readonly error: EntityOperationError;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Error descriptor for entity operations
|
|
157
|
+
*/
|
|
158
|
+
export interface EntityOperationError {
|
|
159
|
+
readonly type: 'not_found' | 'validation' | 'conflict' | 'connector' | 'unauthorized' | 'unknown';
|
|
160
|
+
readonly message: string;
|
|
161
|
+
readonly details?: unknown;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Result of entity validation (discriminated union)
|
|
165
|
+
*/
|
|
166
|
+
export type EntityValidationResult = {
|
|
167
|
+
readonly valid: true;
|
|
168
|
+
readonly data: Record<string, unknown>;
|
|
169
|
+
} | {
|
|
170
|
+
readonly valid: false;
|
|
171
|
+
readonly errors: readonly EntityValidationError[];
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Single field validation error
|
|
175
|
+
*/
|
|
176
|
+
export interface EntityValidationError {
|
|
177
|
+
readonly field: string;
|
|
178
|
+
readonly message: string;
|
|
179
|
+
readonly code: string;
|
|
180
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/entity/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG","sourcesContent":["/**\n * Entity System Types\n *\n * Entity system type definitions for schema-based entity types,\n * CRUD operations, queries, and validation.\n *\n * @module @pwfabric/runtime/entity/types\n */\n\nimport type { z } from 'zod'\n\n// ============================================================\n// BRANDED IDENTIFIERS\n// ============================================================\n\n/**\n * Branded string type for entity type identifiers\n */\nexport type EntityTypeId = string & { readonly __brand: 'EntityTypeId' }\n\n/**\n * Branded string type for entity instance identifiers\n */\nexport type EntityInstanceId = string & { readonly __brand: 'EntityInstanceId' }\n\n// ============================================================\n// ENTITY FIELD DEFINITIONS\n// ============================================================\n\n/**\n * Supported field types for entity definitions\n */\nexport type EntityFieldType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'date'\n | 'datetime'\n | 'enum'\n | 'json'\n | 'reference'\n\n/**\n * Definition of a single field within an entity\n */\nexport interface EntityFieldDefinition {\n readonly name: string\n readonly type: EntityFieldType\n readonly required: boolean\n readonly unique?: boolean\n readonly defaultValue?: unknown\n readonly enumValues?: readonly string[]\n readonly referenceTarget?: EntityTypeId\n readonly validation?: z.ZodType\n readonly label?: string\n readonly description?: string\n}\n\n// ============================================================\n// ENTITY RELATION DEFINITIONS\n// ============================================================\n\n/**\n * Supported relation types between entities\n */\nexport type EntityRelationType = 'has-one' | 'has-many' | 'belongs-to' | 'many-to-many'\n\n/**\n * Definition of a relation between entity types\n */\nexport interface EntityRelationDefinition {\n readonly name: string\n readonly type: EntityRelationType\n readonly target: EntityTypeId\n readonly foreignKey?: string\n readonly through?: EntityTypeId\n readonly cascade?: 'none' | 'delete' | 'nullify'\n}\n\n// ============================================================\n// ENTITY DEFINITION\n// ============================================================\n\n/**\n * Complete definition of an entity type including fields, relations, and schema\n */\nexport interface EntityDefinition {\n readonly id: EntityTypeId\n readonly name: string\n readonly description?: string\n readonly fields: readonly EntityFieldDefinition[]\n readonly relations: readonly EntityRelationDefinition[]\n readonly primaryKey: string\n readonly timestamps?: boolean\n readonly softDelete?: boolean\n readonly schema: z.ZodObject<z.ZodRawShape>\n}\n\n// ============================================================\n// QUERY TYPES\n// ============================================================\n\n/**\n * Entity query specification with optional filter, sort, and pagination\n */\nexport interface EntityQuery {\n readonly filter?: EntityFilter\n readonly sort?: readonly EntitySortField[]\n readonly pagination?: EntityPagination\n readonly include?: readonly string[]\n}\n\n/**\n * Filter condition for entity queries\n */\nexport interface EntityFilter {\n readonly field: string\n readonly operator: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains' | 'startsWith'\n readonly value: unknown\n readonly and?: readonly EntityFilter[]\n readonly or?: readonly EntityFilter[]\n}\n\n/**\n * Sort field specification\n */\nexport interface EntitySortField {\n readonly field: string\n readonly direction: 'asc' | 'desc'\n}\n\n/**\n * Pagination parameters\n */\nexport interface EntityPagination {\n readonly offset: number\n readonly limit: number\n}\n\n/** One number over a collection: `count` needs no field, the rest reduce `field`. */\nexport type EntityAggregateFn = 'count' | 'sum' | 'avg'\n\n/**\n * An aggregate request — the source-level `aggregate` key. `filter`\n * narrows the rows first, in the `EntityQuery.filter` shape.\n */\nexport interface EntityAggregate {\n readonly fn: EntityAggregateFn\n readonly field?: string\n readonly filter?: EntityFilter\n}\n\n/**\n * What an aggregate answers: `value` is the number (`null` when a numeric\n * fn found nothing to reduce), `count` the rows the filter kept.\n */\nexport interface EntityAggregateResult {\n readonly fn: EntityAggregateFn\n readonly field?: string\n readonly value: number | null\n readonly count: number\n}\n\n/**\n * Result of a paginated entity query\n */\nexport interface EntityQueryResult<T = Record<string, unknown>> {\n readonly items: readonly T[]\n readonly total: number\n readonly offset: number\n readonly limit: number\n readonly hasMore: boolean\n}\n\n// ============================================================\n// OPERATION RESULTS (DISCRIMINATED UNIONS)\n// ============================================================\n\n/**\n * Result of a create or update mutation\n */\nexport type EntityMutationResult =\n | {\n readonly success: true\n readonly data: Record<string, unknown>\n readonly id: EntityInstanceId\n }\n | { readonly success: false; readonly error: EntityOperationError }\n\n/**\n * Result of a read operation\n */\nexport type EntityReadResult =\n | { readonly success: true; readonly data: Record<string, unknown> }\n | { readonly success: false; readonly error: EntityOperationError }\n\n/**\n * Error descriptor for entity operations\n */\nexport interface EntityOperationError {\n readonly type: 'not_found' | 'validation' | 'conflict' | 'connector' | 'unauthorized' | 'unknown'\n readonly message: string\n readonly details?: unknown\n}\n\n// ============================================================\n// VALIDATION TYPES\n// ============================================================\n\n/**\n * Result of entity validation (discriminated union)\n */\nexport type EntityValidationResult =\n | { readonly valid: true; readonly data: Record<string, unknown> }\n | { readonly valid: false; readonly errors: readonly EntityValidationError[] }\n\n/**\n * Single field validation error\n */\nexport interface EntityValidationError {\n readonly field: string\n readonly message: string\n readonly code: string\n}\n"]}
|