@konitif/workbench 0.285.7 → 0.285.9

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/README.md CHANGED
@@ -13,6 +13,7 @@ npm install @konitif/workbench
13
13
 
14
14
  - Workspace, layout, panel and shell contracts.
15
15
  - Tool and widget admission, registries and hosting adapters.
16
+ - Generic widget-zone visibility and placement-drop projection.
16
17
  - Runtime lifecycle, checkpoint, recovery and observability contracts.
17
18
  - Project preflight and repository-quality contracts.
18
19
  - Explicit workspace persistence, synchronization and surface ports.
@@ -60,4 +60,5 @@ export declare function transitionWorkbenchExperienceLifecycle<TMetadata>(input:
60
60
  experience: WorkbenchExperience<TMetadata>;
61
61
  expected: Exclude<ExperienceLifecycleStatus, 'tombstoned'>;
62
62
  next: ExperienceLifecycleStatus;
63
+ metadata?: TMetadata;
63
64
  }): ExperienceLifecycleResult<WorkbenchExperience<TMetadata>>;
@@ -83,7 +83,11 @@ export function transitionWorkbenchExperienceLifecycle(input) {
83
83
  if (!isAllowedTransition(input.experience.lifecycle, input.next)) {
84
84
  return refused('experience.lifecycle.status-conflict', '$.next', `Experience lifecycle cannot transition from ${input.experience.lifecycle} to ${input.next}.`, undefined, input.next);
85
85
  }
86
- return accepted({ ...input.experience, lifecycle: input.next });
86
+ return accepted({
87
+ ...input.experience,
88
+ lifecycle: input.next,
89
+ metadata: input.metadata ?? input.experience.metadata,
90
+ });
87
91
  }
88
92
  function isAllowedTransition(current, next) {
89
93
  return next === 'tombstoned'
@@ -38,5 +38,6 @@ export interface WorkbenchExperienceRepository<TMetadata = unknown, TSpecializat
38
38
  experienceId: ExperienceIdentity;
39
39
  expected: Exclude<ExperienceLifecycleStatus, 'tombstoned'>;
40
40
  next: ExperienceLifecycleStatus;
41
+ metadata?: TMetadata;
41
42
  }): Promise<WorkbenchExperienceRepositoryResult<WorkbenchExperience<TMetadata>>>;
42
43
  }
@@ -0,0 +1,15 @@
1
+ export type WorkbenchWidgetZoneProjectionReason = 'closed' | 'visible-content' | 'empty-edit-drop-target' | 'empty-runtime';
2
+ export interface WorkbenchWidgetZoneProjection {
3
+ visible: boolean;
4
+ acceptsPlacementDrop: boolean;
5
+ reason: WorkbenchWidgetZoneProjectionReason;
6
+ }
7
+ /**
8
+ * Projects an authored widget-zone state into host-facing visibility and drop
9
+ * affordances without owning either the zone content or its renderer.
10
+ */
11
+ export declare function projectWorkbenchWidgetZone(input: {
12
+ containerOpen: boolean;
13
+ visiblePlacementCount: number;
14
+ layoutEditingEnabled: boolean;
15
+ }): WorkbenchWidgetZoneProjection;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Projects an authored widget-zone state into host-facing visibility and drop
3
+ * affordances without owning either the zone content or its renderer.
4
+ */
5
+ export function projectWorkbenchWidgetZone(input) {
6
+ if (!input.containerOpen) {
7
+ return { visible: false, acceptsPlacementDrop: false, reason: 'closed' };
8
+ }
9
+ if (input.visiblePlacementCount > 0) {
10
+ return {
11
+ visible: true,
12
+ acceptsPlacementDrop: input.layoutEditingEnabled,
13
+ reason: 'visible-content'
14
+ };
15
+ }
16
+ if (input.layoutEditingEnabled) {
17
+ return { visible: true, acceptsPlacementDrop: true, reason: 'empty-edit-drop-target' };
18
+ }
19
+ return { visible: false, acceptsPlacementDrop: false, reason: 'empty-runtime' };
20
+ }
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./boot/index.js";
2
2
  export * from "./application/launch/workbenchLaunchPolicy.js";
3
3
  export * from "./application/launch/catalogShareReference.js";
4
4
  export * from "./application/widgets/createWorkbenchWidgetAdapter.js";
5
+ export * from "./application/widgets/widgetZoneProjection.js";
5
6
  export * from "./application/tool/experienceToolSelection.js";
6
7
  export * from "./stage/index.js";
7
8
  export * from "./application/shell/state.js";
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from "./boot/index.js";
2
2
  export * from "./application/launch/workbenchLaunchPolicy.js";
3
3
  export * from "./application/launch/catalogShareReference.js";
4
4
  export * from "./application/widgets/createWorkbenchWidgetAdapter.js";
5
+ export * from "./application/widgets/widgetZoneProjection.js";
5
6
  export * from "./application/tool/experienceToolSelection.js";
6
7
  export * from "./stage/index.js";
7
8
  export * from "./application/shell/state.js";
