@kubohiroya/turbowarp-extension-data-editor 0.2.0 → 0.2.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.
Files changed (64) hide show
  1. package/README.md +9 -6
  2. package/dist/build-info.json +4 -4
  3. package/dist/fixed-input-branches.d.ts +12 -0
  4. package/dist/fixed-input-branches.js +180 -0
  5. package/dist/fixed-input-editor.d.ts +39 -0
  6. package/dist/fixed-input-editor.js +538 -0
  7. package/dist/fixed-input-schema.d.ts +15 -0
  8. package/dist/fixed-input-schema.js +21 -0
  9. package/dist/fixed-input-snapshot.d.ts +7 -0
  10. package/dist/fixed-input-snapshot.js +180 -0
  11. package/dist/fixed-input-types.d.ts +138 -0
  12. package/dist/fixed-input-types.js +23 -0
  13. package/dist/fixed-input-view.d.ts +14 -0
  14. package/dist/fixed-input-view.js +168 -0
  15. package/dist/index.d.ts +6 -0
  16. package/dist/index.js +4 -0
  17. package/dist/react.css +42 -0
  18. package/dist/react.d.ts +3 -0
  19. package/dist/react.js +10 -1
  20. package/dist/registry.d.ts +4 -0
  21. package/dist/registry.js +45 -7
  22. package/dist/rjsf.d.ts +24 -1
  23. package/dist/rjsf.js +22 -2
  24. package/dist/schema.d.ts +2 -0
  25. package/dist/schema.js +1 -0
  26. package/dist/session.d.ts +3 -1
  27. package/dist/session.js +205 -7
  28. package/dist/turbowarp/bridge.d.ts +2 -1
  29. package/dist/turbowarp/bridge.js +34 -5
  30. package/dist/turbowarp/fixed-fields.d.ts +82 -0
  31. package/dist/turbowarp/fixed-fields.js +311 -0
  32. package/dist/turbowarp/fixed-transaction.d.ts +18 -0
  33. package/dist/turbowarp/fixed-transaction.js +460 -0
  34. package/dist/turbowarp/host.d.ts +3 -8
  35. package/dist/turbowarp/host.js +68 -1
  36. package/dist/turbowarp.d.ts +4 -0
  37. package/dist/turbowarp.js +1 -1
  38. package/dist/types.d.ts +5 -0
  39. package/dist/view.js +4 -0
  40. package/dist/webpack4/index.js +22 -5
  41. package/dist/webpack4/metafile.json +588 -319
  42. package/dist/webpack4/react.js +9 -1
  43. package/dist/webpack4/react.js.map +2 -2
  44. package/dist/webpack4/rjsf.js +249 -34
  45. package/dist/webpack4/rjsf.js.map +4 -4
  46. package/dist/webpack4/schema.js +6 -3
  47. package/dist/webpack4/{shared-KQOUMWJ4.js → shared-75QIWLZY.js} +1129 -1244
  48. package/dist/webpack4/{shared-KQOUMWJ4.js.map → shared-75QIWLZY.js.map} +4 -4
  49. package/dist/webpack4/shared-FYUILHED.js +1 -0
  50. package/dist/webpack4/shared-GQLPPRT2.js +210 -0
  51. package/dist/webpack4/shared-GQLPPRT2.js.map +7 -0
  52. package/dist/webpack4/shared-P2JBRZFP.js +2206 -0
  53. package/dist/webpack4/shared-P2JBRZFP.js.map +7 -0
  54. package/dist/webpack4/turbowarp.js +910 -9
  55. package/dist/webpack4/turbowarp.js.map +4 -4
  56. package/docs/fixed-input-contracts.md +77 -0
  57. package/docs/stage-2-publication.ja.md +6 -0
  58. package/package.json +8 -1
  59. package/dist/webpack4/shared-CQB3NG2A.js +0 -1
  60. package/dist/webpack4/shared-MRPGBJIH.js +0 -75
  61. package/dist/webpack4/shared-MRPGBJIH.js.map +0 -7
  62. package/dist/webpack4/shared-N6YQE2X6.js +0 -1029
  63. package/dist/webpack4/shared-N6YQE2X6.js.map +0 -7
  64. /package/dist/webpack4/{shared-CQB3NG2A.js.map → shared-FYUILHED.js.map} +0 -0
package/dist/registry.js CHANGED
@@ -3,7 +3,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _EditorRegistry_instances, _EditorRegistry_editors, _EditorRegistry_opcodes, _EditorRegistry_changes, _EditorRegistry_register, _EditorRegistry_notifyChanges;
6
+ var _EditorRegistry_instances, _EditorRegistry_editors, _EditorRegistry_opcodes, _EditorRegistry_fixedDeclarations, _EditorRegistry_changes, _EditorRegistry_register, _EditorRegistry_notifyChanges;
7
7
  import { captureReference, captureSnapshot } from './data.js';
8
8
  import { EditorSession } from './session.js';
9
9
  import { DescendantSession } from './descendants.js';
@@ -11,14 +11,20 @@ import { supportsDescendantEditing } from './descendant-types.js';
11
11
  import { captureSubtree, descendantLimits } from './subtree.js';
12
12
  import { EDITOR_API_VERSION } from './types.js';
13
13
  import { isPreparedEditor } from './prepared-save.js';
