@kumwe/studio-core 0.1.0-alpha.10
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 +21 -0
- package/README.md +86 -0
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/dist/binding-projection.d.ts +47 -0
- package/dist/binding-projection.d.ts.map +1 -0
- package/dist/binding-projection.js +253 -0
- package/dist/binding-projection.js.map +1 -0
- package/dist/canonical.d.ts +20 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +100 -0
- package/dist/canonical.js.map +1 -0
- package/dist/clone.d.ts +2 -0
- package/dist/clone.d.ts.map +1 -0
- package/dist/clone.js +4 -0
- package/dist/clone.js.map +1 -0
- package/dist/commands.d.ts +18 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +799 -0
- package/dist/commands.js.map +1 -0
- package/dist/contributions.d.ts +93 -0
- package/dist/contributions.d.ts.map +1 -0
- package/dist/contributions.js +435 -0
- package/dist/contributions.js.map +1 -0
- package/dist/entry-commands.d.ts +3 -0
- package/dist/entry-commands.d.ts.map +1 -0
- package/dist/entry-commands.js +36 -0
- package/dist/entry-commands.js.map +1 -0
- package/dist/extension-sdk.d.ts +51 -0
- package/dist/extension-sdk.d.ts.map +1 -0
- package/dist/extension-sdk.js +260 -0
- package/dist/extension-sdk.js.map +1 -0
- package/dist/history.d.ts +22 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +81 -0
- package/dist/history.js.map +1 -0
- package/dist/host-session.d.ts +74 -0
- package/dist/host-session.d.ts.map +1 -0
- package/dist/host-session.js +713 -0
- package/dist/host-session.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +66 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +240 -0
- package/dist/layout.js.map +1 -0
- package/dist/migrations.d.ts +47 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +83 -0
- package/dist/migrations.js.map +1 -0
- package/dist/model-commands.d.ts +3 -0
- package/dist/model-commands.d.ts.map +1 -0
- package/dist/model-commands.js +21 -0
- package/dist/model-commands.js.map +1 -0
- package/dist/modes.d.ts +47 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +280 -0
- package/dist/modes.js.map +1 -0
- package/dist/negotiation.d.ts +23 -0
- package/dist/negotiation.d.ts.map +1 -0
- package/dist/negotiation.js +65 -0
- package/dist/negotiation.js.map +1 -0
- package/dist/production-values.d.ts +12 -0
- package/dist/production-values.d.ts.map +1 -0
- package/dist/production-values.js +224 -0
- package/dist/production-values.js.map +1 -0
- package/dist/production.d.ts +86 -0
- package/dist/production.d.ts.map +1 -0
- package/dist/production.js +811 -0
- package/dist/production.js.map +1 -0
- package/dist/profile-validator.d.ts +47 -0
- package/dist/profile-validator.d.ts.map +1 -0
- package/dist/profile-validator.js +887 -0
- package/dist/profile-validator.js.map +1 -0
- package/dist/recipes.d.ts +15 -0
- package/dist/recipes.d.ts.map +1 -0
- package/dist/recipes.js +34 -0
- package/dist/recipes.js.map +1 -0
- package/dist/registry.d.ts +17 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +56 -0
- package/dist/registry.js.map +1 -0
- package/dist/schema-profile.d.ts +27 -0
- package/dist/schema-profile.d.ts.map +1 -0
- package/dist/schema-profile.js +1015 -0
- package/dist/schema-profile.js.map +1 -0
- package/dist/semver.d.ts +20 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +128 -0
- package/dist/semver.js.map +1 -0
- package/dist/session.d.ts +73 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +191 -0
- package/dist/session.js.map +1 -0
- package/dist/url-policy.d.ts +45 -0
- package/dist/url-policy.d.ts.map +1 -0
- package/dist/url-policy.js +248 -0
- package/dist/url-policy.js.map +1 -0
- package/dist/validation.d.ts +13 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +444 -0
- package/dist/validation.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cloneContractValue } from './clone.js';
|
|
2
|
+
import { StudioCommandError } from './commands.js';
|
|
3
|
+
export function applyModelCommand(model, command) {
|
|
4
|
+
if (command.artifactId !== model.id) {
|
|
5
|
+
throw new StudioCommandError('node-not-found', `Command targets ${command.artifactId}, not content model ${model.id}.`);
|
|
6
|
+
}
|
|
7
|
+
if (model.status !== 'draft') {
|
|
8
|
+
throw new StudioCommandError('artifact-not-draft', `Content model ${model.id} is ${model.status}; fields are added through a new draft.`);
|
|
9
|
+
}
|
|
10
|
+
if (model.fields.some((field) => field.id === command.payload.field.id)) {
|
|
11
|
+
throw new StudioCommandError('duplicate-field', `Field ${command.payload.field.id} already exists on ${model.id}.`);
|
|
12
|
+
}
|
|
13
|
+
const position = command.payload.position ?? model.fields.length;
|
|
14
|
+
if (!Number.isInteger(position) || position < 0 || position > model.fields.length) {
|
|
15
|
+
throw new StudioCommandError('invalid-index', `Field position ${position} is outside the model's field list.`);
|
|
16
|
+
}
|
|
17
|
+
const next = cloneContractValue(model);
|
|
18
|
+
next.fields.splice(position, 0, cloneContractValue(command.payload.field));
|
|
19
|
+
return next;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=model-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-commands.js","sourceRoot":"","sources":["../src/model-commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAA6B;IAE7B,IAAI,OAAO,CAAC,UAAU,KAAK,KAAK,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,kBAAkB,CAC1B,gBAAgB,EAChB,mBAAmB,OAAO,CAAC,UAAU,uBAAuB,KAAK,CAAC,EAAE,GAAG,CACxE,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,kBAAkB,CAC1B,oBAAoB,EACpB,iBAAiB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC,MAAM,yCAAyC,CACtF,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,kBAAkB,CAC1B,iBAAiB,EACjB,SAAS,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,sBAAsB,KAAK,CAAC,EAAE,GAAG,CACnE,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAClF,MAAM,IAAI,kBAAkB,CAC1B,eAAe,EACf,kBAAkB,QAAQ,qCAAqC,CAChE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/modes.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { BlueprintCommand, BlueprintDocument, StudioCommand, StudioConfiguration, StudioSessionMode } from '@kumwe/studio-protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Every session mode, in stable sorted order. The permitted-command table is
|
|
4
|
+
* total over exactly this set.
|
|
5
|
+
*/
|
|
6
|
+
export declare const STUDIO_SESSION_MODES: readonly StudioSessionMode[];
|
|
7
|
+
/** Every canonical command type addressable by the mode table. */
|
|
8
|
+
export type StudioCommandType = StudioCommand['type'];
|
|
9
|
+
/**
|
|
10
|
+
* The deterministic mode-to-permitted-command table: one immutable set per
|
|
11
|
+
* session mode, shared across calls, so UIs derive disabled affordances from
|
|
12
|
+
* the same source the session enforces. The table is type-level only; the
|
|
13
|
+
* hybrid entries additionally require every affected collection to stay
|
|
14
|
+
* inside a structural authoring region, which the session enforces per
|
|
15
|
+
* command target.
|
|
16
|
+
*/
|
|
17
|
+
export declare function permittedCommandTypes(mode: StudioSessionMode): ReadonlySet<StudioCommandType>;
|
|
18
|
+
/**
|
|
19
|
+
* Flattens a configuration's editing mode, composite, and session state into
|
|
20
|
+
* the single session mode fixed at session creation: a read-only session
|
|
21
|
+
* state always flattens to `read-only`, the hybrid composite flattens to
|
|
22
|
+
* `hybrid`, and every other session keeps its authoring mode. The hybrid
|
|
23
|
+
* composite is invalid with Model mode, mirroring the configuration schema.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveSessionMode(configuration: Pick<StudioConfiguration, 'composite' | 'mode' | 'sessionState'>): StudioSessionMode;
|
|
26
|
+
/**
|
|
27
|
+
* Fails closed with the stable `mode-forbidden` code when the command type is
|
|
28
|
+
* outside the active mode's permitted set.
|
|
29
|
+
*/
|
|
30
|
+
export declare function assertModePermitsCommandType(mode: StudioSessionMode, type: StudioCommandType): void;
|
|
31
|
+
/**
|
|
32
|
+
* Enforces the bounded-composition rule for one hybrid structure command:
|
|
33
|
+
* every collection the command inserts into, removes from, moves across, or
|
|
34
|
+
* reorders must be a named slot of a node whose authoring policy mode is
|
|
35
|
+
* `structural`; inserted block types must satisfy the structural node's
|
|
36
|
+
* `allowedBlocks` when declared; subtrees containing a `locked` node are
|
|
37
|
+
* never inserted, removed, moved, or duplicated; and document roots are
|
|
38
|
+
* never in bounds. Batch operations are evaluated sequentially against a
|
|
39
|
+
* trial state so later operations may compose nodes earlier operations
|
|
40
|
+
* introduced. A violation fails closed with `mode-forbidden`; a reference
|
|
41
|
+
* the gate cannot resolve is left for the reducer's canonical failure code.
|
|
42
|
+
*
|
|
43
|
+
* The passed document is consumed as trial scratch state and may be mutated;
|
|
44
|
+
* callers pass a clone.
|
|
45
|
+
*/
|
|
46
|
+
export declare function assertHybridCommandInBounds(document: BlueprintDocument, command: BlueprintCommand): void;
|
|
47
|
+
//# sourceMappingURL=modes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../src/modes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,gBAAgB,EAChB,iBAAiB,EAKjB,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAGhC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,iBAAiB,EAM3D,CAAC;AAEH,kEAAkE;AAClE,MAAM,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAoDtD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,iBAAiB,GAAG,WAAW,CAAC,iBAAiB,CAAC,CAE7F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,GAAG,MAAM,GAAG,cAAc,CAAC,GAC9E,iBAAiB,CAWnB;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE,iBAAiB,GACtB,IAAI,CAON;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAyCN"}
|
package/dist/modes.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { applyOperation, StudioCommandError } from './commands.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every session mode, in stable sorted order. The permitted-command table is
|
|
4
|
+
* total over exactly this set.
|
|
5
|
+
*/
|
|
6
|
+
export const STUDIO_SESSION_MODES = Object.freeze([
|
|
7
|
+
'blueprint',
|
|
8
|
+
'content',
|
|
9
|
+
'hybrid',
|
|
10
|
+
'model',
|
|
11
|
+
'read-only',
|
|
12
|
+
]);
|
|
13
|
+
const BLUEPRINT_STRUCTURE_COMMAND_TYPES = [
|
|
14
|
+
'studio.command/apply-pattern',
|
|
15
|
+
'studio.command/batch',
|
|
16
|
+
'studio.command/duplicate-node',
|
|
17
|
+
'studio.command/insert-node',
|
|
18
|
+
'studio.command/move-node',
|
|
19
|
+
'studio.command/remove-binding',
|
|
20
|
+
'studio.command/remove-node',
|
|
21
|
+
'studio.command/reorder-children',
|
|
22
|
+
'studio.command/reset-inherited-property',
|
|
23
|
+
'studio.command/restore-node',
|
|
24
|
+
'studio.command/set-binding',
|
|
25
|
+
'studio.command/set-property',
|
|
26
|
+
'studio.command/set-size-role',
|
|
27
|
+
'studio.command/unset-property',
|
|
28
|
+
'studio.command/unset-size-role',
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* The structure commands hybrid composition may dispatch when every affected
|
|
32
|
+
* collection stays inside a structural authoring region. Property, binding,
|
|
33
|
+
* size-role, inheritance-reset, and pattern commands remain Blueprint-mode
|
|
34
|
+
* vocabulary.
|
|
35
|
+
*/
|
|
36
|
+
const HYBRID_STRUCTURE_OPERATION_TYPES = [
|
|
37
|
+
'studio.command/duplicate-node',
|
|
38
|
+
'studio.command/insert-node',
|
|
39
|
+
'studio.command/move-node',
|
|
40
|
+
'studio.command/remove-node',
|
|
41
|
+
'studio.command/reorder-children',
|
|
42
|
+
'studio.command/restore-node',
|
|
43
|
+
];
|
|
44
|
+
const PERMITTED_COMMAND_TYPES = Object.freeze({
|
|
45
|
+
blueprint: immutableCommandTypeSet(BLUEPRINT_STRUCTURE_COMMAND_TYPES),
|
|
46
|
+
content: immutableCommandTypeSet(['studio.command/set-field-value']),
|
|
47
|
+
hybrid: immutableCommandTypeSet([
|
|
48
|
+
'studio.command/batch',
|
|
49
|
+
...HYBRID_STRUCTURE_OPERATION_TYPES,
|
|
50
|
+
'studio.command/set-field-value',
|
|
51
|
+
]),
|
|
52
|
+
model: immutableCommandTypeSet(['studio.command/add-model-field']),
|
|
53
|
+
'read-only': immutableCommandTypeSet([]),
|
|
54
|
+
});
|
|
55
|
+
const HYBRID_BATCHABLE_OPERATION_TYPES = immutableCommandTypeSet(HYBRID_STRUCTURE_OPERATION_TYPES);
|
|
56
|
+
/**
|
|
57
|
+
* The deterministic mode-to-permitted-command table: one immutable set per
|
|
58
|
+
* session mode, shared across calls, so UIs derive disabled affordances from
|
|
59
|
+
* the same source the session enforces. The table is type-level only; the
|
|
60
|
+
* hybrid entries additionally require every affected collection to stay
|
|
61
|
+
* inside a structural authoring region, which the session enforces per
|
|
62
|
+
* command target.
|
|
63
|
+
*/
|
|
64
|
+
export function permittedCommandTypes(mode) {
|
|
65
|
+
return PERMITTED_COMMAND_TYPES[mode];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Flattens a configuration's editing mode, composite, and session state into
|
|
69
|
+
* the single session mode fixed at session creation: a read-only session
|
|
70
|
+
* state always flattens to `read-only`, the hybrid composite flattens to
|
|
71
|
+
* `hybrid`, and every other session keeps its authoring mode. The hybrid
|
|
72
|
+
* composite is invalid with Model mode, mirroring the configuration schema.
|
|
73
|
+
*/
|
|
74
|
+
export function resolveSessionMode(configuration) {
|
|
75
|
+
if (configuration.sessionState === 'read-only') {
|
|
76
|
+
return 'read-only';
|
|
77
|
+
}
|
|
78
|
+
if (configuration.composite === 'hybrid') {
|
|
79
|
+
if (configuration.mode === 'model') {
|
|
80
|
+
throw new RangeError('The hybrid composite is invalid with the model editing mode.');
|
|
81
|
+
}
|
|
82
|
+
return 'hybrid';
|
|
83
|
+
}
|
|
84
|
+
return configuration.mode;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Fails closed with the stable `mode-forbidden` code when the command type is
|
|
88
|
+
* outside the active mode's permitted set.
|
|
89
|
+
*/
|
|
90
|
+
export function assertModePermitsCommandType(mode, type) {
|
|
91
|
+
if (!PERMITTED_COMMAND_TYPES[mode].has(type)) {
|
|
92
|
+
throw new StudioCommandError('mode-forbidden', `Command type ${type} is not permitted in ${mode} mode.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Enforces the bounded-composition rule for one hybrid structure command:
|
|
97
|
+
* every collection the command inserts into, removes from, moves across, or
|
|
98
|
+
* reorders must be a named slot of a node whose authoring policy mode is
|
|
99
|
+
* `structural`; inserted block types must satisfy the structural node's
|
|
100
|
+
* `allowedBlocks` when declared; subtrees containing a `locked` node are
|
|
101
|
+
* never inserted, removed, moved, or duplicated; and document roots are
|
|
102
|
+
* never in bounds. Batch operations are evaluated sequentially against a
|
|
103
|
+
* trial state so later operations may compose nodes earlier operations
|
|
104
|
+
* introduced. A violation fails closed with `mode-forbidden`; a reference
|
|
105
|
+
* the gate cannot resolve is left for the reducer's canonical failure code.
|
|
106
|
+
*
|
|
107
|
+
* The passed document is consumed as trial scratch state and may be mutated;
|
|
108
|
+
* callers pass a clone.
|
|
109
|
+
*/
|
|
110
|
+
export function assertHybridCommandInBounds(document, command) {
|
|
111
|
+
switch (command.type) {
|
|
112
|
+
case 'studio.command/batch': {
|
|
113
|
+
for (const operation of command.payload.operations) {
|
|
114
|
+
const type = operation.type;
|
|
115
|
+
if (type === 'studio.command/batch' ||
|
|
116
|
+
type === 'studio.command/apply-pattern' ||
|
|
117
|
+
type === 'studio.command/reset-inherited-property') {
|
|
118
|
+
// Never legal inside a batch; the reducer's canonical
|
|
119
|
+
// invalid-batch rejection resurfaces when the command executes.
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (!HYBRID_BATCHABLE_OPERATION_TYPES.has(operation.type)) {
|
|
123
|
+
throw new StudioCommandError('mode-forbidden', `Batch operation type ${operation.type} is not permitted in hybrid mode.`);
|
|
124
|
+
}
|
|
125
|
+
assertHybridOperationInBounds(document, operation);
|
|
126
|
+
try {
|
|
127
|
+
applyOperation(document, operation);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// The trial cannot advance past this operation; the reducer's
|
|
131
|
+
// canonical failure code resurfaces when the command executes.
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
case 'studio.command/apply-pattern':
|
|
138
|
+
case 'studio.command/reset-inherited-property':
|
|
139
|
+
// Unreachable behind the type gate; kept for fail-closed defence.
|
|
140
|
+
throw new StudioCommandError('mode-forbidden', `Command type ${command.type} is not permitted in hybrid mode.`);
|
|
141
|
+
default:
|
|
142
|
+
assertHybridOperationInBounds(document, command);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function assertHybridOperationInBounds(document, operation) {
|
|
146
|
+
switch (operation.type) {
|
|
147
|
+
case 'studio.command/insert-node':
|
|
148
|
+
case 'studio.command/restore-node': {
|
|
149
|
+
assertSubtreeUnlocked(operation.payload.node);
|
|
150
|
+
assertComposableDestination(document, operation.payload.destination, operation.payload.node);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case 'studio.command/remove-node': {
|
|
154
|
+
const location = locateNode(document.roots, operation.payload.nodeId);
|
|
155
|
+
if (location === undefined) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
assertSubtreeUnlocked(location.node);
|
|
159
|
+
assertComposableParent(location.parent, location.slot);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
case 'studio.command/move-node': {
|
|
163
|
+
const location = locateNode(document.roots, operation.payload.nodeId);
|
|
164
|
+
if (location === undefined) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
assertSubtreeUnlocked(location.node);
|
|
168
|
+
assertComposableParent(location.parent, location.slot);
|
|
169
|
+
assertComposableDestination(document, operation.payload.destination, location.node);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
case 'studio.command/duplicate-node': {
|
|
173
|
+
const location = locateNode(document.roots, operation.payload.nodeId);
|
|
174
|
+
if (location === undefined) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
assertSubtreeUnlocked(location.node);
|
|
178
|
+
if (operation.payload.destination === undefined) {
|
|
179
|
+
assertComposableParent(location.parent, location.slot);
|
|
180
|
+
if (location.parent !== undefined) {
|
|
181
|
+
assertAllowedBlock(location.parent, location.slot, location.node);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
assertComposableDestination(document, operation.payload.destination, location.node);
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
case 'studio.command/reorder-children': {
|
|
190
|
+
if (operation.payload.parentNodeId === undefined) {
|
|
191
|
+
throw rootsOutOfBounds();
|
|
192
|
+
}
|
|
193
|
+
assertComposableParent(locateNode(document.roots, operation.payload.parentNodeId)?.node, operation.payload.slot);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
default:
|
|
197
|
+
// Unreachable behind the type gate; kept for fail-closed defence.
|
|
198
|
+
throw new StudioCommandError('mode-forbidden', `Batch operation type ${operation.type} is not permitted in hybrid mode.`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function locateNode(nodes, nodeId, parent, slot) {
|
|
202
|
+
for (const node of nodes) {
|
|
203
|
+
if (node.id === nodeId) {
|
|
204
|
+
if (parent === undefined) {
|
|
205
|
+
return { node };
|
|
206
|
+
}
|
|
207
|
+
return slot === undefined ? { node, parent } : { node, parent, slot };
|
|
208
|
+
}
|
|
209
|
+
for (const [slotName, children] of Object.entries(node.slots)) {
|
|
210
|
+
const nested = locateNode(children, nodeId, node, slotName);
|
|
211
|
+
if (nested !== undefined) {
|
|
212
|
+
return nested;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
function assertComposableDestination(document, destination, node) {
|
|
219
|
+
if (destination.parentNodeId === undefined) {
|
|
220
|
+
throw rootsOutOfBounds();
|
|
221
|
+
}
|
|
222
|
+
const parent = locateNode(document.roots, destination.parentNodeId)?.node;
|
|
223
|
+
if (parent === undefined) {
|
|
224
|
+
// The reducer's canonical parent-not-found rejection resurfaces.
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
assertComposableParent(parent, destination.slot);
|
|
228
|
+
assertAllowedBlock(parent, destination.slot, node);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* A collection is composable when its parent node declares structural
|
|
232
|
+
* authoring, or when the parent's per-slot composition marker names the slot
|
|
233
|
+
* (ADR 0013). The marker only grants composability; it never revokes what
|
|
234
|
+
* the node-level policy permits.
|
|
235
|
+
*/
|
|
236
|
+
function assertComposableParent(parent, slot) {
|
|
237
|
+
if (parent === undefined) {
|
|
238
|
+
throw rootsOutOfBounds();
|
|
239
|
+
}
|
|
240
|
+
if (parent.authoring.mode === 'structural') {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (slot !== undefined && parent.authoring.slots?.[slot]?.composable === true) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
throw new StudioCommandError('mode-forbidden', `Hybrid composition is bounded to structural slots; node ${parent.id} declares neither structural authoring nor a composable marker for the affected slot.`);
|
|
247
|
+
}
|
|
248
|
+
function assertAllowedBlock(parent, slot, node) {
|
|
249
|
+
const slotPolicy = slot === undefined ? undefined : parent.authoring.slots?.[slot];
|
|
250
|
+
const allowedBlocks = slotPolicy?.allowedBlocks ?? parent.authoring.allowedBlocks;
|
|
251
|
+
if (allowedBlocks !== undefined && !allowedBlocks.includes(node.type)) {
|
|
252
|
+
throw new StudioCommandError('mode-forbidden', `Block type ${node.type} is not an allowed block inside the composable region of node ${parent.id}.`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function assertSubtreeUnlocked(node) {
|
|
256
|
+
const stack = [node];
|
|
257
|
+
while (stack.length > 0) {
|
|
258
|
+
const current = stack.pop();
|
|
259
|
+
if (current === undefined) {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
if (current.authoring.mode === 'locked') {
|
|
263
|
+
throw new StudioCommandError('mode-forbidden', `Node ${current.id} is locked and never changes through hybrid composition.`);
|
|
264
|
+
}
|
|
265
|
+
for (const children of Object.values(current.slots)) {
|
|
266
|
+
stack.push(...children);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function rootsOutOfBounds() {
|
|
271
|
+
return new StudioCommandError('mode-forbidden', 'Hybrid composition is bounded to structural slots; the document roots are out of bounds.');
|
|
272
|
+
}
|
|
273
|
+
function immutableCommandTypeSet(types) {
|
|
274
|
+
const set = new Set(types);
|
|
275
|
+
const forbidMutation = () => {
|
|
276
|
+
throw new TypeError('The permitted command-type table is immutable.');
|
|
277
|
+
};
|
|
278
|
+
return Object.freeze(Object.assign(set, { add: forbidMutation, clear: forbidMutation, delete: forbidMutation }));
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=modes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modes.js","sourceRoot":"","sources":["../src/modes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HostCapabilities, QualifiedName, StudioDiagnostic } from '@kumwe/studio-protocol';
|
|
2
|
+
export interface CapabilityNegotiationOptions {
|
|
3
|
+
optionalPorts?: readonly QualifiedName[];
|
|
4
|
+
requiredPorts?: readonly QualifiedName[];
|
|
5
|
+
supportedProtocolVersions?: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export interface CapabilityNegotiationResult {
|
|
8
|
+
availablePorts: QualifiedName[];
|
|
9
|
+
diagnostics: StudioDiagnostic[];
|
|
10
|
+
missingOptionalPorts: QualifiedName[];
|
|
11
|
+
missingRequiredPorts: QualifiedName[];
|
|
12
|
+
protocolVersion?: string;
|
|
13
|
+
sessionState: 'editable' | 'read-only';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve one session posture from a host capability document. Capability
|
|
17
|
+
* negotiation fails closed: without a common wire protocol version or a
|
|
18
|
+
* required port there is no editable session, only a diagnosable read-only
|
|
19
|
+
* one. Optional ports degrade with informational diagnostics instead of
|
|
20
|
+
* being silently assumed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function negotiateCapabilities(capabilities: HostCapabilities, options?: Readonly<CapabilityNegotiationOptions>): CapabilityNegotiationResult;
|
|
23
|
+
//# sourceMappingURL=negotiation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation.d.ts","sourceRoot":"","sources":["../src/negotiation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAGhG,MAAM,WAAW,4BAA4B;IAC3C,aAAa,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,aAAa,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,yBAAyB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,2BAA2B;IAC1C,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,oBAAoB,EAAE,aAAa,EAAE,CAAC;IACtC,oBAAoB,EAAE,aAAa,EAAE,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,UAAU,GAAG,WAAW,CAAC;CACxC;AAID;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,gBAAgB,EAC9B,OAAO,GAAE,QAAQ,CAAC,4BAA4B,CAAM,GACnD,2BAA2B,CA6D7B"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { STUDIO_WIRE_PROTOCOL_VERSION } from '@kumwe/studio-protocol';
|
|
2
|
+
const DEFAULT_REQUIRED_PORTS = ['studio.port/artifact'];
|
|
3
|
+
/**
|
|
4
|
+
* Resolve one session posture from a host capability document. Capability
|
|
5
|
+
* negotiation fails closed: without a common wire protocol version or a
|
|
6
|
+
* required port there is no editable session, only a diagnosable read-only
|
|
7
|
+
* one. Optional ports degrade with informational diagnostics instead of
|
|
8
|
+
* being silently assumed.
|
|
9
|
+
*/
|
|
10
|
+
export function negotiateCapabilities(capabilities, options = {}) {
|
|
11
|
+
const supportedVersions = options.supportedProtocolVersions ?? [STUDIO_WIRE_PROTOCOL_VERSION];
|
|
12
|
+
const requiredPorts = options.requiredPorts ?? DEFAULT_REQUIRED_PORTS;
|
|
13
|
+
const optionalPorts = options.optionalPorts ?? [];
|
|
14
|
+
const diagnostics = [];
|
|
15
|
+
const availablePorts = capabilities.ports.map((port) => port.id);
|
|
16
|
+
const available = new Set(availablePorts);
|
|
17
|
+
const protocolVersion = supportedVersions.find((version) => capabilities.protocolVersions.includes(version));
|
|
18
|
+
if (protocolVersion === undefined) {
|
|
19
|
+
diagnostics.push({
|
|
20
|
+
code: 'studio.host/no-common-protocol-version',
|
|
21
|
+
message: {
|
|
22
|
+
defaultMessage: 'Studio and the host share no wire protocol version.',
|
|
23
|
+
key: 'studio.host/no-common-protocol-version',
|
|
24
|
+
},
|
|
25
|
+
severity: 'blocking',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const missingRequiredPorts = requiredPorts.filter((port) => !available.has(port));
|
|
29
|
+
for (const port of missingRequiredPorts) {
|
|
30
|
+
diagnostics.push({
|
|
31
|
+
code: 'studio.host/missing-required-port',
|
|
32
|
+
message: {
|
|
33
|
+
defaultMessage: `The host does not provide the required ${port} port.`,
|
|
34
|
+
key: 'studio.host/missing-required-port',
|
|
35
|
+
},
|
|
36
|
+
parameters: { port },
|
|
37
|
+
severity: 'blocking',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const missingOptionalPorts = optionalPorts.filter((port) => !available.has(port));
|
|
41
|
+
for (const port of missingOptionalPorts) {
|
|
42
|
+
diagnostics.push({
|
|
43
|
+
code: 'studio.host/missing-optional-port',
|
|
44
|
+
message: {
|
|
45
|
+
defaultMessage: `The optional ${port} port is unavailable; its features are disabled.`,
|
|
46
|
+
key: 'studio.host/missing-optional-port',
|
|
47
|
+
},
|
|
48
|
+
parameters: { port },
|
|
49
|
+
severity: 'information',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const editable = protocolVersion !== undefined && missingRequiredPorts.length === 0;
|
|
53
|
+
const result = {
|
|
54
|
+
availablePorts,
|
|
55
|
+
diagnostics,
|
|
56
|
+
missingOptionalPorts,
|
|
57
|
+
missingRequiredPorts,
|
|
58
|
+
sessionState: editable ? 'editable' : 'read-only',
|
|
59
|
+
};
|
|
60
|
+
if (protocolVersion !== undefined) {
|
|
61
|
+
result.protocolVersion = protocolVersion;
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=negotiation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation.js","sourceRoot":"","sources":["../src/negotiation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAiBtE,MAAM,sBAAsB,GAA6B,CAAC,sBAAsB,CAAC,CAAC;AAElF;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,YAA8B,EAC9B,UAAkD,EAAE;IAEpD,MAAM,iBAAiB,GAAG,OAAO,CAAC,yBAAyB,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC9F,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACtE,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;IAElD,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAgB,cAAc,CAAC,CAAC;IAEzD,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CACzD,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAChD,CAAC;IACF,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,wCAAwC;YAC9C,OAAO,EAAE;gBACP,cAAc,EAAE,qDAAqD;gBACrE,GAAG,EAAE,wCAAwC;aAC9C;YACD,QAAQ,EAAE,UAAU;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,oBAAoB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAClF,KAAK,MAAM,IAAI,IAAI,oBAAoB,EAAE,CAAC;QACxC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,mCAAmC;YACzC,OAAO,EAAE;gBACP,cAAc,EAAE,0CAA0C,IAAI,QAAQ;gBACtE,GAAG,EAAE,mCAAmC;aACzC;YACD,UAAU,EAAE,EAAE,IAAI,EAAE;YACpB,QAAQ,EAAE,UAAU;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,oBAAoB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAClF,KAAK,MAAM,IAAI,IAAI,oBAAoB,EAAE,CAAC;QACxC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,mCAAmC;YACzC,OAAO,EAAE;gBACP,cAAc,EAAE,gBAAgB,IAAI,kDAAkD;gBACtF,GAAG,EAAE,mCAAmC;aACzC;YACD,UAAU,EAAE,EAAE,IAAI,EAAE;YACpB,QAAQ,EAAE,aAAa;SACxB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,KAAK,SAAS,IAAI,oBAAoB,CAAC,MAAM,KAAK,CAAC,CAAC;IACpF,MAAM,MAAM,GAAgC;QAC1C,cAAc;QACd,WAAW;QACX,oBAAoB;QACpB,oBAAoB;QACpB,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW;KAClD,CAAC;IACF,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,eAAe,GAAG,eAAe,CAAC;IAC3C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StudioChartSpec, StudioDrawingDocument, StudioMoneyValue, StudioPresentationIntent, StudioTableDocument } from '@kumwe/studio-protocol';
|
|
2
|
+
/** Parse and detach one canonical chart spec, refusing library-specific configuration. */
|
|
3
|
+
export declare function parseStudioChartSpec(value: unknown): StudioChartSpec;
|
|
4
|
+
/** Parse bounded vector strokes and reject SVG, data URLs, and canvas commands. */
|
|
5
|
+
export declare function parseStudioDrawingDocument(value: unknown): StudioDrawingDocument;
|
|
6
|
+
/** Parse exact decimal money without converting through a binary float. */
|
|
7
|
+
export declare function parseStudioMoneyValue(value: unknown): StudioMoneyValue;
|
|
8
|
+
/** Parse closed presentation intent without accepting selectors, declarations, or measurements. */
|
|
9
|
+
export declare function parseStudioPresentationIntent(value: unknown): StudioPresentationIntent;
|
|
10
|
+
/** Parse a bounded, text-only table and require one cell per declared column. */
|
|
11
|
+
export declare function parseStudioTableDocument(value: unknown): StudioTableDocument;
|
|
12
|
+
//# sourceMappingURL=production-values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-values.d.ts","sourceRoot":"","sources":["../src/production-values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EACf,qBAAqB,EAGrB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AAOhC,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CA4CpE;AAED,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,CA2ChF;AAED,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAStE;AAED,mGAAmG;AACnG,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CA4FtF;AAED,iFAAiF;AACjF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAsB5E"}
|