@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,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL Entity Connector
|
|
3
|
+
*
|
|
4
|
+
* Database connector for entity data persistence using Drizzle ORM.
|
|
5
|
+
* Implements the EntityConnector interface with PostgreSQL-specific query building.
|
|
6
|
+
*
|
|
7
|
+
* @module @pwfabric/runtime/entity/postgres-connector
|
|
8
|
+
*/
|
|
9
|
+
// ============================================================
|
|
10
|
+
// SQL BUILDER HELPERS
|
|
11
|
+
// ============================================================
|
|
12
|
+
function escapeIdentifier(name) {
|
|
13
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
14
|
+
}
|
|
15
|
+
function buildFilterClause(filter, params, offset) {
|
|
16
|
+
const parts = [];
|
|
17
|
+
let currentOffset = offset;
|
|
18
|
+
if (filter.field && filter.operator) {
|
|
19
|
+
const col = escapeIdentifier(filter.field);
|
|
20
|
+
const paramIndex = currentOffset + 1;
|
|
21
|
+
currentOffset++;
|
|
22
|
+
switch (filter.operator) {
|
|
23
|
+
case 'eq':
|
|
24
|
+
parts.push(`${col} = $${paramIndex}`);
|
|
25
|
+
params.push(filter.value);
|
|
26
|
+
break;
|
|
27
|
+
case 'neq':
|
|
28
|
+
parts.push(`${col} != $${paramIndex}`);
|
|
29
|
+
params.push(filter.value);
|
|
30
|
+
break;
|
|
31
|
+
case 'gt':
|
|
32
|
+
parts.push(`${col} > $${paramIndex}`);
|
|
33
|
+
params.push(filter.value);
|
|
34
|
+
break;
|
|
35
|
+
case 'gte':
|
|
36
|
+
parts.push(`${col} >= $${paramIndex}`);
|
|
37
|
+
params.push(filter.value);
|
|
38
|
+
break;
|
|
39
|
+
case 'lt':
|
|
40
|
+
parts.push(`${col} < $${paramIndex}`);
|
|
41
|
+
params.push(filter.value);
|
|
42
|
+
break;
|
|
43
|
+
case 'lte':
|
|
44
|
+
parts.push(`${col} <= $${paramIndex}`);
|
|
45
|
+
params.push(filter.value);
|
|
46
|
+
break;
|
|
47
|
+
case 'in':
|
|
48
|
+
parts.push(`${col} = ANY($${paramIndex})`);
|
|
49
|
+
params.push(filter.value);
|
|
50
|
+
break;
|
|
51
|
+
case 'contains':
|
|
52
|
+
parts.push(`${col} ILIKE $${paramIndex}`);
|
|
53
|
+
params.push(`%${filter.value}%`);
|
|
54
|
+
break;
|
|
55
|
+
case 'startsWith':
|
|
56
|
+
parts.push(`${col} ILIKE $${paramIndex}`);
|
|
57
|
+
params.push(`${filter.value}%`);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (filter.and && filter.and.length > 0) {
|
|
62
|
+
for (const sub of filter.and) {
|
|
63
|
+
const result = buildFilterClause(sub, params, currentOffset);
|
|
64
|
+
parts.push(result.sql);
|
|
65
|
+
currentOffset = result.nextOffset;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (filter.or && filter.or.length > 0) {
|
|
69
|
+
const orParts = [];
|
|
70
|
+
for (const sub of filter.or) {
|
|
71
|
+
const result = buildFilterClause(sub, params, currentOffset);
|
|
72
|
+
orParts.push(result.sql);
|
|
73
|
+
currentOffset = result.nextOffset;
|
|
74
|
+
}
|
|
75
|
+
if (orParts.length > 0) {
|
|
76
|
+
parts.push(`(${orParts.join(' OR ')})`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
sql: parts.length > 0 ? parts.join(' AND ') : '1=1',
|
|
81
|
+
nextOffset: currentOffset,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function buildOrderClause(sort) {
|
|
85
|
+
if (sort.length === 0)
|
|
86
|
+
return '';
|
|
87
|
+
const parts = sort.map((s) => `${escapeIdentifier(s.field)} ${s.direction === 'desc' ? 'DESC' : 'ASC'}`);
|
|
88
|
+
return ` ORDER BY ${parts.join(', ')}`;
|
|
89
|
+
}
|
|
90
|
+
// ============================================================
|
|
91
|
+
// POSTGRES ENTITY CONNECTOR
|
|
92
|
+
// ============================================================
|
|
93
|
+
/**
|
|
94
|
+
* PostgreSQL connector for entity data operations.
|
|
95
|
+
* Maps entity CRUD operations to SQL queries via a DatabaseAdapter.
|
|
96
|
+
*/
|
|
97
|
+
export class PostgresEntityConnector {
|
|
98
|
+
name;
|
|
99
|
+
type = 'database';
|
|
100
|
+
db;
|
|
101
|
+
tablePrefix;
|
|
102
|
+
defaultPageSize;
|
|
103
|
+
maxPageSize;
|
|
104
|
+
constructor(name, config) {
|
|
105
|
+
this.name = name;
|
|
106
|
+
this.tablePrefix = config.tablePrefix ?? '';
|
|
107
|
+
this.defaultPageSize = config.defaultPageSize ?? 50;
|
|
108
|
+
this.maxPageSize = config.maxPageSize ?? 1000;
|
|
109
|
+
if (typeof config.connection === 'string') {
|
|
110
|
+
throw new Error('String connection not yet supported. Pass a DatabaseAdapter instance. ' +
|
|
111
|
+
'Use createDatabaseAdapter() from your Drizzle setup.');
|
|
112
|
+
}
|
|
113
|
+
this.db = config.connection;
|
|
114
|
+
}
|
|
115
|
+
tableName(entityType) {
|
|
116
|
+
return escapeIdentifier(`${this.tablePrefix}${entityType}`);
|
|
117
|
+
}
|
|
118
|
+
async create(entityType, data) {
|
|
119
|
+
try {
|
|
120
|
+
const table = this.tableName(entityType);
|
|
121
|
+
const keys = Object.keys(data);
|
|
122
|
+
const cols = keys.map(escapeIdentifier).join(', ');
|
|
123
|
+
const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ');
|
|
124
|
+
const values = keys.map((k) => data[k]);
|
|
125
|
+
const sql = `INSERT INTO ${table} (${cols}) VALUES (${placeholders}) RETURNING *`;
|
|
126
|
+
const result = await this.db.execute(sql, values);
|
|
127
|
+
if (result.rows.length === 0) {
|
|
128
|
+
return { success: false, error: 'Insert returned no rows' };
|
|
129
|
+
}
|
|
130
|
+
return { success: true, data: result.rows[0] ?? {} };
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async read(entityType, instanceId) {
|
|
137
|
+
try {
|
|
138
|
+
const table = this.tableName(entityType);
|
|
139
|
+
const sql = `SELECT * FROM ${table} WHERE "id" = $1 LIMIT 1`;
|
|
140
|
+
const result = await this.db.execute(sql, [instanceId]);
|
|
141
|
+
if (result.rows.length === 0) {
|
|
142
|
+
return { success: false, error: `Entity ${entityType}/${instanceId} not found` };
|
|
143
|
+
}
|
|
144
|
+
return { success: true, data: result.rows[0] ?? {} };
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async update(entityType, instanceId, data) {
|
|
151
|
+
try {
|
|
152
|
+
const table = this.tableName(entityType);
|
|
153
|
+
const keys = Object.keys(data);
|
|
154
|
+
if (keys.length === 0) {
|
|
155
|
+
return this.read(entityType, instanceId);
|
|
156
|
+
}
|
|
157
|
+
const setClauses = keys.map((key, i) => `${escapeIdentifier(key)} = $${i + 1}`);
|
|
158
|
+
const values = [...keys.map((k) => data[k]), instanceId];
|
|
159
|
+
const sql = `UPDATE ${table} SET ${setClauses.join(', ')} WHERE "id" = $${keys.length + 1} RETURNING *`;
|
|
160
|
+
const result = await this.db.execute(sql, values);
|
|
161
|
+
if (result.rows.length === 0) {
|
|
162
|
+
return { success: false, error: `Entity ${entityType}/${instanceId} not found` };
|
|
163
|
+
}
|
|
164
|
+
return { success: true, data: result.rows[0] ?? {} };
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async delete(entityType, instanceId) {
|
|
171
|
+
try {
|
|
172
|
+
const table = this.tableName(entityType);
|
|
173
|
+
const sql = `DELETE FROM ${table} WHERE "id" = $1 RETURNING *`;
|
|
174
|
+
const result = await this.db.execute(sql, [instanceId]);
|
|
175
|
+
if (result.rows.length === 0) {
|
|
176
|
+
return { success: false, error: `Entity ${entityType}/${instanceId} not found` };
|
|
177
|
+
}
|
|
178
|
+
return { success: true, data: result.rows[0] ?? {} };
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async query(entityType, query) {
|
|
185
|
+
try {
|
|
186
|
+
const table = this.tableName(entityType);
|
|
187
|
+
const params = [];
|
|
188
|
+
let paramOffset = 0;
|
|
189
|
+
// WHERE clause
|
|
190
|
+
let whereClause = '';
|
|
191
|
+
if (query.filter) {
|
|
192
|
+
const filterResult = buildFilterClause(query.filter, params, paramOffset);
|
|
193
|
+
whereClause = ` WHERE ${filterResult.sql}`;
|
|
194
|
+
paramOffset = filterResult.nextOffset;
|
|
195
|
+
}
|
|
196
|
+
// COUNT query
|
|
197
|
+
const countSql = `SELECT COUNT(*) as count FROM ${table}${whereClause}`;
|
|
198
|
+
const countResult = await this.db.execute(countSql, [...params]);
|
|
199
|
+
const total = Number(countResult.rows[0]?.count ?? 0);
|
|
200
|
+
// ORDER clause
|
|
201
|
+
const orderClause = query.sort ? buildOrderClause(query.sort) : '';
|
|
202
|
+
// PAGINATION
|
|
203
|
+
const limit = Math.min(query.pagination?.limit ?? this.defaultPageSize, this.maxPageSize);
|
|
204
|
+
const offset = query.pagination?.offset ?? 0;
|
|
205
|
+
paramOffset++;
|
|
206
|
+
const limitParam = `$${paramOffset}`;
|
|
207
|
+
params.push(limit);
|
|
208
|
+
paramOffset++;
|
|
209
|
+
const offsetParam = `$${paramOffset}`;
|
|
210
|
+
params.push(offset);
|
|
211
|
+
// DATA query
|
|
212
|
+
const dataSql = `SELECT * FROM ${table}${whereClause}${orderClause} LIMIT ${limitParam} OFFSET ${offsetParam}`;
|
|
213
|
+
const dataResult = await this.db.execute(dataSql, params);
|
|
214
|
+
return {
|
|
215
|
+
success: true,
|
|
216
|
+
result: {
|
|
217
|
+
items: dataResult.rows,
|
|
218
|
+
total,
|
|
219
|
+
offset,
|
|
220
|
+
limit,
|
|
221
|
+
hasMore: total > offset + dataResult.rows.length,
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
return { success: false, error: err instanceof Error ? err.message : String(err) };
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ============================================================
|
|
231
|
+
// FACTORY
|
|
232
|
+
// ============================================================
|
|
233
|
+
/**
|
|
234
|
+
* Create a PostgreSQL entity connector
|
|
235
|
+
*/
|
|
236
|
+
export function createPostgresConnector(name, config) {
|
|
237
|
+
return new PostgresEntityConnector(name, config);
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=postgres-connector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-connector.js","sourceRoot":"","sources":["../../src/entity/postgres-connector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PostgreSQL Entity Connector\n *\n * Database connector for entity data persistence using Drizzle ORM.\n * Implements the EntityConnector interface with PostgreSQL-specific query building.\n *\n * @module @pwfabric/runtime/entity/postgres-connector\n */\n\nimport type {\n EntityTypeId,\n EntityInstanceId,\n EntityQuery,\n EntityFilter,\n EntitySortField,\n} from './types.js'\nimport type {\n EntityConnector,\n EntityConnectorType,\n ConnectorResult,\n ConnectorQueryResult,\n} from './connector.js'\n\n// ============================================================\n// CONFIGURATION\n// ============================================================\n\n/**\n * PostgreSQL connector configuration\n */\nexport interface PostgresConnectorConfig {\n /**\n * Database connection — either a connection string or a Drizzle db instance.\n * When a string, the connector will create its own connection.\n * When an object, it must implement the DatabaseAdapter interface.\n */\n readonly connection: string | DatabaseAdapter\n\n /** Optional table name prefix for multi-tenant isolation */\n readonly tablePrefix?: string\n\n /** Default page size for queries */\n readonly defaultPageSize?: number\n\n /** Maximum page size to prevent excessive queries */\n readonly maxPageSize?: number\n}\n\n/**\n * Minimal database adapter interface.\n * This abstracts over Drizzle ORM or any SQL-capable client.\n */\nexport interface DatabaseAdapter {\n execute(sql: string, params?: unknown[]): Promise<DatabaseResult>\n}\n\n/**\n * Result of a database query execution\n */\nexport interface DatabaseResult {\n readonly rows: Record<string, unknown>[]\n readonly rowCount: number\n}\n\n// ============================================================\n// SQL BUILDER HELPERS\n// ============================================================\n\nfunction escapeIdentifier(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`\n}\n\nfunction buildFilterClause(\n filter: EntityFilter,\n params: unknown[],\n offset: number\n): { sql: string; nextOffset: number } {\n const parts: string[] = []\n let currentOffset = offset\n\n if (filter.field && filter.operator) {\n const col = escapeIdentifier(filter.field)\n const paramIndex = currentOffset + 1\n currentOffset++\n\n switch (filter.operator) {\n case 'eq':\n parts.push(`${col} = $${paramIndex}`)\n params.push(filter.value)\n break\n case 'neq':\n parts.push(`${col} != $${paramIndex}`)\n params.push(filter.value)\n break\n case 'gt':\n parts.push(`${col} > $${paramIndex}`)\n params.push(filter.value)\n break\n case 'gte':\n parts.push(`${col} >= $${paramIndex}`)\n params.push(filter.value)\n break\n case 'lt':\n parts.push(`${col} < $${paramIndex}`)\n params.push(filter.value)\n break\n case 'lte':\n parts.push(`${col} <= $${paramIndex}`)\n params.push(filter.value)\n break\n case 'in':\n parts.push(`${col} = ANY($${paramIndex})`)\n params.push(filter.value)\n break\n case 'contains':\n parts.push(`${col} ILIKE $${paramIndex}`)\n params.push(`%${filter.value}%`)\n break\n case 'startsWith':\n parts.push(`${col} ILIKE $${paramIndex}`)\n params.push(`${filter.value}%`)\n break\n }\n }\n\n if (filter.and && filter.and.length > 0) {\n for (const sub of filter.and) {\n const result = buildFilterClause(sub, params, currentOffset)\n parts.push(result.sql)\n currentOffset = result.nextOffset\n }\n }\n\n if (filter.or && filter.or.length > 0) {\n const orParts: string[] = []\n for (const sub of filter.or) {\n const result = buildFilterClause(sub, params, currentOffset)\n orParts.push(result.sql)\n currentOffset = result.nextOffset\n }\n if (orParts.length > 0) {\n parts.push(`(${orParts.join(' OR ')})`)\n }\n }\n\n return {\n sql: parts.length > 0 ? parts.join(' AND ') : '1=1',\n nextOffset: currentOffset,\n }\n}\n\nfunction buildOrderClause(sort: readonly EntitySortField[]): string {\n if (sort.length === 0) return ''\n const parts = sort.map(\n (s) => `${escapeIdentifier(s.field)} ${s.direction === 'desc' ? 'DESC' : 'ASC'}`\n )\n return ` ORDER BY ${parts.join(', ')}`\n}\n\n// ============================================================\n// POSTGRES ENTITY CONNECTOR\n// ============================================================\n\n/**\n * PostgreSQL connector for entity data operations.\n * Maps entity CRUD operations to SQL queries via a DatabaseAdapter.\n */\nexport class PostgresEntityConnector implements EntityConnector {\n readonly name: string\n readonly type: EntityConnectorType = 'database'\n\n private readonly db: DatabaseAdapter\n private readonly tablePrefix: string\n private readonly defaultPageSize: number\n private readonly maxPageSize: number\n\n constructor(name: string, config: PostgresConnectorConfig) {\n this.name = name\n this.tablePrefix = config.tablePrefix ?? ''\n this.defaultPageSize = config.defaultPageSize ?? 50\n this.maxPageSize = config.maxPageSize ?? 1000\n\n if (typeof config.connection === 'string') {\n throw new Error(\n 'String connection not yet supported. Pass a DatabaseAdapter instance. ' +\n 'Use createDatabaseAdapter() from your Drizzle setup.'\n )\n }\n\n this.db = config.connection\n }\n\n private tableName(entityType: EntityTypeId): string {\n return escapeIdentifier(`${this.tablePrefix}${entityType}`)\n }\n\n async create(entityType: EntityTypeId, data: Record<string, unknown>): Promise<ConnectorResult> {\n try {\n const table = this.tableName(entityType)\n const keys = Object.keys(data)\n const cols = keys.map(escapeIdentifier).join(', ')\n const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ')\n const values = keys.map((k) => data[k])\n\n const sql = `INSERT INTO ${table} (${cols}) VALUES (${placeholders}) RETURNING *`\n const result = await this.db.execute(sql, values)\n\n if (result.rows.length === 0) {\n return { success: false, error: 'Insert returned no rows' }\n }\n\n return { success: true, data: result.rows[0] ?? {} }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n }\n\n async read(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<ConnectorResult> {\n try {\n const table = this.tableName(entityType)\n const sql = `SELECT * FROM ${table} WHERE \"id\" = $1 LIMIT 1`\n const result = await this.db.execute(sql, [instanceId])\n\n if (result.rows.length === 0) {\n return { success: false, error: `Entity ${entityType}/${instanceId} not found` }\n }\n\n return { success: true, data: result.rows[0] ?? {} }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n }\n\n async update(\n entityType: EntityTypeId,\n instanceId: EntityInstanceId,\n data: Record<string, unknown>\n ): Promise<ConnectorResult> {\n try {\n const table = this.tableName(entityType)\n const keys = Object.keys(data)\n\n if (keys.length === 0) {\n return this.read(entityType, instanceId)\n }\n\n const setClauses = keys.map((key, i) => `${escapeIdentifier(key)} = $${i + 1}`)\n const values = [...keys.map((k) => data[k]), instanceId]\n\n const sql = `UPDATE ${table} SET ${setClauses.join(', ')} WHERE \"id\" = $${keys.length + 1} RETURNING *`\n const result = await this.db.execute(sql, values)\n\n if (result.rows.length === 0) {\n return { success: false, error: `Entity ${entityType}/${instanceId} not found` }\n }\n\n return { success: true, data: result.rows[0] ?? {} }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n }\n\n async delete(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<ConnectorResult> {\n try {\n const table = this.tableName(entityType)\n const sql = `DELETE FROM ${table} WHERE \"id\" = $1 RETURNING *`\n const result = await this.db.execute(sql, [instanceId])\n\n if (result.rows.length === 0) {\n return { success: false, error: `Entity ${entityType}/${instanceId} not found` }\n }\n\n return { success: true, data: result.rows[0] ?? {} }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n }\n\n async query(entityType: EntityTypeId, query: EntityQuery): Promise<ConnectorQueryResult> {\n try {\n const table = this.tableName(entityType)\n const params: unknown[] = []\n let paramOffset = 0\n\n // WHERE clause\n let whereClause = ''\n if (query.filter) {\n const filterResult = buildFilterClause(query.filter, params, paramOffset)\n whereClause = ` WHERE ${filterResult.sql}`\n paramOffset = filterResult.nextOffset\n }\n\n // COUNT query\n const countSql = `SELECT COUNT(*) as count FROM ${table}${whereClause}`\n const countResult = await this.db.execute(countSql, [...params])\n const total = Number(countResult.rows[0]?.count ?? 0)\n\n // ORDER clause\n const orderClause = query.sort ? buildOrderClause(query.sort) : ''\n\n // PAGINATION\n const limit = Math.min(query.pagination?.limit ?? this.defaultPageSize, this.maxPageSize)\n const offset = query.pagination?.offset ?? 0\n paramOffset++\n const limitParam = `$${paramOffset}`\n params.push(limit)\n paramOffset++\n const offsetParam = `$${paramOffset}`\n params.push(offset)\n\n // DATA query\n const dataSql = `SELECT * FROM ${table}${whereClause}${orderClause} LIMIT ${limitParam} OFFSET ${offsetParam}`\n const dataResult = await this.db.execute(dataSql, params)\n\n return {\n success: true,\n result: {\n items: dataResult.rows,\n total,\n offset,\n limit,\n hasMore: total > offset + dataResult.rows.length,\n },\n }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n }\n}\n\n// ============================================================\n// FACTORY\n// ============================================================\n\n/**\n * Create a PostgreSQL entity connector\n */\nexport function createPostgresConnector(\n name: string,\n config: PostgresConnectorConfig\n): PostgresEntityConnector {\n return new PostgresEntityConnector(name, config)\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Registry
|
|
3
|
+
*
|
|
4
|
+
* Registration and lookup of entity definitions with Zod-based validation.
|
|
5
|
+
*
|
|
6
|
+
* @module @pwfabric/runtime/entity/registry
|
|
7
|
+
*/
|
|
8
|
+
import type { EntityTypeId, EntityDefinition, EntityValidationResult } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Registry for entity type definitions
|
|
11
|
+
*/
|
|
12
|
+
export interface EntityRegistry {
|
|
13
|
+
/**
|
|
14
|
+
* Register an entity definition
|
|
15
|
+
* @throws Error if definition with the same id is already registered
|
|
16
|
+
*/
|
|
17
|
+
register(definition: EntityDefinition): void;
|
|
18
|
+
/**
|
|
19
|
+
* Get an entity definition by id
|
|
20
|
+
*/
|
|
21
|
+
get(id: EntityTypeId): EntityDefinition | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Check if an entity definition is registered
|
|
24
|
+
*/
|
|
25
|
+
has(id: EntityTypeId): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* List all registered entity type ids
|
|
28
|
+
*/
|
|
29
|
+
list(): readonly EntityTypeId[];
|
|
30
|
+
/**
|
|
31
|
+
* Validate data against an entity definition's Zod schema
|
|
32
|
+
*/
|
|
33
|
+
validate(id: EntityTypeId, data: unknown): EntityValidationResult;
|
|
34
|
+
/**
|
|
35
|
+
* Remove an entity definition
|
|
36
|
+
*/
|
|
37
|
+
unregister(id: EntityTypeId): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Remove all entity definitions
|
|
40
|
+
*/
|
|
41
|
+
clear(): void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* In-memory implementation of EntityRegistry
|
|
45
|
+
*/
|
|
46
|
+
export declare class InMemoryEntityRegistry implements EntityRegistry {
|
|
47
|
+
private readonly definitions;
|
|
48
|
+
register(definition: EntityDefinition): void;
|
|
49
|
+
get(id: EntityTypeId): EntityDefinition | undefined;
|
|
50
|
+
has(id: EntityTypeId): boolean;
|
|
51
|
+
list(): readonly EntityTypeId[];
|
|
52
|
+
validate(id: EntityTypeId, data: unknown): EntityValidationResult;
|
|
53
|
+
unregister(id: EntityTypeId): boolean;
|
|
54
|
+
clear(): void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create an entity registry
|
|
58
|
+
*/
|
|
59
|
+
export declare function createEntityRegistry(): EntityRegistry;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity Registry
|
|
3
|
+
*
|
|
4
|
+
* Registration and lookup of entity definitions with Zod-based validation.
|
|
5
|
+
*
|
|
6
|
+
* @module @pwfabric/runtime/entity/registry
|
|
7
|
+
*/
|
|
8
|
+
// ============================================================
|
|
9
|
+
// IN-MEMORY ENTITY REGISTRY
|
|
10
|
+
// ============================================================
|
|
11
|
+
/**
|
|
12
|
+
* In-memory implementation of EntityRegistry
|
|
13
|
+
*/
|
|
14
|
+
export class InMemoryEntityRegistry {
|
|
15
|
+
definitions = new Map();
|
|
16
|
+
register(definition) {
|
|
17
|
+
if (!definition.id) {
|
|
18
|
+
throw new Error('Entity definition must have an id');
|
|
19
|
+
}
|
|
20
|
+
if (!definition.name) {
|
|
21
|
+
throw new Error('Entity definition must have a name');
|
|
22
|
+
}
|
|
23
|
+
if (!definition.schema) {
|
|
24
|
+
throw new Error('Entity definition must have a schema');
|
|
25
|
+
}
|
|
26
|
+
if (!definition.primaryKey) {
|
|
27
|
+
throw new Error('Entity definition must have a primaryKey');
|
|
28
|
+
}
|
|
29
|
+
if (this.definitions.has(definition.id)) {
|
|
30
|
+
throw new Error(`Entity type '${definition.id}' is already registered`);
|
|
31
|
+
}
|
|
32
|
+
this.definitions.set(definition.id, definition);
|
|
33
|
+
}
|
|
34
|
+
get(id) {
|
|
35
|
+
return this.definitions.get(id);
|
|
36
|
+
}
|
|
37
|
+
has(id) {
|
|
38
|
+
return this.definitions.has(id);
|
|
39
|
+
}
|
|
40
|
+
list() {
|
|
41
|
+
return Array.from(this.definitions.keys());
|
|
42
|
+
}
|
|
43
|
+
validate(id, data) {
|
|
44
|
+
const definition = this.definitions.get(id);
|
|
45
|
+
if (!definition) {
|
|
46
|
+
return {
|
|
47
|
+
valid: false,
|
|
48
|
+
errors: [
|
|
49
|
+
{
|
|
50
|
+
field: '_entity',
|
|
51
|
+
message: `Entity type '${id}' is not registered`,
|
|
52
|
+
code: 'entity_not_found',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const result = definition.schema.safeParse(data);
|
|
58
|
+
if (result.success) {
|
|
59
|
+
return {
|
|
60
|
+
valid: true,
|
|
61
|
+
data: result.data,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const errors = result.error.issues.map((issue) => ({
|
|
65
|
+
field: issue.path.join('.') || '_root',
|
|
66
|
+
message: issue.message,
|
|
67
|
+
code: issue.code,
|
|
68
|
+
}));
|
|
69
|
+
return {
|
|
70
|
+
valid: false,
|
|
71
|
+
errors,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
unregister(id) {
|
|
75
|
+
return this.definitions.delete(id);
|
|
76
|
+
}
|
|
77
|
+
clear() {
|
|
78
|
+
this.definitions.clear();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ============================================================
|
|
82
|
+
// FACTORY FUNCTION
|
|
83
|
+
// ============================================================
|
|
84
|
+
/**
|
|
85
|
+
* Create an entity registry
|
|
86
|
+
*/
|
|
87
|
+
export function createEntityRegistry() {
|
|
88
|
+
return new InMemoryEntityRegistry();
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/entity/registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Entity Registry\n *\n * Registration and lookup of entity definitions with Zod-based validation.\n *\n * @module @pwfabric/runtime/entity/registry\n */\n\nimport type {\n EntityTypeId,\n EntityDefinition,\n EntityValidationResult,\n EntityValidationError,\n} from './types.js'\n\n// ============================================================\n// ENTITY REGISTRY INTERFACE\n// ============================================================\n\n/**\n * Registry for entity type definitions\n */\nexport interface EntityRegistry {\n /**\n * Register an entity definition\n * @throws Error if definition with the same id is already registered\n */\n register(definition: EntityDefinition): void\n\n /**\n * Get an entity definition by id\n */\n get(id: EntityTypeId): EntityDefinition | undefined\n\n /**\n * Check if an entity definition is registered\n */\n has(id: EntityTypeId): boolean\n\n /**\n * List all registered entity type ids\n */\n list(): readonly EntityTypeId[]\n\n /**\n * Validate data against an entity definition's Zod schema\n */\n validate(id: EntityTypeId, data: unknown): EntityValidationResult\n\n /**\n * Remove an entity definition\n */\n unregister(id: EntityTypeId): boolean\n\n /**\n * Remove all entity definitions\n */\n clear(): void\n}\n\n// ============================================================\n// IN-MEMORY ENTITY REGISTRY\n// ============================================================\n\n/**\n * In-memory implementation of EntityRegistry\n */\nexport class InMemoryEntityRegistry implements EntityRegistry {\n private readonly definitions = new Map<EntityTypeId, EntityDefinition>()\n\n register(definition: EntityDefinition): void {\n if (!definition.id) {\n throw new Error('Entity definition must have an id')\n }\n\n if (!definition.name) {\n throw new Error('Entity definition must have a name')\n }\n\n if (!definition.schema) {\n throw new Error('Entity definition must have a schema')\n }\n\n if (!definition.primaryKey) {\n throw new Error('Entity definition must have a primaryKey')\n }\n\n if (this.definitions.has(definition.id)) {\n throw new Error(`Entity type '${definition.id}' is already registered`)\n }\n\n this.definitions.set(definition.id, definition)\n }\n\n get(id: EntityTypeId): EntityDefinition | undefined {\n return this.definitions.get(id)\n }\n\n has(id: EntityTypeId): boolean {\n return this.definitions.has(id)\n }\n\n list(): readonly EntityTypeId[] {\n return Array.from(this.definitions.keys())\n }\n\n validate(id: EntityTypeId, data: unknown): EntityValidationResult {\n const definition = this.definitions.get(id)\n if (!definition) {\n return {\n valid: false,\n errors: [\n {\n field: '_entity',\n message: `Entity type '${id}' is not registered`,\n code: 'entity_not_found',\n },\n ],\n }\n }\n\n const result = definition.schema.safeParse(data)\n\n if (result.success) {\n return {\n valid: true,\n data: result.data as Record<string, unknown>,\n }\n }\n\n const errors: EntityValidationError[] = result.error.issues.map((issue) => ({\n field: issue.path.join('.') || '_root',\n message: issue.message,\n code: issue.code,\n }))\n\n return {\n valid: false,\n errors,\n }\n }\n\n unregister(id: EntityTypeId): boolean {\n return this.definitions.delete(id)\n }\n\n clear(): void {\n this.definitions.clear()\n }\n}\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\n/**\n * Create an entity registry\n */\nexport function createEntityRegistry(): EntityRegistry {\n return new InMemoryEntityRegistry()\n}\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
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 type { EntityTypeId, EntityInstanceId, EntityQuery, EntityQueryResult, EntityMutationResult, EntityReadResult, EntityAggregate, EntityAggregateResult } from './types.js';
|
|
10
|
+
import type { EntityRegistry } from './registry.js';
|
|
11
|
+
import type { ConnectorRegistry } from './connector.js';
|
|
12
|
+
import type { SurfaceEventBus } from '@pwfabric/contracts';
|
|
13
|
+
/**
|
|
14
|
+
* Entity store interface for CRUD operations
|
|
15
|
+
*/
|
|
16
|
+
export interface EntityStore {
|
|
17
|
+
/**
|
|
18
|
+
* Create a new entity instance
|
|
19
|
+
*/
|
|
20
|
+
create(entityType: EntityTypeId, data: Record<string, unknown>): Promise<EntityMutationResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Read a single entity instance
|
|
23
|
+
*/
|
|
24
|
+
read(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityReadResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Update an existing entity instance
|
|
27
|
+
*/
|
|
28
|
+
update(entityType: EntityTypeId, instanceId: EntityInstanceId, data: Record<string, unknown>): Promise<EntityMutationResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Delete an entity instance
|
|
31
|
+
*/
|
|
32
|
+
delete(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityMutationResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Query entity instances
|
|
35
|
+
*/
|
|
36
|
+
query(entityType: EntityTypeId, query: EntityQuery): Promise<EntityQueryResult>;
|
|
37
|
+
/**
|
|
38
|
+
* One number over the collection. Server-side when the connector
|
|
39
|
+
* can; otherwise the connector's rows are reduced in memory. REJECTS when
|
|
40
|
+
* the number cannot be served — unlike `query`, whose honest failure is an
|
|
41
|
+
* empty list, a counter's `0` would be a lie.
|
|
42
|
+
*
|
|
43
|
+
* OPTIONAL so a host-written `EntityStore` keeps compiling; the facade
|
|
44
|
+
* lists and reduces through `query` when a store has none.
|
|
45
|
+
*/
|
|
46
|
+
aggregate?(entityType: EntityTypeId, aggregate: EntityAggregate): Promise<EntityAggregateResult>;
|
|
47
|
+
}
|
|
48
|
+
export declare class DefaultEntityStore implements EntityStore {
|
|
49
|
+
private readonly registry;
|
|
50
|
+
private readonly connectors;
|
|
51
|
+
private readonly eventBus;
|
|
52
|
+
constructor(registry: EntityRegistry, connectors: ConnectorRegistry, eventBus?: SurfaceEventBus);
|
|
53
|
+
create(entityType: EntityTypeId, data: Record<string, unknown>): Promise<EntityMutationResult>;
|
|
54
|
+
read(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityReadResult>;
|
|
55
|
+
update(entityType: EntityTypeId, instanceId: EntityInstanceId, data: Record<string, unknown>): Promise<EntityMutationResult>;
|
|
56
|
+
delete(entityType: EntityTypeId, instanceId: EntityInstanceId): Promise<EntityMutationResult>;
|
|
57
|
+
query(entityType: EntityTypeId, query: EntityQuery): Promise<EntityQueryResult>;
|
|
58
|
+
aggregate(entityType: EntityTypeId, aggregate: EntityAggregate): Promise<EntityAggregateResult>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create an entity store.
|
|
62
|
+
*
|
|
63
|
+
* Pass an optional `eventBus` to enable surface-scoped event
|
|
64
|
+
* emission on successful CRUD operations (entity:created, entity:updated, entity:deleted).
|
|
65
|
+
*/
|
|
66
|
+
export declare function createEntityStore(registry: EntityRegistry, connectors: ConnectorRegistry, eventBus?: SurfaceEventBus): EntityStore;
|