14
+ import { isFixedInputEditor, captureFixedInputEditorDefinition } from './fixed-input-editor.js';
15
+ import { captureFixedInputDeclaration, captureFixedSnapshot } from './fixed-input-snapshot.js';
16
+ import { supportsFixedInputEditing } from './fixed-input-types.js';
14
17
  export class EditorRegistry {
15
18
  constructor() {
16
19
  _EditorRegistry_instances.add(this);
17
20
  _EditorRegistry_editors.set(this, new Map());
18
21
  _EditorRegistry_opcodes.set(this, new Map());
22
+ _EditorRegistry_fixedDeclarations.set(this, new Map());
19
23
  _EditorRegistry_changes.set(this, new Set());
20
24
  }
21
25
  register(definition) {
26
+ if (isFixedInputEditor(definition))
27
+ throw new TypeError('Fixed input editors require registerFixed().');
22
28
  if (isPreparedEditor(definition))
23
29
  throw new TypeError('Prepared editors require registerPrepared().');
24
30
  return __classPrivateFieldGet(this, _EditorRegistry_instances, "m", _EditorRegistry_register).call(this, definition);
@@ -29,6 +35,9 @@ export class EditorRegistry {
29
35
  }
30
36
  return __classPrivateFieldGet(this, _EditorRegistry_instances, "m", _EditorRegistry_register).call(this, definition);
31
37
  }
38
+ registerFixed(definition) {
39
+ return __classPrivateFieldGet(this, _EditorRegistry_instances, "m", _EditorRegistry_register).call(this, captureFixedInputEditorDefinition(definition));
40
+ }
32
41
  resolve(opcode) {
33
42
  const entry = __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(opcode);
34
43
  if (!entry)
@@ -38,15 +47,37 @@ export class EditorRegistry {
38
47
  opcodes: entry.opcodes, editableArguments: entry.editableArguments
39
48
  });
40
49
  }
50
+ /** Stable, callback-free authority for this exact registration, never caller metadata. */
51
+ resolveFixed(opcode) {
52
+ const entry = __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(opcode);
53
+ return entry ? __classPrivateFieldGet(this, _EditorRegistry_fixedDeclarations, "f").get(entry) : undefined;
54
+ }
41
55
  open(reference, host) {
42
56
  const capturedReference = captureReference(reference);
43
57
  const live = host.readBlock(capturedReference);
44
58
  if (!live)
45
59
  return undefined;
60
+ const entry = __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(live.opcode);
61
+ if (!entry) {
62
+ // Preserve legacy snapshot validation even when no editor is registered.
63
+ captureSnapshot(live, capturedReference);
64
+ return undefined;
65
+ }
66
+ if (isFixedInputEditor(entry)) {
67
+ if (!supportsFixedInputEditing(host))
68
+ return undefined;
69
+ const fixed = host.fixedInputs.readBlock(capturedReference, entry);
70
+ if (!fixed || fixed.opcode !== live.opcode)
71
+ return undefined;
72
+ const snapshot = captureFixedSnapshot(fixed, capturedReference, entry);
73
+ return new EditorSession(entry, snapshot, host, () => __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(snapshot.opcode) === entry, listener => {
74
+ __classPrivateFieldGet(this, _EditorRegistry_changes, "f").add(listener);
75
+ return () => { __classPrivateFieldGet(this, _EditorRegistry_changes, "f").delete(listener); };
76
+ });
77
+ }
46
78
  const snapshot = captureSnapshot(live, capturedReference);
47
- const entry = __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(snapshot.opcode);
48
- return entry ? new EditorSession(entry, snapshot, host, isPreparedEditor(entry)
49
- ? () => __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(snapshot.opcode) === entry : undefined) : undefined;
79
+ return new EditorSession(entry, snapshot, host, isPreparedEditor(entry)
80
+ ? () => __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(snapshot.opcode) === entry : undefined);
50
81
  }