@@ -1,8 +1,11 @@
1
- import type { WorkbenchExperienceRepository } from "../../application/experience/experienceRepository.js";
1
+ import type { WorkbenchExperienceRepository, WorkbenchExperienceRepositoryResult, WorkbenchExperienceRepositorySnapshot } from "../../application/experience/experienceRepository.js";
2
2
  export interface BrowserExperienceRepositoryStorage {
3
3
  getItem(key: string): string | null;
4
4
  setItem(key: string, value: string): void;
5
5
  }
6
+ export interface BrowserWorkbenchExperienceRepository<TMetadata = unknown, TSpecialization = unknown> extends WorkbenchExperienceRepository<TMetadata, TSpecialization> {
7
+ initialize(snapshot: WorkbenchExperienceRepositorySnapshot<TMetadata, TSpecialization>): Promise<WorkbenchExperienceRepositoryResult<WorkbenchExperienceRepositorySnapshot<TMetadata, TSpecialization>>>;
8
+ }
6
9
  /**
7
10
  * Browser persistence adapter for the generic Workbench Experience authority.
8
11
  * Products choose the storage key and keep migration and specialization policy
@@ -11,4 +14,4 @@ export interface BrowserExperienceRepositoryStorage {
11
14
  export declare function createBrowserWorkbenchExperienceRepository<TMetadata = unknown, TSpecialization = unknown>(input: {
12
15
  storageKey: string;
13
16
  storage?: BrowserExperienceRepositoryStorage | null;
14
- }): WorkbenchExperienceRepository<TMetadata, TSpecialization>;
17
+ }): BrowserWorkbenchExperienceRepository<TMetadata, TSpecialization>;
@@ -10,6 +10,18 @@ export function createBrowserWorkbenchExperienceRepository(input) {
10
10
  const storageKey = requireStorageKey(input.storageKey);
11
11
  return {
12
12
  hydrate: () => hydrate(storage, storageKey),
13
+ async initialize(snapshot) {
14
+ const current = await hydrate(storage, storageKey);
15
+ if (!current.ok)
16
+ return current;
17
+ if (current.value.experiences.length > 0 || current.value.revisions.length > 0) {
18
+ return refused('experience.repository.already-exists', 'Browser Experience repository is already initialized.');
19
+ }
20
+ if (!isRepositorySnapshot(snapshot)) {
21
+ return refused('experience.repository.invalid-artifact', 'Initial Experience snapshot does not match the Workbench contract.');
22
+ }
23
+ return persist(storage, storageKey, snapshot);
24
+ },
13
25
  async list() {
14
26
  const snapshot = await hydrate(storage, storageKey);
15
27
  return snapshot.ok ? accepted(snapshot.value.experiences) : snapshot;
@@ -78,6 +90,7 @@ export function createBrowserWorkbenchExperienceRepository(input) {
78
90
  experience,
79
91
  expected: value.expected,
80
92
  next: value.next,
93
+ metadata: value.metadata,
81
94
  });
82
95
  if (!transitioned.ok)
83
96
  return lifecycleRefused(transitioned.diagnostics[0]);
@@ -141,6 +154,11 @@ function isStoredRepository(value) {
141
154
  || !Array.isArray(value.experiences)
142
155
  || !Array.isArray(value.revisions))
143
156
  return false;
157
+ return isRepositorySnapshot(value);
158
+ }
159
+ function isRepositorySnapshot(value) {
160
+ if (!isRecord(value) || !Array.isArray(value.experiences) || !Array.isArray(value.revisions))
161
+ return false;
144
162
  const experiences = value.experiences;
145
163
  const revisions = value.revisions;
146
164
  if (!experiences.every(isWorkbenchExperience) || !revisions.every(isWorkbenchExperienceRevision))
@@ -149,7 +167,9 @@ function isStoredRepository(value) {
149
167
  && isIdentity(revision.experienceId, 'experience')
150
168
  && isIdentity(revision.id, 'experience-revision')
151
169
  && revision.experienceId.value === experience.id.value
152
- && revision.id.value === experience.headRevisionId.value));
170
+ && revision.id.value === experience.headRevisionId.value)) && revisions.every(revision => experiences.some(experience => isRecord(revision)
171
+ && isIdentity(revision.experienceId, 'experience')
172
+ && revision.experienceId.value === experience.id.value));
153
173
  }
154
174
  function isWorkbenchExperience(value) {
155
175
  return isRecord(value)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@konitif/workbench",
3
3
  "license": "PolyForm-Noncommercial-1.0.0",
4
- "version": "0.285.7",
4
+ "version": "0.285.9",
5
5
  "description": "Workspace composition, docking, registries and hosting contracts for KONITIF.",
6
6
  "repository": {
7
7
  "type": "git",
@@ -107,7 +107,9 @@
107
107
  ],
108
108
  "symbolNames": [
109
109
  "createWorkbenchWidgetAdapter",
110
- "WorkbenchWidgetHosting"
110
+ "WorkbenchWidgetHosting",
111
+ "projectWorkbenchWidgetZone",
112
+ "WorkbenchWidgetZoneProjection"
111
113
  ]
112
114
  },
113
115
  {