@konitif/workbench 0.285.2 → 0.285.4

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
@@ -17,6 +17,8 @@ npm install @konitif/workbench
17
17
  - Project preflight and repository-quality contracts.
18
18
  - Explicit workspace persistence, synchronization and surface ports.
19
19
  - Content-addressed workspace usage bundles with strict host-context admission.
20
+ - Abstract Experience revisions that bind presets by immutable content reference
21
+ or by an explicit, traceable override.
20
22
 
21
23
  ## Authority boundary
22
24
 
@@ -31,6 +33,12 @@ content-addressed projection of a preset and its workspace, shell and focus
31
33
  fragments. Admission rejects altered content, incomplete fragments, incompatible
32
34
  host contexts and identity/revision conflicts.
33
35
 
36
+ An Experience is a Workbench authority: it records the stable identity and
37
+ revision lineage of an experimentation arrangement without absorbing the
38
+ domain that specializes it. A product can reference an authored workspace
39
+ preset unchanged or declare an override with ordered transformation records;
40
+ admission always verifies the referenced canonical content.
41
+
34
42
  ## Quick start
35
43
 
36
44
  ```ts
@@ -0,0 +1,79 @@
1
+ import type { WorkspacePresetArtifact } from "../workspace/presetArtifacts.js";
2
+ export declare const WORKBENCH_EXPERIENCE_SCHEMA: "konitif.workbench-experience";
3
+ export declare const WORKBENCH_EXPERIENCE_SCHEMA_VERSION: 1;
4
+ export interface ExperienceIdentity {
5
+ kind: 'experience';
6
+ value: string;
7
+ }
8
+ export interface ExperienceRevisionIdentity {
9
+ kind: 'experience-revision';
10
+ value: string;
11
+ }
12
+ export type ExperienceLifecycleStatus = 'active' | 'archived' | 'tombstoned';
13
+ export interface ExperienceContentAddressPort {
14
+ sha256(canonicalJson: string): Promise<string>;
15
+ }
16
+ export interface WorkspacePresetContentReference {
17
+ kind: 'workspace-preset';
18
+ id: string;
19
+ revision: string;
20
+ contentId: string;
21
+ }
22
+ export interface ExperienceTransformation {
23
+ order: number;
24
+ kind: string;
25
+ summary: string;
26
+ }
27
+ export type WorkspaceExperiencePresetBinding = {
28
+ mode: 'reference';
29
+ source: WorkspacePresetContentReference;
30
+ } | {
31
+ mode: 'override';
32
+ source: WorkspacePresetContentReference;
33
+ result: WorkspacePresetContentReference;
34
+ transformations: readonly ExperienceTransformation[];
35
+ };
36
+ export interface WorkbenchExperienceRevision<TSpecialization = unknown> {
37
+ schema: typeof WORKBENCH_EXPERIENCE_SCHEMA;
38
+ schemaVersion: typeof WORKBENCH_EXPERIENCE_SCHEMA_VERSION;
39
+ id: ExperienceRevisionIdentity;
40
+ experienceId: ExperienceIdentity;
41
+ parentRevisionId: ExperienceRevisionIdentity | null;
42
+ derivedFrom: ExperienceRevisionIdentity | null;
43
+ preset: WorkspaceExperiencePresetBinding;
44
+ specialization: TSpecialization;
45
+ }
46
+ export interface WorkbenchExperience<TMetadata = unknown> {
47
+ id: ExperienceIdentity;
48
+ headRevisionId: ExperienceRevisionIdentity;
49
+ lifecycle: ExperienceLifecycleStatus;
50
+ metadata: TMetadata;
51
+ }
52
+ export type ExperienceArtifactDiagnosticCode = 'experience.invalid-identity' | 'experience.invalid-content-id' | 'experience.preset-identity-conflict' | 'experience.preset-content-conflict' | 'experience.invalid-override';
53
+ export interface ExperienceArtifactDiagnostic {
54
+ code: ExperienceArtifactDiagnosticCode;
55
+ path: string;
56
+ message: string;
57
+ }
58
+ export type ExperienceArtifactResult<T> = {
59
+ ok: true;
60
+ value: T;
61
+ diagnostics: [];
62
+ } | {
63
+ ok: false;
64
+ diagnostics: ExperienceArtifactDiagnostic[];
65
+ };
66
+ export declare function defineExperienceIdentity(value: string): ExperienceIdentity;
67
+ export declare function defineExperienceRevisionIdentity(value: string): ExperienceRevisionIdentity;
68
+ export declare function createWorkspacePresetContentReference(artifact: WorkspacePresetArtifact, content: ExperienceContentAddressPort): Promise<WorkspacePresetContentReference>;
69
+ export declare function admitWorkspacePresetContentReference(reference: WorkspacePresetContentReference, artifact: WorkspacePresetArtifact, content: ExperienceContentAddressPort): Promise<ExperienceArtifactResult<WorkspacePresetContentReference>>;
70
+ export declare function createWorkspaceExperiencePresetBinding(input: {
71
+ source: WorkspacePresetArtifact;
72
+ result?: WorkspacePresetArtifact;
73
+ transformations?: readonly ExperienceTransformation[];
74
+ }, content: ExperienceContentAddressPort): Promise<ExperienceArtifactResult<WorkspaceExperiencePresetBinding>>;
75
+ export declare function admitWorkspaceExperiencePresetBinding(input: {
76
+ binding: WorkspaceExperiencePresetBinding;
77
+ source: WorkspacePresetArtifact;
78
+ result?: WorkspacePresetArtifact;
79
+ }, content: ExperienceContentAddressPort): Promise<ExperienceArtifactResult<WorkspaceExperiencePresetBinding>>;
@@ -0,0 +1,109 @@
1
+ import { serializeWorkspacePresetArtifact } from "../workspace/presetArtifacts.js";
2
+ export const WORKBENCH_EXPERIENCE_SCHEMA = 'konitif.workbench-experience';
3
+ export const WORKBENCH_EXPERIENCE_SCHEMA_VERSION = 1;
4
+ export function defineExperienceIdentity(value) {
5
+ return { kind: 'experience', value: requireIdentity(value, 'Experience') };
6
+ }
7
+ export function defineExperienceRevisionIdentity(value) {
8
+ return { kind: 'experience-revision', value: requireIdentity(value, 'Experience revision') };
9
+ }
10
+ export async function createWorkspacePresetContentReference(artifact, content) {
11
+ const contentId = await content.sha256(serializeWorkspacePresetArtifact(artifact));
12
+ if (!isContentId(contentId)) {
13
+ throw new TypeError('Workspace preset content addressing must return a lowercase SHA-256 digest.');
14
+ }
15
+ return freezeDetached({
16
+ kind: 'workspace-preset',
17
+ id: artifact.id,
18
+ revision: artifact.version,
19
+ contentId
20
+ });
21
+ }
22
+ export async function admitWorkspacePresetContentReference(reference, artifact, content) {
23
+ if (!isContentId(reference.contentId)) {
24
+ return refused('experience.invalid-content-id', '$.contentId', 'Workspace preset content identity must be a lowercase SHA-256 digest.');
25
+ }
26
+ if (reference.kind !== 'workspace-preset' || reference.id !== artifact.id || reference.revision !== artifact.version) {
27
+ return refused('experience.preset-identity-conflict', '$', 'Workspace preset identity and revision must match their immutable reference.');
28
+ }
29
+ const resolved = await createWorkspacePresetContentReference(artifact, content);
30
+ if (resolved.contentId !== reference.contentId) {
31
+ return refused('experience.preset-content-conflict', '$.contentId', 'Workspace preset reference is bound to different canonical content.');
32
+ }
33
+ return accepted(reference);
34
+ }
35
+ export async function createWorkspaceExperiencePresetBinding(input, content) {
36
+ const source = await createWorkspacePresetContentReference(input.source, content);
37
+ if (!input.result) {
38
+ return accepted(freezeDetached({ mode: 'reference', source }));
39
+ }
40
+ const transformations = normalizeTransformations(input.transformations ?? []);
41
+ if (!transformations) {
42
+ return refused('experience.invalid-override', '$.transformations', 'A workspace preset override requires ordered, non-empty transformation records.');
43
+ }
44
+ const result = await createWorkspacePresetContentReference(input.result, content);
45
+ if (source.contentId === result.contentId) {
46
+ return refused('experience.invalid-override', '$.result', 'A workspace preset override must produce content distinct from its source.');
47
+ }
48
+ return accepted(freezeDetached({ mode: 'override', source, result, transformations }));
49
+ }
50
+ export async function admitWorkspaceExperiencePresetBinding(input, content) {
51
+ const source = await admitWorkspacePresetContentReference(input.binding.source, input.source, content);
52
+ if (!source.ok)
53
+ return source;
54
+ if (input.binding.mode === 'reference') {
55
+ if (input.result) {
56
+ return refused('experience.invalid-override', '$.result', 'A reference binding cannot admit override content.');
57
+ }
58
+ return accepted(freezeDetached(input.binding));
59
+ }
60
+ const transformations = normalizeTransformations(input.binding.transformations);
61
+ if (!transformations || !input.result) {
62
+ return refused('experience.invalid-override', '$', 'An override binding requires its resolved result and ordered transformation records.');
63
+ }
64
+ const result = await admitWorkspacePresetContentReference(input.binding.result, input.result, content);
65
+ if (!result.ok)
66
+ return result;
67
+ if (input.binding.source.contentId === input.binding.result.contentId) {
68
+ return refused('experience.invalid-override', '$.result', 'A workspace preset override must produce content distinct from its source.');
69
+ }
70
+ return accepted(freezeDetached({ ...input.binding, transformations }));
71
+ }
72
+ function normalizeTransformations(values) {
73
+ if (values.length === 0)
74
+ return null;
75
+ const normalized = values.map((value, index) => ({
76
+ order: value.order,
77
+ kind: value.kind.trim(),
78
+ summary: value.summary.trim()
79
+ }));
80
+ if (normalized.some((value, index) => value.order !== index || !value.kind || !value.summary)) {
81
+ return null;
82
+ }
83
+ return freezeDetached(normalized);
84
+ }
85
+ function requireIdentity(value, label) {
86
+ const normalized = value.trim();
87
+ if (!normalized)
88
+ throw new TypeError(`${label} identity is required.`);
89
+ return normalized;
90
+ }
91
+ function isContentId(value) {
92
+ return /^[a-f0-9]{64}$/.test(value);
93
+ }
94
+ function accepted(value) {
95
+ return { ok: true, value: freezeDetached(value), diagnostics: [] };
96
+ }
97
+ function refused(code, path, message) {
98
+ return { ok: false, diagnostics: [{ code, path, message }] };
99
+ }
100
+ function freezeDetached(value) {
101
+ return deepFreeze(structuredClone(value));
102
+ }
103
+ function deepFreeze(value) {
104
+ if (!value || typeof value !== 'object' || Object.isFrozen(value))
105
+ return value;
106
+ for (const nested of Object.values(value))
107
+ deepFreeze(nested);
108
+ return Object.freeze(value);
109
+ }
@@ -1,7 +1,7 @@
1
1
  import { createPanel, createStack, createWorkspaceShell, createWorkspaceWindow } from "../../domain/workspace/factories.js";
2
2
  import { openTool } from "./openTool.js";
3
3
  export function createWorkspace(toolCatalog, options = {}) {
4
- const initialPanel = createPanel('Welcome');
4
+ const initialPanel = createPanel();
5
5
  const initialStack = createStack([initialPanel]);
6
6
  const initialWindow = createWorkspaceWindow(initialStack);
7
7
  const workspace = createWorkspaceShell(initialWindow);
@@ -1,10 +1,9 @@
1
1
  import { createWorkspaceSessionState } from "./session.js";
2
2
  import { createWorkspace } from "./createWorkspace.js";
3
- const DEFAULT_WORKSPACE_INITIAL_TOOL_ID = 'example.welcome';
4
3
  export function createWorkspaceFromPreset(toolCatalog, presetId = 'default') {
5
4
  switch (presetId) {
6
5
  case 'default':
7
- return createWorkspace(toolCatalog, { initialToolId: DEFAULT_WORKSPACE_INITIAL_TOOL_ID });
6
+ return createWorkspace(toolCatalog);
8
7
  }
9
8
  }
10
9
  export function createWorkspaceSessionFromPreset(toolCatalog, presetId = 'default') {
@@ -15,7 +15,7 @@ export function unassignTool(workspace, toolId) {
15
15
  ...window,
16
16
  root: updatePanelById(window.root, panel.id, current => ({
17
17
  ...current,
18
- title: 'Welcome',
18
+ title: 'Untitled panel',
19
19
  toolInstanceId: null
20
20
  }))
21
21
  }));
package/dist/index.d.ts CHANGED
@@ -55,6 +55,7 @@ export * from "./application/runtime/RuntimeProjectionSession.js";
55
55
  export * from "./application/runtime/RuntimeProjectionViewerSessionSync.js";
56
56
  export * from "./application/experiment/ControlledExperimentRecorder.js";
57
57
  export * from "./application/experiment/ControlledExperimentCampaign.js";
58
+ export * from "./application/experience/experienceArtifacts.js";
58
59
  export * from "./application/repository/RepositoryPreflightEngine.js";
59
60
  export * from "./domain/layout/model.js";
60
61
  export * from "./domain/layout/interaction.js";
package/dist/index.js CHANGED
@@ -55,6 +55,7 @@ export * from "./application/runtime/RuntimeProjectionSession.js";
55
55
  export * from "./application/runtime/RuntimeProjectionViewerSessionSync.js";
56
56
  export * from "./application/experiment/ControlledExperimentRecorder.js";
57
57
  export * from "./application/experiment/ControlledExperimentCampaign.js";
58
+ export * from "./application/experience/experienceArtifacts.js";
58
59
  export * from "./application/repository/RepositoryPreflightEngine.js";
59
60
  export * from "./domain/layout/model.js";
60
61
  export * from "./domain/layout/interaction.js";
@@ -39,6 +39,7 @@ export * from "./application/workspace/presetSelection.js";
39
39
  export * from "./application/workspace/usageSnapshots.js";
40
40
  export * from "./application/launch/workbenchLaunchPolicy.js";
41
41
  export * from "./application/tool/experienceToolSelection.js";
42
+ export * from "./application/experience/experienceArtifacts.js";
42
43
  export * from "./application/workspace/unassignTool.js";
43
44
  export * from "./application/workspace/parkedTool.js";
44
45
  export * from "./application/workspace/workspacePresetCatalogAdmission.js";
@@ -31,6 +31,7 @@ export * from "./application/workspace/presetSelection.js";
31
31
  export * from "./application/workspace/usageSnapshots.js";
32
32
  export * from "./application/launch/workbenchLaunchPolicy.js";
33
33
  export * from "./application/tool/experienceToolSelection.js";
34
+ export * from "./application/experience/experienceArtifacts.js";
34
35
  export * from "./application/workspace/unassignTool.js";
35
36
  export * from "./application/workspace/parkedTool.js";
36
37
  export * from "./application/workspace/workspacePresetCatalogAdmission.js";
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.2",
4
+ "version": "0.285.4",
5
5
  "description": "Workspace composition, docking, registries and hosting contracts for KONITIF.",
6
6
  "repository": {
7
7
  "type": "git",
@@ -104,6 +104,10 @@
104
104
  "domain/tool/",
105
105
  "domain/widget/",
106
106
  "domain/surface/"
107
+ ],
108
+ "symbolNames": [
109
+ "createWorkbenchWidgetAdapter",
110
+ "WorkbenchWidgetHosting"
107
111
  ]
108
112
  },
109
113
  {