51
82
  openDescendants(reference, host, limits) {
52
83
  if (!supportsDescendantEditing(host))
@@ -58,15 +89,19 @@ export class EditorRegistry {
58
89
  if (!live)
59
90
  return undefined;
60
91
  const captured = captureSubtree(live, capturedReference, resolvedLimits);
61
- if (!__classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").has(captured.snapshot.nodes[0].block.opcode))
92
+ const root = __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(captured.snapshot.nodes[0].block.opcode);
93
+ if (!root || isFixedInputEditor(root))
62
94
  return undefined;
63
- return new DescendantSession(captured, port, opcode => __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(opcode), listener => {
95
+ return new DescendantSession(captured, port, opcode => {
96
+ const entry = __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").get(opcode);
97
+ return entry && !isFixedInputEditor(entry) ? entry : undefined;
98
+ }, listener => {
64
99
  __classPrivateFieldGet(this, _EditorRegistry_changes, "f").add(listener);
65
100
  return () => { __classPrivateFieldGet(this, _EditorRegistry_changes, "f").delete(listener); };
66
101
  }, resolvedLimits);
67
102
  }
68
103
  }
69
- _EditorRegistry_editors = new WeakMap(), _EditorRegistry_opcodes = new WeakMap(), _EditorRegistry_changes = new WeakMap(), _EditorRegistry_instances = new WeakSet(), _EditorRegistry_register = function _EditorRegistry_register(definition) {
104
+ _EditorRegistry_editors = new WeakMap(), _EditorRegistry_opcodes = new WeakMap(), _EditorRegistry_fixedDeclarations = new WeakMap(), _EditorRegistry_changes = new WeakMap(), _EditorRegistry_instances = new WeakSet(), _EditorRegistry_register = function _EditorRegistry_register(definition) {
70
105
  if (definition.apiVersion !== EDITOR_API_VERSION)
71
106
  throw new TypeError('Unsupported editor API version.');
72
107
  if (!/^[a-z0-9]+$/i.test(definition.extensionId) ||
@@ -98,6 +133,8 @@ _EditorRegistry_editors = new WeakMap(), _EditorRegistry_opcodes = new WeakMap()
98
133
  opcodes: Object.freeze([...definition.opcodes]),
99
134
  editableArguments: Object.freeze([...definition.editableArguments])
100
135
  });
136
+ if (isFixedInputEditor(entry))
137
+ __classPrivateFieldGet(this, _EditorRegistry_fixedDeclarations, "f").set(entry, captureFixedInputDeclaration(entry));
101
138
  __classPrivateFieldGet(this, _EditorRegistry_editors, "f").set(key, entry);
102
139
  for (const opcode of entry.opcodes)
103
140
  __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").set(opcode, entry);
@@ -108,6 +145,7 @@ _EditorRegistry_editors = new WeakMap(), _EditorRegistry_opcodes = new WeakMap()
108
145
  __classPrivateFieldGet(this, _EditorRegistry_editors, "f").delete(key);
109
146
  for (const opcode of entry.opcodes)
110
147
  __classPrivateFieldGet(this, _EditorRegistry_opcodes, "f").delete(opcode);
148
+ __classPrivateFieldGet(this, _EditorRegistry_fixedDeclarations, "f").delete(entry);
111
149
  __classPrivateFieldGet(this, _EditorRegistry_instances, "m", _EditorRegistry_notifyChanges).call(this);
112
150
  };
113
151
  }, _EditorRegistry_notifyChanges = function _EditorRegistry_notifyChanges() {
package/dist/rjsf.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ import type { FixedInputMessageSource } from './fixed-input-view.js';
2
+ export type { FixedInputViewMessages, FixedInputMessageSource } from './fixed-input-view.js';
3
+ import type { FixedInputEditorOptions } from './fixed-input-editor.js';
4
+ export { createFixedInputEditor } from './fixed-input-editor.js';
5
+ export type { FixedInputEditorOptions, FixedInputBinding, FixedInputBranchPolicy } from './fixed-input-editor.js';
6
+ export type * from './fixed-input-types.js';
1
7
  import type { SourceEditorOptions } from './source-types.js';
2
8
  export { createSourceEditor } from './source-editor.js';
3
9
  export type * from './source-types.js';
@@ -35,6 +41,7 @@ export interface BlockEditorRegistrationAPI {
35
41
  registerSchema(definition: SchemaEditorOptions): () => void;
36
42
  registerSchemaBundle?<C>(definition: SchemaBundleEditorOptions<C>): () => void;
37
43
  registerSourceEditor?<C = null>(definition: SourceEditorOptions<C>): () => void;
44
+ registerFixedInputEditor?<C = null>(definition: FixedInputEditorOptions<C>): () => void;
38
45
  }
39
46
  /** Capability guaranteed by the service factory, optional on a legacy host-supplied API. */
40
47
  export interface SchemaBundleBlockEditorRegistrationAPI extends BlockEditorRegistrationAPI {
@@ -44,14 +51,30 @@ export interface SchemaBundleBlockEditorRegistrationAPI extends BlockEditorRegis
44
51
  export interface SourceBlockEditorRegistrationAPI extends SchemaBundleBlockEditorRegistrationAPI {
45
52
  registerSourceEditor<C = null>(definition: SourceEditorOptions<C>): () => void;
46
53
  }
54
+ export interface FixedBlockEditorRegistrationAPI extends SourceBlockEditorRegistrationAPI {
55
+ registerFixedInputEditor<C = null>(definition: FixedInputEditorOptions<C>): () => void;
56
+ }
47
57
  export interface BlockEditorService {
48
58
  readonly registry: EditorRegistry;
49
59
  readonly api: BlockEditorRegistrationAPI;
50
60
  subscribe(listener: () => void): () => void;
51
61
  }
52
62
  /** A host owns the service's lifetime; this module never stores VM or workspace instances. */
53
- export declare function createBlockEditorService(): BlockEditorService & {
63
+ export declare function createBlockEditorService(options: {
64
+ readonly fixedInputs: true;
65
+ readonly fixedInputMessages?: FixedInputMessageSource;
66
+ }): BlockEditorService & {
67
+ readonly api: FixedBlockEditorRegistrationAPI;
68
+ };
69
+ export declare function createBlockEditorService(options?: {
70
+ readonly fixedInputs?: false;
71
+ readonly fixedInputMessages?: FixedInputMessageSource;
72
+ }): BlockEditorService & {
54
73
  readonly api: SourceBlockEditorRegistrationAPI;
55
74
  };
75
+ export declare function createBlockEditorService(options: {
76
+ readonly fixedInputs?: boolean;
77
+ readonly fixedInputMessages?: FixedInputMessageSource;
78
+ }): BlockEditorService;
56
79
  /** Build an editor with JSON/YAML serialization, schema validation and the standard RJSF body. */
57
80
  export declare function createSchemaEditor(options: SchemaEditorOptions): EditorDefinition;
package/dist/rjsf.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { createSourceEditor } from './source-editor.js';
3
+ import { createFixedInputEditor } from './fixed-input-editor.js';
4
+ import { captureFixedInputMessages, resolveFixedInputMessages, mountFixedInputView } from './fixed-input-view.js';
5
+ export { createFixedInputEditor } from './fixed-input-editor.js';
3
6
  export { createSourceEditor } from './source-editor.js';
4
7
  import * as ReactDOM from 'react-dom';
5
8
  import * as RjsfCore from '@rjsf/core';
@@ -65,13 +68,30 @@ export function createSchemaBundleEditor(options) {
65
68
  ...(format === undefined ? {} : { format }), ...(uiSchema === undefined ? {} : { uiSchema }),
66
69
  ...(validateData === undefined ? {} : { validateData }) }, { issuesFor, dialect: result.validator.dialect });
67
70
  }
68
- /** A host owns the service's lifetime; this module never stores VM or workspace instances. */
69
- export function createBlockEditorService() {
71
+ export function createBlockEditorService(options) {
72
+ if ((options === null || options === void 0 ? void 0 : options.fixedInputs) !== undefined && typeof options.fixedInputs !== 'boolean')
73
+ throw new TypeError('Invalid fixed input capability option.');
74
+ const messageSource = options === null || options === void 0 ? void 0 : options.fixedInputMessages;
75
+ const fixedMessages = typeof messageSource === 'function' ? messageSource : captureFixedInputMessages(messageSource);
70
76
  const registry = new EditorRegistry();
71
77
  const listeners = new Set();
72
78
  const notify = () => { for (const listener of [...listeners])
73
79
  listener(); };
80
+ const fixed = (options === null || options === void 0 ? void 0 : options.fixedInputs) === true ? {
81
+ registerFixedInputEditor: (definition) => {
82
+ const fixedDefinition = createFixedInputEditor(definition);
83
+ const remove = registry.registerFixed({ ...fixedDefinition, mount: (container, context) => mountFixedInputView(container, context, resolveFixedInputMessages(fixedMessages)) });
84
+ notify();
85
+ let active = true;
86
+ return () => { if (active) {
87
+ active = false;
88
+ remove();
89
+ notify();
90
+ } };
91
+ }
92
+ } : {};
74
93
  const api = Object.freeze({
94
+ ...fixed,
75
95
  apiVersion: EDITOR_API_VERSION,
76
96
  register: (definition) => {
77
97
  const custom = definition;
package/dist/schema.d.ts CHANGED
@@ -6,3 +6,5 @@ export { validateSchemaInput } from './schema-compose.js';
6
6
  export declare function toValidationIssues(diagnostics: readonly InputDiagnostic[]): readonly ValidationIssue[];
7
7
  export type * from './source-types.js';
8
8
  export { jsonValueSchema, jsonValueSchemaBundle } from './json-value.js';
9
+ export { parseFixedNumberInput } from './fixed-input-schema.js';
10
+ export type { FixedNumberInputResult } from './fixed-input-schema.js';
package/dist/schema.js CHANGED
@@ -84,3 +84,4 @@ export function toValidationIssues(diagnostics) {
84
84
  }
85
85
  }
86
86
  export { jsonValueSchema, jsonValueSchemaBundle } from './json-value.js';
87
+ export { parseFixedNumberInput } from './fixed-input-schema.js';
package/dist/session.d.ts CHANGED
@@ -1,11 +1,13 @@
1
+ import type { FixedInputViewDescription } from './fixed-input-types.js';
1
2
  import type { BlockEditorHost, BlockReference, BlockSnapshot, EditorDefinition, EditorViewContext, JsonObject, SaveResult, SessionState, ValidationIssue } from './types.js';
2
3
  export declare class EditorSession implements EditorViewContext {
3
4
  #private;
4
5
  /** Use EditorRegistry.open() to construct sessions from a captured host snapshot. */
5
- constructor(definition: EditorDefinition, snapshot: BlockSnapshot, host: BlockEditorHost, isRegistered?: () => boolean);
6
+ constructor(definition: EditorDefinition, snapshot: BlockSnapshot, host: BlockEditorHost, isRegistered?: () => boolean, subscribeRegistrationChanges?: (listener: () => void) => () => void);
6
7
  /** Stable instance identity remains available after the session closes. */
7
8
  get reference(): BlockReference;
8
9
  getDraft(): JsonObject;
10
+ getFixedInputView(): FixedInputViewDescription | undefined;
9
11
  setDraft(draft: JsonObject): void;
10
12
  setValidationIssues(issues: readonly ValidationIssue[]): void;
11
13
  getState(): SessionState;
package/dist/session.js CHANGED
@@ -9,14 +9,19 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _EditorSession_instances, _EditorSession_draft, _EditorSession_status, _EditorSession_issues, _EditorSession_error, _EditorSession_listeners, _EditorSession_view, _EditorSession_definition, _EditorSession_snapshot, _EditorSession_host, _EditorSession_isRegistered, _EditorSession_prepareChanges, _EditorSession_copyIssues, _EditorSession_copyDraft, _EditorSession_assertOpen, _EditorSession_finish, _EditorSession_notify, _EditorSession_reportObserverError;
12
+ var _EditorSession_instances, _EditorSession_draft, _EditorSession_status, _EditorSession_issues, _EditorSession_error, _EditorSession_listeners, _EditorSession_view, _EditorSession_definition, _EditorSession_snapshot, _EditorSession_host, _EditorSession_fixedPort, _EditorSession_isRegistered, _EditorSession_subscribeRegistrationChanges, _EditorSession_unsubscribeFixedScope, _EditorSession_unsubscribeFixedRegistration, _EditorSession_fixedSavingController, _EditorSession_saveFixed, _EditorSession_prepareChanges, _EditorSession_copyIssues, _EditorSession_copyDraft, _EditorSession_assertOpen, _EditorSession_finish, _EditorSession_notify, _EditorSession_reportObserverError;
13
13
  import { captureReference, captureSnapshot, cloneJson, isLiteral, sameSnapshot } from './data.js';
14
14
  import { BlockEditorConflictError } from './types.js';
15
15
  import { EditorView } from './view.js';
16
16
  import { isPreparedEditor, capturePreparedSave } from './prepared-save.js';
17
+ import { isFixedInputEditor, captureFixedPreparedSave } from './fixed-input-editor.js';
18
+ import { captureFixedSnapshot, sameFixedSnapshot } from './fixed-input-snapshot.js';
19
+ import { supportsFixedInputEditing } from './fixed-input-types.js';
20
+ import { snapshotJson, isJsonRecord } from './schema-json.js';
21
+ import { validateFixedBranchChanges } from './fixed-input-branches.js';
17
22
  export class EditorSession {
18
23
  /** Use EditorRegistry.open() to construct sessions from a captured host snapshot. */
19
- constructor(definition, snapshot, host, isRegistered) {
24
+ constructor(definition, snapshot, host, isRegistered, subscribeRegistrationChanges) {
20
25
  _EditorSession_instances.add(this);
21
26
  _EditorSession_draft.set(this, void 0);
22
27
  _EditorSession_status.set(this, 'editing');
@@ -27,12 +32,68 @@ export class EditorSession {
27
32
  _EditorSession_definition.set(this, void 0);
28
33
  _EditorSession_snapshot.set(this, void 0);
29
34
  _EditorSession_host.set(this, void 0);
35
+ _EditorSession_fixedPort.set(this, void 0);
30
36
  _EditorSession_isRegistered.set(this, void 0);
37
+ _EditorSession_subscribeRegistrationChanges.set(this, void 0);
38
+ _EditorSession_unsubscribeFixedScope.set(this, void 0);
39
+ _EditorSession_unsubscribeFixedRegistration.set(this, void 0);
40
+ _EditorSession_fixedSavingController.set(this, void 0);
31
41
  __classPrivateFieldSet(this, _EditorSession_isRegistered, isRegistered, "f");
42
+ __classPrivateFieldSet(this, _EditorSession_subscribeRegistrationChanges, subscribeRegistrationChanges, "f");
32
43
  __classPrivateFieldSet(this, _EditorSession_definition, definition, "f");
33
- __classPrivateFieldSet(this, _EditorSession_snapshot, captureSnapshot(snapshot, captureReference(snapshot)), "f");
44
+ __classPrivateFieldSet(this, _EditorSession_snapshot, isFixedInputEditor(definition)
45
+ ? captureFixedSnapshot(snapshot, captureReference(snapshot), definition)
46
+ : captureSnapshot(snapshot, captureReference(snapshot)), "f");
34
47
  __classPrivateFieldSet(this, _EditorSession_host, host, "f");
35
- __classPrivateFieldSet(this, _EditorSession_draft, __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_copyDraft).call(this, definition.read(__classPrivateFieldGet(this, _EditorSession_snapshot, "f"))), "f");
48
+ __classPrivateFieldSet(this, _EditorSession_fixedPort, isFixedInputEditor(definition) && supportsFixedInputEditing(host) ? host.fixedInputs : undefined, "f");
49
+ if (isFixedInputEditor(definition) && !supportsFixedInputEditing(host))
50
+ throw new TypeError('Fixed input editors require a compatible host.');
51
+ __classPrivateFieldSet(this, _EditorSession_draft, __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_copyDraft).call(this, isFixedInputEditor(definition)
52
+ ? definition.readFixed(__classPrivateFieldGet(this, _EditorSession_snapshot, "f")) : definition.read(__classPrivateFieldGet(this, _EditorSession_snapshot, "f"))), "f");
53
+ if (isFixedInputEditor(definition) && __classPrivateFieldGet(this, _EditorSession_subscribeRegistrationChanges, "f")) {
54
+ const unsubscribe = __classPrivateFieldGet(this, _EditorSession_subscribeRegistrationChanges, "f").call(this, () => {
55
+ var _a;
56
+ if (__classPrivateFieldGet(this, _EditorSession_isRegistered, "f") && !__classPrivateFieldGet(this, _EditorSession_isRegistered, "f").call(this) && (__classPrivateFieldGet(this, _EditorSession_status, "f") === 'editing' || __classPrivateFieldGet(this, _EditorSession_status, "f") === 'saving')) {
57
+ (_a = __classPrivateFieldGet(this, _EditorSession_fixedSavingController, "f")) === null || _a === void 0 ? void 0 : _a.abort(new BlockEditorConflictError());
58
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_finish).call(this, 'disposed');
59
+ }
60
+ });
61
+ if (__classPrivateFieldGet(this, _EditorSession_status, "f") === 'editing')
62
+ __classPrivateFieldSet(this, _EditorSession_unsubscribeFixedRegistration, unsubscribe, "f");
63
+ else
64
+ unsubscribe();
65
+ }
66
+ try {
67
+ if (isFixedInputEditor(definition) && __classPrivateFieldGet(this, _EditorSession_fixedPort, "f")) {
68
+ let subscribe;
69
+ for (let item = __classPrivateFieldGet(this, _EditorSession_fixedPort, "f"), depth = 0; item && depth < 64; item = Object.getPrototypeOf(item), depth++) {
70
+ const property = Object.getOwnPropertyDescriptor(item, 'subscribeInvalidation');
71
+ if (property) {
72
+ subscribe = 'value' in property ? property.value : undefined;
73
+ break;
74
+ }
75
+ }
76
+ if (typeof subscribe === 'function') {
77
+ const unsubscribe = subscribe.call(__classPrivateFieldGet(this, _EditorSession_fixedPort, "f"), this.reference, definition, () => {
78
+ var _a;
79
+ if (__classPrivateFieldGet(this, _EditorSession_status, "f") !== 'editing' && __classPrivateFieldGet(this, _EditorSession_status, "f") !== 'saving')
80
+ return;
81
+ (_a = __classPrivateFieldGet(this, _EditorSession_fixedSavingController, "f")) === null || _a === void 0 ? void 0 : _a.abort(new BlockEditorConflictError());
82
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_finish).call(this, 'disposed');
83
+ });
84
+ if (typeof unsubscribe !== 'function')
85
+ throw new TypeError('Invalid fixed scope subscription.');
86
+ if (__classPrivateFieldGet(this, _EditorSession_status, "f") === 'editing')
87
+ __classPrivateFieldSet(this, _EditorSession_unsubscribeFixedScope, unsubscribe, "f");
88
+ else
89
+ unsubscribe();
90
+ }
91
+ }
92
+ }
93
+ catch (error) {
94
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_finish).call(this, 'disposed');
95
+ throw error;
96
+ }
36
97
  }
37
98
  /** Stable instance identity remains available after the session closes. */
38
99
  get reference() {
@@ -42,6 +103,36 @@ export class EditorSession {
42
103
  __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_assertOpen).call(this);
43
104
  return cloneJson(__classPrivateFieldGet(this, _EditorSession_draft, "f"));
44
105
  }
106
+ getFixedInputView() {
107
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_assertOpen).call(this);
108
+ const definition = __classPrivateFieldGet(this, _EditorSession_definition, "f");
109
+ if (!isFixedInputEditor(definition) || !definition.describeFixed)
110
+ return undefined;
111
+ let description;
112
+ try {
113
+ description = definition.describeFixed(__classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_copyDraft).call(this, __classPrivateFieldGet(this, _EditorSession_draft, "f")), __classPrivateFieldGet(this, _EditorSession_snapshot, "f"));
114
+ const captured = snapshotJson(description);
115
+ if (!isJsonRecord(captured) || !isJsonRecord(captured.inputs) ||
116
+ !Array.isArray(captured.issues) || !Array.isArray(captured.branches)) {
117
+ throw new TypeError('Invalid fixed input presentation.');
118
+ }
119
+ const freeze = (value) => {
120
+ if (value && typeof value === 'object') {
121
+ Object.values(value).forEach(freeze);
122
+ Object.freeze(value);
123
+ }
124
+ };
125
+ freeze(captured);
126
+ return captured;
127
+ }
128
+ catch (_a) {
129
+ try {
130
+ void Promise.prototype.then.call(description, () => undefined, () => undefined);
131
+ }
132
+ catch ( /* Never inspect arbitrary thenables. */_b) { /* Never inspect arbitrary thenables. */ }
133
+ throw new TypeError('Invalid fixed input presentation.');
134
+ }
135
+ }
45
136
  setDraft(draft) {
46
137
  if (__classPrivateFieldGet(this, _EditorSession_status, "f") !== 'editing')
47
138
  throw new Error('The session is not editable.');
@@ -82,6 +173,8 @@ export class EditorSession {
82
173
  try {
83
174
  if (__classPrivateFieldGet(this, _EditorSession_isRegistered, "f") && !__classPrivateFieldGet(this, _EditorSession_isRegistered, "f").call(this))
84
175
  throw new BlockEditorConflictError('The source editor registration expired.');
176
+ if (isFixedInputEditor(__classPrivateFieldGet(this, _EditorSession_definition, "f")))
177
+ return await __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_saveFixed).call(this);
85
178
  const prepared = isPreparedEditor(__classPrivateFieldGet(this, _EditorSession_definition, "f"))
86
179
  ? capturePreparedSave(__classPrivateFieldGet(this, _EditorSession_definition, "f"), cloneJson(__classPrivateFieldGet(this, _EditorSession_draft, "f")), __classPrivateFieldGet(this, _EditorSession_snapshot, "f")) : undefined;
87
180
  const issues = prepared ? (prepared.kind === 'invalid' ? prepared.issues : [])
@@ -135,7 +228,73 @@ export class EditorSession {
135
228
  return true;
136
229
  }
137
230
  }
138
- _EditorSession_draft = new WeakMap(), _EditorSession_status = new WeakMap(), _EditorSession_issues = new WeakMap(), _EditorSession_error = new WeakMap(), _EditorSession_listeners = new WeakMap(), _EditorSession_view = new WeakMap(), _EditorSession_definition = new WeakMap(), _EditorSession_snapshot = new WeakMap(), _EditorSession_host = new WeakMap(), _EditorSession_isRegistered = new WeakMap(), _EditorSession_instances = new WeakSet(), _EditorSession_prepareChanges = function _EditorSession_prepareChanges(patch) {
231
+ _EditorSession_draft = new WeakMap(), _EditorSession_status = new WeakMap(), _EditorSession_issues = new WeakMap(), _EditorSession_error = new WeakMap(), _EditorSession_listeners = new WeakMap(), _EditorSession_view = new WeakMap(), _EditorSession_definition = new WeakMap(), _EditorSession_snapshot = new WeakMap(), _EditorSession_host = new WeakMap(), _EditorSession_fixedPort = new WeakMap(), _EditorSession_isRegistered = new WeakMap(), _EditorSession_subscribeRegistrationChanges = new WeakMap(), _EditorSession_unsubscribeFixedScope = new WeakMap(), _EditorSession_unsubscribeFixedRegistration = new WeakMap(), _EditorSession_fixedSavingController = new WeakMap(), _EditorSession_instances = new WeakSet(), _EditorSession_saveFixed = async function _EditorSession_saveFixed() {
232
+ var _a;
233
+ const definition = __classPrivateFieldGet(this, _EditorSession_definition, "f");
234
+ if (!isFixedInputEditor(definition))
235
+ throw new TypeError('Fixed input capability is unavailable.');
236
+ if (!supportsFixedInputEditing(__classPrivateFieldGet(this, _EditorSession_host, "f")) || __classPrivateFieldGet(this, _EditorSession_host, "f").fixedInputs !== __classPrivateFieldGet(this, _EditorSession_fixedPort, "f")) {
237
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_finish).call(this, 'disposed');
238
+ throw new BlockEditorConflictError('The fixed input capability changed.');
239
+ }
240
+ const snapshot = __classPrivateFieldGet(this, _EditorSession_snapshot, "f");
241
+ const prepared = captureFixedPreparedSave(definition, __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_copyDraft).call(this, __classPrivateFieldGet(this, _EditorSession_draft, "f")), snapshot);
242
+ if (__classPrivateFieldGet(this, _EditorSession_status, "f") !== 'saving')
243
+ throw new BlockEditorConflictError();
244
+ if (prepared.kind === 'invalid') {
245
+ __classPrivateFieldSet(this, _EditorSession_issues, __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_copyIssues).call(this, prepared.issues), "f");
246
+ return { status: 'invalid', issues: __classPrivateFieldGet(this, _EditorSession_issues, "f") };
247
+ }
248
+ const changes = __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_prepareChanges).call(this, prepared.changes);
249
+ const port = __classPrivateFieldGet(this, _EditorSession_host, "f").fixedInputs;
250
+ if (__classPrivateFieldGet(this, _EditorSession_isRegistered, "f") && !__classPrivateFieldGet(this, _EditorSession_isRegistered, "f").call(this))
251
+ throw new BlockEditorConflictError('The fixed editor registration expired.');
252
+ const current = port.readBlock(snapshot, definition);
253
+ if (!current)
254
+ throw new BlockEditorConflictError();
255
+ try {
256
+ const captured = captureFixedSnapshot(current, snapshot, definition);
257
+ if (captured.fixedContext.generation !== snapshot.fixedContext.generation) {
258
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_finish).call(this, 'disposed');
259
+ throw new BlockEditorConflictError();
260
+ }
261
+ if (!sameFixedSnapshot(snapshot, captured))
262
+ throw new BlockEditorConflictError();
263
+ }
264
+ catch (_b) {
265
+ throw new BlockEditorConflictError();
266
+ }
267
+ if (!supportsFixedInputEditing(__classPrivateFieldGet(this, _EditorSession_host, "f")) || __classPrivateFieldGet(this, _EditorSession_host, "f").fixedInputs !== port ||
268
+ (__classPrivateFieldGet(this, _EditorSession_isRegistered, "f") && !__classPrivateFieldGet(this, _EditorSession_isRegistered, "f").call(this)))
269
+ throw new BlockEditorConflictError('The fixed editor registration expired.');
270
+ if (changes.length > 0) {
271
+ const controller = new AbortController();
272
+ __classPrivateFieldSet(this, _EditorSession_fixedSavingController, controller, "f");
273
+ const context = prepared.context;
274
+ const unsubscribe = (_a = __classPrivateFieldGet(this, _EditorSession_subscribeRegistrationChanges, "f")) === null || _a === void 0 ? void 0 : _a.call(this, () => {
275
+ if (__classPrivateFieldGet(this, _EditorSession_isRegistered, "f") && !__classPrivateFieldGet(this, _EditorSession_isRegistered, "f").call(this))
276
+ controller.abort(new BlockEditorConflictError('The fixed editor registration expired.'));
277
+ });
278
+ try {
279
+ if (__classPrivateFieldGet(this, _EditorSession_isRegistered, "f") && !__classPrivateFieldGet(this, _EditorSession_isRegistered, "f").call(this))
280
+ throw new BlockEditorConflictError('The fixed editor registration expired.');
281
+ await port.commit(Object.freeze({ expected: snapshot, changes, context, signal: controller.signal }));
282
+ if (controller.signal.aborted)
283
+ throw new BlockEditorConflictError('The fixed editor registration expired.');
284
+ }
285
+ catch (error) {
286
+ if (controller.signal.aborted)
287
+ throw new BlockEditorConflictError('The fixed editor registration expired.');
288
+ throw error;
289
+ }
290
+ finally {
291
+ unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
292
+ __classPrivateFieldSet(this, _EditorSession_fixedSavingController, undefined, "f");
293
+ }
294
+ }
295
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_finish).call(this, 'saved');
296
+ return { status: 'saved', changed: changes.length > 0 };
297
+ }, _EditorSession_prepareChanges = function _EditorSession_prepareChanges(patch) {
139
298
  if (!Array.isArray(patch))
140
299
  throw new TypeError('createPatch() must return an array.');
141
300
  const seen = new Set();
@@ -151,11 +310,23 @@ _EditorSession_draft = new WeakMap(), _EditorSession_status = new WeakMap(), _Ed
151
310
  if (!slot || slot.kind !== 'literal') {
152
311
  throw new TypeError('Only existing literal arguments can be changed.');
153
312
  }
154
- if (slot.value !== change.value)
313
+ if (isFixedInputEditor(__classPrivateFieldGet(this, _EditorSession_definition, "f"))) {
314
+ const metadata = __classPrivateFieldGet(this, _EditorSession_snapshot, "f").fixedContext.inputs[change.argument];
315
+ if (!metadata || metadata.role !== 'editable' || (metadata.source !== 'field' && metadata.source !== 'shadow'))
316
+ throw new TypeError('Fixed patches require editable literal fields.');
317
+ if (!Object.is(slot.value, change.value)) {
318
+ changes.push(Object.freeze({ argument: change.argument, value: change.value }));
319
+ }
320
+ }
321
+ else if (slot.value !== change.value)
155
322
  changes.push(Object.freeze({ ...change }));
156
323
  }
324
+ if (isFixedInputEditor(__classPrivateFieldGet(this, _EditorSession_definition, "f")) && validateFixedBranchChanges(__classPrivateFieldGet(this, _EditorSession_definition, "f"), __classPrivateFieldGet(this, _EditorSession_snapshot, "f"), changes).length)
325
+ throw new TypeError('Fixed dependency validation is unavailable.');
157
326
  return Object.freeze(changes);
158
327
  }, _EditorSession_copyIssues = function _EditorSession_copyIssues(issues) {
328
+ if (isFixedInputEditor(__classPrivateFieldGet(this, _EditorSession_definition, "f")))
329
+ issues = snapshotJson(issues);
159
330
  if (!Array.isArray(issues))
160
331
  throw new TypeError('Expected a validation issue array.');
161
332
  return Object.freeze(issues.map(issue => {
@@ -169,7 +340,18 @@ _EditorSession_draft = new WeakMap(), _EditorSession_status = new WeakMap(), _Ed
169
340
  if (!draft || typeof draft !== 'object' || Array.isArray(draft)) {
170
341
  throw new TypeError('The editor draft must be a JSON object.');
171
342
  }
172
- return cloneJson(draft);
343
+ if (!isFixedInputEditor(__classPrivateFieldGet(this, _EditorSession_definition, "f")))
344
+ return cloneJson(draft);
345
+ try {
346
+ return snapshotJson(draft);
347
+ }
348
+ catch (error) {
349
+ try {
350
+ void Promise.prototype.then.call(draft, () => undefined, () => undefined);
351
+ }
352
+ catch ( /* Synchronous fixed drafts never inspect arbitrary thenables. */_a) { /* Synchronous fixed drafts never inspect arbitrary thenables. */ }
353
+ throw error;
354
+ }
173
355
  }, _EditorSession_assertOpen = function _EditorSession_assertOpen() {
174
356
  if (__classPrivateFieldGet(this, _EditorSession_status, "f") !== 'editing' && __classPrivateFieldGet(this, _EditorSession_status, "f") !== 'saving') {
175
357
  throw new Error('The session is closed.');
@@ -177,6 +359,22 @@ _EditorSession_draft = new WeakMap(), _EditorSession_status = new WeakMap(), _Ed
177
359
  }, _EditorSession_finish = function _EditorSession_finish(status) {
178
360
  __classPrivateFieldSet(this, _EditorSession_status, status, "f");
179
361
  __classPrivateFieldSet(this, _EditorSession_draft, {}, "f");
362
+ const unsubscribe = __classPrivateFieldGet(this, _EditorSession_unsubscribeFixedScope, "f");
363
+ __classPrivateFieldSet(this, _EditorSession_unsubscribeFixedScope, undefined, "f");
364
+ try {
365
+ unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
366
+ }
367
+ catch (error) {
368
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_reportObserverError).call(this, error);
369
+ }
370
+ const unsubscribeRegistration = __classPrivateFieldGet(this, _EditorSession_unsubscribeFixedRegistration, "f");
371
+ __classPrivateFieldSet(this, _EditorSession_unsubscribeFixedRegistration, undefined, "f");
372
+ try {
373
+ unsubscribeRegistration === null || unsubscribeRegistration === void 0 ? void 0 : unsubscribeRegistration();
374
+ }
375
+ catch (error) {
376
+ __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_reportObserverError).call(this, error);
377
+ }
180
378
  __classPrivateFieldGet(this, _EditorSession_instances, "m", _EditorSession_notify).call(this);
181
379
  try {
182
380
  __classPrivateFieldGet(this, _EditorSession_view, "f").unmount();
@@ -1,5 +1,5 @@
1
1
  export default createBlockEditorBridge;
2
- declare function createBlockEditorBridge({ ScratchBlocks, workspace, vm, service, label, canOpen, onOpen, onError, descendants }: {
2
+ declare function createBlockEditorBridge({ ScratchBlocks, workspace, vm, service, label, canOpen, onOpen, onError, descendants, fixedInputs }: {
3
3
  ScratchBlocks: any;
4
4
  workspace: any;
5
5
  vm: any;
@@ -9,6 +9,7 @@ declare function createBlockEditorBridge({ ScratchBlocks, workspace, vm, service
9
9
  onOpen: any;
10
10
  onError: any;
11
11
  descendants?: boolean | undefined;
12
+ fixedInputs?: boolean | undefined;
12
13
  }): {
13
14
  refresh: () => void;
14
15
  dispose: () => void;
@@ -1,22 +1,32 @@
1
1
  import createBlockEditorHost from './host.js';
2
2
  import bindBlockEditorIcon from './icon.js';
3
3
  import readBlockEditorAppearance from './appearance.js';
4
- import { supportsDescendantEditing } from '../index.js';
4
+ import { supportsDescendantEditing, supportsFixedInputEditing } from '../index.js';
5
5
  import createBlockEditorErrorSession from './error-session.js';
6
- const openBlockEditorSession = ({ registry, reference, host, descendants }) => (descendants && supportsDescendantEditing(host) ?
7
- registry.openDescendants(reference, host) : registry.open(reference, host));
8
- const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, canOpen, onOpen, onError, descendants = false }) => {
6
+ const fixedDeclaration = (registry, snapshot) => snapshot && typeof registry.resolveFixed === 'function' &&
7
+ registry.resolveFixed(snapshot.opcode);
8
+ const openBlockEditorSession = ({ registry, reference, host, descendants }) => {
9
+ const snapshot = host.readBlock ? host.readBlock(reference) : null;
10
+ // A fixed registration owns only this block; legacy aggregate traversal stays fail-closed.
11
+ if (fixedDeclaration(registry, snapshot))
12
+ return supportsFixedInputEditing(host) ? registry.open(reference, host) : undefined;
13
+ return descendants && supportsDescendantEditing(host) ?
14
+ registry.openDescendants(reference, host) : registry.open(reference, host);
15
+ };
16
+ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label, canOpen, onOpen, onError, descendants = false, fixedInputs = false }) => {
9
17
  const host = createBlockEditorHost({ ScratchBlocks,
10
18
  workspace,
11
19
  vm,
12
20
  registry: service.registry,
13
21
  enableDescendants: descendants,
22
+ enableFixedInputs: fixedInputs,
14
23
  onError });
15
24
  const decorations = new Map();
16
25
  let disposed = false;
17
26
  let timer = null;
18
27
  let activeSession = null;
19
28
  let openingSnapshot = null;
29
+ let openingFixedDeclaration = null;
20
30
  let stopWaiting = null;
21
31
  const endSession = () => {
22
32
  const session = activeSession;
@@ -41,6 +51,7 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
41
51
  }
42
52
  };
43
53
  const checkSession = () => {
54
+ var _a;
44
55
  // The host owns rollback. Its synchronous transaction must retain the draft on failure.
45
56
  if (host.isCommitting())
46
57
  return;
@@ -49,6 +60,14 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
49
60
  return;
50
61
  const current = typeof activeSession.getNodes === 'function' ?
51
62
  host.descendants.readSubtree(activeSession.reference) : host.readBlock(activeSession.reference);
63
+ if (openingFixedDeclaration) {
64
+ // Same-target external edits conflict at save while the session retains its draft.
65
+ // Project/target/registration replacement ends the session and drops that draft.
66
+ if (!current || ((_a = current.fixedContext) === null || _a === void 0 ? void 0 : _a.generation) !== openingSnapshot.fixedContext.generation ||
67
+ fixedDeclaration(service.registry, current) !== openingFixedDeclaration)
68
+ endSession();
69
+ return;
70
+ }
52
71
  if (!current || JSON.stringify(current) !== JSON.stringify(openingSnapshot))
53
72
  endSession();
54
73
  };
@@ -56,6 +75,8 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
56
75
  if (disposed || !vm.editingTarget || !canOpen() || !service.registry.resolve(block.type))
57
76
  return false;
58
77
  const snapshot = host.readBlock({ targetId: vm.editingTarget.id, blockId: block.id });
78
+ if (fixedDeclaration(service.registry, snapshot))
79
+ return supportsFixedInputEditing(host);
59
80
  return snapshot && Object.values(snapshot.arguments).every(slot => slot.kind === 'literal');
60
81
  };
61
82
  const open = block => {
@@ -71,6 +92,7 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
71
92
  activeSession = session;
72
93
  openingSnapshot = typeof session.getNodes === 'function' ?
73
94
  host.descendants.readSubtree(session.reference) : host.readBlock(session.reference);
95
+ openingFixedDeclaration = fixedDeclaration(service.registry, openingSnapshot) || null;
74
96
  const labels = {};
75
97
  const appearances = Object.create(null);
76
98
  if (typeof session.getNodes === 'function') {
@@ -88,6 +110,7 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
88
110
  onError(error);
89
111
  activeSession = createBlockEditorErrorSession(reference, error);
90
112
  openingSnapshot = null;
113
+ openingFixedDeclaration = null;
91
114
  onOpen(activeSession);
92
115
  }
93
116
  };
@@ -137,7 +160,13 @@ const createBlockEditorBridge = ({ ScratchBlocks, workspace, vm, service, label,
137
160
  };
138
161
  const unregister = service.subscribe(() => {
139
162
  // Aggregate sessions observe relevant registry changes themselves.
140
- if (!activeSession || typeof activeSession.getNodes !== 'function') {
163
+ if (openingFixedDeclaration && activeSession) {
164
+ if (service.registry.resolveFixed(openingSnapshot.opcode) !== openingFixedDeclaration) {
165
+ host.invalidate();
166
+ endSession();
167
+ }
168
+ }
169
+ else if (!activeSession || typeof activeSession.getNodes !== 'function') {
141
170
  host.invalidate();
142
171
  endSession();
143
172
  }