@powerhousedao/powerhouse-vetra-packages 6.2.2-dev.7 → 6.2.2-dev.70

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 (103) hide show
  1. package/dist/browser/assets/{entry-Cvoo4_c9.js → entry-BBghrmE1.js} +3 -2
  2. package/dist/browser/assets/{projection-entry-DVec8YRh.js → projection-entry-BtmaPdIp.js} +4 -4
  3. package/dist/browser/{linting-Dn6pXRkK.js → button-CuO8Gh3v.js} +20 -6
  4. package/dist/browser/button-CuO8Gh3v.js.map +1 -0
  5. package/dist/browser/{connect-KEU-HR3o.js → connect-DmCpI0kg.js} +916 -200
  6. package/dist/browser/connect-DmCpI0kg.js.map +1 -0
  7. package/dist/browser/{dist-CXoKspdx.js → dist-B4FWbuEM.js} +10 -2
  8. package/dist/browser/{dist-CXoKspdx.js.map → dist-B4FWbuEM.js.map} +1 -1
  9. package/dist/{node/dist-BeZaEP6S.mjs → browser/dist-BAJ5nRDl.js} +21 -2
  10. package/dist/browser/{dist-D8H48e8N.js.map → dist-BAJ5nRDl.js.map} +1 -1
  11. package/dist/browser/{dist-D5ra2aRj.js → dist-DfoAQf6g.js} +1617 -1293
  12. package/dist/browser/dist-DfoAQf6g.js.map +1 -0
  13. package/dist/browser/{document-drive-IdFV1QXL.js → document-drive-D6XhjHzr.js} +1184 -122
  14. package/dist/browser/document-drive-D6XhjHzr.js.map +1 -0
  15. package/dist/browser/document-models/index.js +1 -1
  16. package/dist/browser/{documents-D4ek7Ubv.js → documents-J_l59mSV.js} +5 -604
  17. package/dist/browser/documents-J_l59mSV.js.map +1 -0
  18. package/dist/browser/editor-C069kNOj.js +25 -0
  19. package/dist/browser/editor-C069kNOj.js.map +1 -0
  20. package/dist/browser/{editor-DiZF3ao3.js → editor-XlOiVjqp.js} +671 -236
  21. package/dist/browser/editor-XlOiVjqp.js.map +1 -0
  22. package/dist/browser/editors/document-model-editor/module.js +1 -1
  23. package/dist/browser/editors/generic-drive-explorer/index.js +5 -5
  24. package/dist/browser/editors/generic-drive-explorer/module.js +1 -1
  25. package/dist/{node/folder-view-Cy-QxsDg.mjs → browser/folder-view-B4b9Ik-G.js} +73 -46
  26. package/dist/browser/folder-view-B4b9Ik-G.js.map +1 -0
  27. package/dist/browser/{graphql-editor-ZLRO_8Ce.js → graphql-editor-BDze7_wI.js} +8 -7
  28. package/dist/browser/{graphql-editor-ZLRO_8Ce.js.map → graphql-editor-BDze7_wI.js.map} +1 -1
  29. package/dist/browser/{hooks-CORHBNHb.js → hooks-KKcNp2X0.js} +2 -2
  30. package/dist/browser/{hooks-CORHBNHb.js.map → hooks-KKcNp2X0.js.map} +1 -1
  31. package/dist/browser/index.js +378 -9
  32. package/dist/browser/index.js.map +1 -1
  33. package/dist/browser/{json-editor-DBuZ6gN7.js → json-editor-nI61gbA-.js} +4 -4
  34. package/dist/browser/{json-editor-DBuZ6gN7.js.map → json-editor-nI61gbA-.js.map} +1 -1
  35. package/dist/browser/{lib-C-f3izXz.js → lib-CE5V8jW5.js} +13 -4
  36. package/dist/browser/lib-CE5V8jW5.js.map +1 -0
  37. package/dist/browser/printer-CEYr4JOg.js +604 -0
  38. package/dist/browser/printer-CEYr4JOg.js.map +1 -0
  39. package/dist/browser/{schema-context-DY-GEGnY.js → schema-context-ZyeclQwy.js} +2 -2
  40. package/dist/browser/{schema-context-DY-GEGnY.js.map → schema-context-ZyeclQwy.js.map} +1 -1
  41. package/dist/browser/{state-schemas-BjQKM498.js → state-schemas-DvpLHgMU.js} +8 -18
  42. package/dist/browser/state-schemas-DvpLHgMU.js.map +1 -0
  43. package/dist/node/{linting-Dx50GuLN.mjs → button-Da7CxMn7.mjs} +20 -7
  44. package/dist/node/button-Da7CxMn7.mjs.map +1 -0
  45. package/dist/node/{connect-KcYZcy_Z.mjs → connect-BOwTtHRq.mjs} +916 -200
  46. package/dist/node/connect-BOwTtHRq.mjs.map +1 -0
  47. package/dist/node/{dist-DJEK2WVi.mjs → dist-CRrgpr8A.mjs} +1621 -1292
  48. package/dist/node/dist-CRrgpr8A.mjs.map +1 -0
  49. package/dist/{browser/dist-D8H48e8N.js → node/dist-CzYOpeXN.mjs} +21 -2
  50. package/dist/node/{dist-BeZaEP6S.mjs.map → dist-CzYOpeXN.mjs.map} +1 -1
  51. package/dist/node/{dist-fA4EItr0.mjs → dist-DT7jI9ol.mjs} +10 -2
  52. package/dist/node/{dist-fA4EItr0.mjs.map → dist-DT7jI9ol.mjs.map} +1 -1
  53. package/dist/node/{document-drive-C8hbqQ3C.mjs → document-drive-B65n0lIk.mjs} +1184 -122
  54. package/dist/node/document-drive-B65n0lIk.mjs.map +1 -0
  55. package/dist/node/document-models/index.mjs +1 -1
  56. package/dist/node/{documents-BFBPmyw1.mjs → documents-DCf53bzO.mjs} +3 -3
  57. package/dist/node/{documents-BFBPmyw1.mjs.map → documents-DCf53bzO.mjs.map} +1 -1
  58. package/dist/node/{editor-B1KhoF1f.mjs → editor-BGcLm6LA.mjs} +672 -237
  59. package/dist/node/editor-BGcLm6LA.mjs.map +1 -0
  60. package/dist/node/editor-DIiXhhl2.mjs +25 -0
  61. package/dist/node/editor-DIiXhhl2.mjs.map +1 -0
  62. package/dist/node/editors/document-model-editor/module.mjs +1 -1
  63. package/dist/node/editors/generic-drive-explorer/index.mjs +5 -5
  64. package/dist/node/editors/generic-drive-explorer/module.mjs +1 -1
  65. package/dist/{browser/folder-view-DMFqcJhc.js → node/folder-view-DyijTEeD.mjs} +73 -46
  66. package/dist/node/folder-view-DyijTEeD.mjs.map +1 -0
  67. package/dist/node/{graphql-DskHmkMe.mjs → graphql-BfAoPeWM.mjs} +2 -2
  68. package/dist/node/{graphql-DskHmkMe.mjs.map → graphql-BfAoPeWM.mjs.map} +1 -1
  69. package/dist/node/{graphql-editor-C5VLRqEf.mjs → graphql-editor-5YU1uHpd.mjs} +7 -7
  70. package/dist/node/{graphql-editor-C5VLRqEf.mjs.map → graphql-editor-5YU1uHpd.mjs.map} +1 -1
  71. package/dist/node/{hooks-DJrjfVaS.mjs → hooks-D0DcS3MV.mjs} +2 -2
  72. package/dist/node/{hooks-DJrjfVaS.mjs.map → hooks-D0DcS3MV.mjs.map} +1 -1
  73. package/dist/node/index.mjs +378 -9
  74. package/dist/node/index.mjs.map +1 -1
  75. package/dist/node/{json-editor-iI2s9a_4.mjs → json-editor-iuJkZEgS.mjs} +4 -4
  76. package/dist/node/{json-editor-iI2s9a_4.mjs.map → json-editor-iuJkZEgS.mjs.map} +1 -1
  77. package/dist/node/{main-D82dkD7g.mjs → main-B5JSm6Hi.mjs} +15 -6
  78. package/dist/node/main-B5JSm6Hi.mjs.map +1 -0
  79. package/dist/node/{schema-context-CX5ml_9t.mjs → schema-context-DL8jhi_d.mjs} +3 -3
  80. package/dist/node/{schema-context-CX5ml_9t.mjs.map → schema-context-DL8jhi_d.mjs.map} +1 -1
  81. package/dist/node/{state-schemas-Bl7nA8bB.mjs → state-schemas-DHQAxfto.mjs} +10 -20
  82. package/dist/{browser/state-schemas-BjQKM498.js.map → node/state-schemas-DHQAxfto.mjs.map} +1 -1
  83. package/package.json +8 -7
  84. package/dist/browser/connect-KEU-HR3o.js.map +0 -1
  85. package/dist/browser/dist-D5ra2aRj.js.map +0 -1
  86. package/dist/browser/document-drive-IdFV1QXL.js.map +0 -1
  87. package/dist/browser/documents-D4ek7Ubv.js.map +0 -1
  88. package/dist/browser/editor-DiZF3ao3.js.map +0 -1
  89. package/dist/browser/editor-SqNULDP-.js +0 -29
  90. package/dist/browser/editor-SqNULDP-.js.map +0 -1
  91. package/dist/browser/folder-view-DMFqcJhc.js.map +0 -1
  92. package/dist/browser/lib-C-f3izXz.js.map +0 -1
  93. package/dist/browser/linting-Dn6pXRkK.js.map +0 -1
  94. package/dist/node/connect-KcYZcy_Z.mjs.map +0 -1
  95. package/dist/node/dist-DJEK2WVi.mjs.map +0 -1
  96. package/dist/node/document-drive-C8hbqQ3C.mjs.map +0 -1
  97. package/dist/node/editor-B1KhoF1f.mjs.map +0 -1
  98. package/dist/node/editor-yBGEvMGD.mjs +0 -29
  99. package/dist/node/editor-yBGEvMGD.mjs.map +0 -1
  100. package/dist/node/folder-view-Cy-QxsDg.mjs.map +0 -1
  101. package/dist/node/linting-Dx50GuLN.mjs.map +0 -1
  102. package/dist/node/main-D82dkD7g.mjs.map +0 -1
  103. package/dist/node/state-schemas-Bl7nA8bB.mjs.map +0 -1
@@ -1,145 +1,14 @@
1
- import { C as parse, T as $ZodError, _ as string, a as snakeCase, b as url, h as object, n as constantCase, p as literal, r as pascalCase, v as union, w as parseAsync } from "./dist-fA4EItr0.mjs";
2
- import { D as deleteOperationError, E as deleteOperation, F as setModelDescription, G as setStateSchema, H as setOperationErrorName, I as setModelExtension, L as setModelId, M as setAuthorName, N as setAuthorWebsite, P as setInitialState, R as setModelName, T as deleteModule, U as setOperationName, V as setOperationDescription, W as setOperationSchema, X as generateId, f as addModule, m as addOperationError, p as addOperation, z as setModuleName } from "./document-drive-C8hbqQ3C.mjs";
3
- import { c as FormProvider, d as set, f as useForm, l as appendErrors, p as useFormContext, r as DocumentToolbar, s as Controller, u as get } from "./connect-KcYZcy_Z.mjs";
4
- import { C as twMerge, y as composeRefs } from "./dist-BeZaEP6S.mjs";
5
- import { A as useSetPHDocumentEditorConfig, C as usePHToast, w as useSelectedDocumentOfType } from "./dist-DJEK2WVi.mjs";
6
- import { a as handleModelNameChange, c as makeEmptyOperationSchema, d as makeOperationInitialDoc, i as compareStringsWithoutWhitespace, l as makeInitialSchemaDoc, o as initializeModelSchema, p as renameSchemaType, s as isEmptyOperationSchema, t as ensureValidOperationSchemaInputName } from "./linting-Dx50GuLN.mjs";
7
- import { t as SchemaContextProvider } from "./schema-context-CX5ml_9t.mjs";
1
+ import { E as $ZodError, T as parseAsync, a as snakeCase, h as object, n as constantCase, p as literal, r as pascalCase, v as string, w as parse$1, x as url, y as union } from "./dist-DT7jI9ol.mjs";
2
+ import { $ as setOperationErrorName, G as setInitialState, J as setModelId, K as setModelDescription, M as deleteModule, N as deleteOperation, P as deleteOperationError, Q as setOperationDescription, U as setAuthorName, V as releaseNewVersion, W as setAuthorWebsite, X as setModuleName, Y as setModelName, _ as addOperationError, ct as generateId, et as setOperationName, g as addOperation, h as addModule, nt as setStateSchema, q as setModelExtension, tt as setOperationSchema } from "./document-drive-B65n0lIk.mjs";
3
+ import { t as require_graphql } from "./graphql-BfAoPeWM.mjs";
4
+ import { _ as Modal, a as DocumentToolbar, b as Primitive, c as ModalButton, d as FormProvider, f as appendErrors, g as useFormContext, h as useForm, m as set, p as get, r as ConnectSelect, u as Controller, x as Slot } from "./connect-BOwTtHRq.mjs";
5
+ import { w as twMerge } from "./dist-CzYOpeXN.mjs";
6
+ import { P as usePHToast, m as useSelectedDocumentOfType, y as useSetPHDocumentEditorConfig } from "./dist-CRrgpr8A.mjs";
7
+ import { a as compareStringsWithoutWhitespace, c as isEmptyOperationSchema, f as makeOperationInitialDoc, l as makeEmptyOperationSchema, m as renameSchemaType, n as ensureValidOperationSchemaInputName, o as handleModelNameChange, s as initializeModelSchema, t as Button, u as makeInitialSchemaDoc } from "./button-Da7CxMn7.mjs";
8
+ import { t as SchemaContextProvider } from "./schema-context-DL8jhi_d.mjs";
8
9
  import * as React$1 from "react";
9
10
  import React, { Suspense, forwardRef, lazy, useCallback, useEffect, useId, useImperativeHandle, useRef, useState } from "react";
10
- import { jsx, jsxs } from "react/jsx-runtime";
11
- import "react-dom";
12
- //#region ../../node_modules/.pnpm/@radix-ui+react-slot@1.2.4_@types+react@19.2.14_react@19.2.6/node_modules/@radix-ui/react-slot/dist/index.mjs
13
- var REACT_LAZY_TYPE = Symbol.for("react.lazy");
14
- var use$1 = React$1[" use ".trim().toString()];
15
- function isPromiseLike(value) {
16
- return typeof value === "object" && value !== null && "then" in value;
17
- }
18
- function isLazyComponent(element) {
19
- return element != null && typeof element === "object" && "$$typeof" in element && element.$$typeof === REACT_LAZY_TYPE && "_payload" in element && isPromiseLike(element._payload);
20
- }
21
- /* @__NO_SIDE_EFFECTS__ */
22
- function createSlot(ownerName) {
23
- const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);
24
- const Slot2 = React$1.forwardRef((props, forwardedRef) => {
25
- let { children, ...slotProps } = props;
26
- if (isLazyComponent(children) && typeof use$1 === "function") children = use$1(children._payload);
27
- const childrenArray = React$1.Children.toArray(children);
28
- const slottable = childrenArray.find(isSlottable);
29
- if (slottable) {
30
- const newElement = slottable.props.children;
31
- const newChildren = childrenArray.map((child) => {
32
- if (child === slottable) {
33
- if (React$1.Children.count(newElement) > 1) return React$1.Children.only(null);
34
- return React$1.isValidElement(newElement) ? newElement.props.children : null;
35
- } else return child;
36
- });
37
- return /* @__PURE__ */ jsx(SlotClone, {
38
- ...slotProps,
39
- ref: forwardedRef,
40
- children: React$1.isValidElement(newElement) ? React$1.cloneElement(newElement, void 0, newChildren) : null
41
- });
42
- }
43
- return /* @__PURE__ */ jsx(SlotClone, {
44
- ...slotProps,
45
- ref: forwardedRef,
46
- children
47
- });
48
- });
49
- Slot2.displayName = `${ownerName}.Slot`;
50
- return Slot2;
51
- }
52
- var Slot = /* @__PURE__ */ createSlot("Slot");
53
- /* @__NO_SIDE_EFFECTS__ */
54
- function createSlotClone(ownerName) {
55
- const SlotClone = React$1.forwardRef((props, forwardedRef) => {
56
- let { children, ...slotProps } = props;
57
- if (isLazyComponent(children) && typeof use$1 === "function") children = use$1(children._payload);
58
- if (React$1.isValidElement(children)) {
59
- const childrenRef = getElementRef(children);
60
- const props2 = mergeProps(slotProps, children.props);
61
- if (children.type !== React$1.Fragment) props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
62
- return React$1.cloneElement(children, props2);
63
- }
64
- return React$1.Children.count(children) > 1 ? React$1.Children.only(null) : null;
65
- });
66
- SlotClone.displayName = `${ownerName}.SlotClone`;
67
- return SlotClone;
68
- }
69
- var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
70
- function isSlottable(child) {
71
- return React$1.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
72
- }
73
- function mergeProps(slotProps, childProps) {
74
- const overrideProps = { ...childProps };
75
- for (const propName in childProps) {
76
- const slotPropValue = slotProps[propName];
77
- const childPropValue = childProps[propName];
78
- if (/^on[A-Z]/.test(propName)) {
79
- if (slotPropValue && childPropValue) overrideProps[propName] = (...args) => {
80
- const result = childPropValue(...args);
81
- slotPropValue(...args);
82
- return result;
83
- };
84
- else if (slotPropValue) overrideProps[propName] = slotPropValue;
85
- } else if (propName === "style") overrideProps[propName] = {
86
- ...slotPropValue,
87
- ...childPropValue
88
- };
89
- else if (propName === "className") overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
90
- }
91
- return {
92
- ...slotProps,
93
- ...overrideProps
94
- };
95
- }
96
- function getElementRef(element) {
97
- let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
98
- let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
99
- if (mayWarn) return element.ref;
100
- getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
101
- mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
102
- if (mayWarn) return element.props.ref;
103
- return element.props.ref || element.ref;
104
- }
105
- //#endregion
106
- //#region ../../node_modules/.pnpm/@radix-ui+react-primitive@2.1.4_@types+react-dom@19.2.3_@types+react@19.2.14__@types+re_c8c8fd2647f03197dbf56370d7498033/node_modules/@radix-ui/react-primitive/dist/index.mjs
107
- var Primitive = [
108
- "a",
109
- "button",
110
- "div",
111
- "form",
112
- "h2",
113
- "h3",
114
- "img",
115
- "input",
116
- "label",
117
- "li",
118
- "nav",
119
- "ol",
120
- "p",
121
- "select",
122
- "span",
123
- "svg",
124
- "ul"
125
- ].reduce((primitive, node) => {
126
- const Slot = /* @__PURE__ */ createSlot(`Primitive.${node}`);
127
- const Node = React$1.forwardRef((props, forwardedRef) => {
128
- const { asChild, ...primitiveProps } = props;
129
- const Comp = asChild ? Slot : node;
130
- if (typeof window !== "undefined") window[Symbol.for("radix-ui")] = true;
131
- return /* @__PURE__ */ jsx(Comp, {
132
- ...primitiveProps,
133
- ref: forwardedRef
134
- });
135
- });
136
- Node.displayName = `Primitive.${node}`;
137
- return {
138
- ...primitive,
139
- [node]: Node
140
- };
141
- }, {});
142
- //#endregion
11
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
143
12
  //#region ../../node_modules/.pnpm/clsx@2.0.0/node_modules/clsx/dist/clsx.mjs
144
13
  function r$1(e) {
145
14
  var t, f, n = "";
@@ -328,7 +197,7 @@ function a(o$1, a, u) {
328
197
  }(o$1)) return function(s, c, f) {
329
198
  try {
330
199
  return Promise.resolve(t(function() {
331
- return Promise.resolve(("sync" === u.mode ? parse : parseAsync)(o$1, s, a)).then(function(e) {
200
+ return Promise.resolve(("sync" === u.mode ? parse$1 : parseAsync)(o$1, s, a)).then(function(e) {
332
201
  return f.shouldUseNativeValidation && o({}, f), {
333
202
  errors: {},
334
203
  values: u.raw ? Object.assign({}, s) : e
@@ -888,7 +757,7 @@ function OperationErrors({ operation, addOperationError, deleteOperationError, s
888
757
  }
889
758
  //#endregion
890
759
  //#region editors/document-model-editor/components/operation.tsx
891
- const GraphqlEditor = lazy(() => import("./graphql-editor-C5VLRqEf.mjs"));
760
+ const GraphqlEditor = lazy(() => import("./graphql-editor-5YU1uHpd.mjs"));
892
761
  function Operation(props) {
893
762
  const { operation, module, allOperationNames, lastCreatedOperationId, onAddOperationAndInitialSchema, updateOperationName, deleteOperation, updateOperationSchema, setOperationDescription, addOperationError, deleteOperationError, setOperationErrorName, toggleNoInputRequired } = props;
894
763
  const noInputRequired = isEmptyOperationSchema(operation.schema);
@@ -1101,6 +970,226 @@ function Modules({ modules, allOperations, addModule, updateModuleName, deleteMo
1101
970
  });
1102
971
  }
1103
972
  //#endregion
973
+ //#region editors/document-model-editor/components/version-controls.tsx
974
+ const compactButtonStyle$1 = "min-h-0 min-w-0 flex-none rounded-lg px-6 py-1.5 text-sm whitespace-nowrap";
975
+ function VersionControls(props) {
976
+ const { specifications, viewedVersion, onViewVersion, onReleaseNewVersion } = props;
977
+ const [showReleaseModal, setShowReleaseModal] = useState(false);
978
+ const latestVersion = specifications[specifications.length - 1].version;
979
+ const nextVersion = latestVersion + 1;
980
+ return /* @__PURE__ */ jsxs("div", {
981
+ className: "mb-4 flex items-center justify-between gap-4",
982
+ children: [
983
+ /* @__PURE__ */ jsxs("div", {
984
+ className: "flex items-center gap-2",
985
+ children: [/* @__PURE__ */ jsxs("span", {
986
+ className: "rounded-md bg-muted px-2 py-0.5 font-mono text-xs text-foreground",
987
+ "data-testid": "model-version-badge",
988
+ children: ["Version ", viewedVersion]
989
+ }), specifications.length >= 2 && /* @__PURE__ */ jsx("div", {
990
+ "aria-label": "Document model version",
991
+ "data-testid": "model-version-switcher",
992
+ children: /* @__PURE__ */ jsx(ConnectSelect, {
993
+ absolutePositionMenu: true,
994
+ containerClassName: "z-10 [&_svg]:size-4",
995
+ id: "model-version-switcher",
996
+ itemClassName: "gap-1 px-2 py-1 font-mono text-xs leading-none [&_p:empty]:hidden",
997
+ items: specifications.map((spec) => ({
998
+ value: String(spec.version),
999
+ displayValue: /* @__PURE__ */ jsx("span", {
1000
+ className: "normal-case",
1001
+ children: spec.version === latestVersion ? `v${spec.version} (latest)` : `v${spec.version} (frozen)`
1002
+ })
1003
+ })),
1004
+ listClassName: "border border-t-0 border-border shadow-md",
1005
+ menuClassName: "min-w-0 pr-1.5",
1006
+ onChange: (value) => {
1007
+ const version = Number(value);
1008
+ onViewVersion(version === latestVersion ? "latest" : version);
1009
+ },
1010
+ value: String(viewedVersion)
1011
+ })
1012
+ })]
1013
+ }),
1014
+ /* @__PURE__ */ jsx(Button, {
1015
+ className: "inline-flex h-8 items-center justify-center py-0",
1016
+ "data-testid": "release-new-version-button",
1017
+ onClick: () => setShowReleaseModal(true),
1018
+ type: "button",
1019
+ children: "Release new version"
1020
+ }),
1021
+ /* @__PURE__ */ jsx(Modal, {
1022
+ open: showReleaseModal,
1023
+ onOpenChange: (status) => {
1024
+ if (!status) setShowReleaseModal(false);
1025
+ },
1026
+ children: /* @__PURE__ */ jsxs("div", {
1027
+ className: "w-[440px] p-6",
1028
+ children: [
1029
+ /* @__PURE__ */ jsxs("div", {
1030
+ className: "pb-2 text-2xl font-bold text-foreground",
1031
+ children: ["Release version ", nextVersion]
1032
+ }),
1033
+ /* @__PURE__ */ jsxs("div", {
1034
+ className: "my-4 rounded-md bg-background p-4 text-left text-sm text-foreground",
1035
+ children: [/* @__PURE__ */ jsxs("p", { children: [
1036
+ "Version ",
1037
+ latestVersion,
1038
+ " will be frozen as-is. Version",
1039
+ " ",
1040
+ nextVersion,
1041
+ " starts as an identical copy, and all further edits apply to version ",
1042
+ nextVersion,
1043
+ "."
1044
+ ] }), /* @__PURE__ */ jsxs("p", {
1045
+ className: "mt-3",
1046
+ children: [
1047
+ "Existing version ",
1048
+ latestVersion,
1049
+ " documents will be upgradeable once you define the migration."
1050
+ ]
1051
+ })]
1052
+ }),
1053
+ /* @__PURE__ */ jsxs("div", {
1054
+ className: "mt-4 flex justify-between gap-3",
1055
+ children: [/* @__PURE__ */ jsx(ModalButton, {
1056
+ className: compactButtonStyle$1,
1057
+ onClick: () => setShowReleaseModal(false),
1058
+ variant: "cancel",
1059
+ children: "Cancel"
1060
+ }), /* @__PURE__ */ jsxs(ModalButton, {
1061
+ className: compactButtonStyle$1,
1062
+ "data-testid": "confirm-release-button",
1063
+ onClick: () => {
1064
+ setShowReleaseModal(false);
1065
+ onReleaseNewVersion();
1066
+ },
1067
+ variant: "confirm",
1068
+ children: ["Release version ", nextVersion]
1069
+ })]
1070
+ })
1071
+ ]
1072
+ })
1073
+ })
1074
+ ]
1075
+ });
1076
+ }
1077
+ function FrozenVersionBanner(props) {
1078
+ const { viewedVersion, latestVersion } = props;
1079
+ return /* @__PURE__ */ jsxs("div", {
1080
+ className: "mb-4 rounded-md border border-border bg-muted p-3 text-sm text-foreground",
1081
+ "data-testid": "frozen-version-banner",
1082
+ children: [
1083
+ "Version ",
1084
+ viewedVersion,
1085
+ " is frozen. You're viewing it read-only. Edits go to version ",
1086
+ latestVersion,
1087
+ "."
1088
+ ]
1089
+ });
1090
+ }
1091
+ //#endregion
1092
+ //#region editors/document-model-editor/components/version-advisory-modal.tsx
1093
+ const compactButtonStyle = "min-h-0 min-w-0 flex-none rounded-lg px-4 py-1.5 text-sm whitespace-nowrap";
1094
+ function FieldDiffList(props) {
1095
+ const { label, fields } = props;
1096
+ if (fields.length === 0) return null;
1097
+ return /* @__PURE__ */ jsxs("div", {
1098
+ className: "mt-3",
1099
+ children: [/* @__PURE__ */ jsx("p", {
1100
+ className: "mb-1.5",
1101
+ children: label
1102
+ }), /* @__PURE__ */ jsx("div", {
1103
+ className: "flex flex-col items-start gap-1",
1104
+ children: fields.map((field) => /* @__PURE__ */ jsx("span", {
1105
+ className: "rounded-md bg-muted px-2 py-0.5 font-mono text-xs text-foreground",
1106
+ children: field
1107
+ }, field))
1108
+ })]
1109
+ });
1110
+ }
1111
+ function VersionAdvisoryModal(props) {
1112
+ const { prompt, onReleaseFirst, onKeepEditing, onCancel } = props;
1113
+ if (!prompt) return null;
1114
+ const { version, reason, diff } = prompt;
1115
+ const nextVersion = version + 1;
1116
+ return /* @__PURE__ */ jsx(Modal, {
1117
+ open: true,
1118
+ onOpenChange: (status) => {
1119
+ if (!status) onCancel();
1120
+ },
1121
+ children: /* @__PURE__ */ jsxs("div", {
1122
+ className: "w-[440px] p-6",
1123
+ "data-testid": "version-advisory-modal",
1124
+ children: [
1125
+ /* @__PURE__ */ jsxs("div", {
1126
+ className: "pb-2 text-2xl font-bold text-foreground",
1127
+ children: [
1128
+ "Is version ",
1129
+ version,
1130
+ " of this model already in use?"
1131
+ ]
1132
+ }),
1133
+ /* @__PURE__ */ jsxs("div", {
1134
+ className: "my-4 rounded-md bg-background p-4 text-left text-sm text-foreground",
1135
+ children: [
1136
+ /* @__PURE__ */ jsxs("p", { children: [
1137
+ reason,
1138
+ " Documents that were already created with version ",
1139
+ version,
1140
+ " ",
1141
+ "may stop working correctly."
1142
+ ] }),
1143
+ diff && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1144
+ /* @__PURE__ */ jsx(FieldDiffList, {
1145
+ fields: diff.addedFields,
1146
+ label: "New fields:"
1147
+ }),
1148
+ /* @__PURE__ */ jsx(FieldDiffList, {
1149
+ fields: diff.removedFields,
1150
+ label: "Removed fields:"
1151
+ }),
1152
+ /* @__PURE__ */ jsx(FieldDiffList, {
1153
+ fields: diff.changedFields,
1154
+ label: "Changed fields:"
1155
+ })
1156
+ ] }),
1157
+ /* @__PURE__ */ jsxs("p", {
1158
+ className: "mt-3",
1159
+ children: [
1160
+ "If others are already using version ",
1161
+ version,
1162
+ ", release version",
1163
+ " ",
1164
+ nextVersion,
1165
+ " first. Your change will go into version ",
1166
+ nextVersion,
1167
+ ", and existing documents can be updated safely."
1168
+ ]
1169
+ })
1170
+ ]
1171
+ }),
1172
+ /* @__PURE__ */ jsxs("div", {
1173
+ className: "mt-4 flex flex-col gap-2",
1174
+ children: [/* @__PURE__ */ jsx(ModalButton, {
1175
+ className: compactButtonStyle,
1176
+ "data-testid": "advisory-release-first",
1177
+ onClick: onReleaseFirst,
1178
+ variant: "confirm",
1179
+ children: `It's in use — release v${nextVersion} first`
1180
+ }), /* @__PURE__ */ jsxs(ModalButton, {
1181
+ className: compactButtonStyle,
1182
+ "data-testid": "advisory-keep-editing",
1183
+ onClick: onKeepEditing,
1184
+ variant: "cancel",
1185
+ children: ["Still in development — keep editing v", version]
1186
+ })]
1187
+ })
1188
+ ]
1189
+ })
1190
+ });
1191
+ }
1192
+ //#endregion
1104
1193
  //#region editors/document-model-editor/config.ts
1105
1194
  const editorConfig = { isExternalControlsEnabled: false };
1106
1195
  //#endregion
@@ -1109,8 +1198,305 @@ function useSelectedDocumentModelDocument() {
1109
1198
  return useSelectedDocumentOfType("powerhouse/document-model");
1110
1199
  }
1111
1200
  //#endregion
1201
+ //#region editors/document-model-editor/utils/change-classification.ts
1202
+ var import_graphql = require_graphql();
1203
+ function isShapeTypeNode(node) {
1204
+ return node.kind === import_graphql.Kind.OBJECT_TYPE_DEFINITION || node.kind === import_graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION || node.kind === import_graphql.Kind.ENUM_TYPE_DEFINITION;
1205
+ }
1206
+ function collectTypeFields(doc) {
1207
+ const types = /* @__PURE__ */ new Map();
1208
+ for (const definition of doc.definitions) {
1209
+ if (!isShapeTypeNode(definition)) continue;
1210
+ const fields = /* @__PURE__ */ new Map();
1211
+ if (definition.kind === import_graphql.Kind.ENUM_TYPE_DEFINITION) for (const value of definition.values ?? []) fields.set(value.name.value, "value");
1212
+ else for (const field of definition.fields ?? []) fields.set(field.name.value, (0, import_graphql.print)(field.type));
1213
+ types.set(definition.name.value, fields);
1214
+ }
1215
+ return types;
1216
+ }
1217
+ function escapeRegExp(value) {
1218
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1219
+ }
1220
+ function replaceTypeName(printedType, oldName, newName) {
1221
+ return printedType.replace(new RegExp(`\\b${escapeRegExp(oldName)}\\b`, "g"), newName);
1222
+ }
1223
+ function typeSignature(name, fields) {
1224
+ return [...fields.entries()].map(([field, type]) => `${field}:${replaceTypeName(type, name, "__SELF__")}`).sort().join("|");
1225
+ }
1226
+ function detectTypeRenames(oldTypes, newTypes) {
1227
+ const renames = /* @__PURE__ */ new Map();
1228
+ const removed = [...oldTypes.keys()].filter((name) => !newTypes.has(name));
1229
+ const added = new Set([...newTypes.keys()].filter((name) => !oldTypes.has(name)));
1230
+ for (const oldName of removed) {
1231
+ const oldSignature = typeSignature(oldName, oldTypes.get(oldName));
1232
+ for (const newName of added) if (typeSignature(newName, newTypes.get(newName)) === oldSignature) {
1233
+ renames.set(oldName, newName);
1234
+ added.delete(newName);
1235
+ break;
1236
+ }
1237
+ }
1238
+ return renames;
1239
+ }
1240
+ function flattenFields(types, renames) {
1241
+ const fields = /* @__PURE__ */ new Map();
1242
+ for (const [typeName, typeFields] of types) {
1243
+ const resolvedTypeName = renames.get(typeName) ?? typeName;
1244
+ for (const [fieldName, printedType] of typeFields) {
1245
+ let resolvedType = printedType;
1246
+ for (const [oldName, newName] of renames) resolvedType = replaceTypeName(resolvedType, oldName, newName);
1247
+ fields.set(`${resolvedTypeName}.${fieldName}`, resolvedType);
1248
+ }
1249
+ }
1250
+ return fields;
1251
+ }
1252
+ function hasShapeChange(diff) {
1253
+ return diff.addedFields.length > 0 || diff.removedFields.length > 0 || diff.changedFields.length > 0;
1254
+ }
1255
+ function diffSdlShapes(oldSdl, newSdl) {
1256
+ const empty = {
1257
+ addedFields: [],
1258
+ removedFields: [],
1259
+ changedFields: []
1260
+ };
1261
+ let oldDoc;
1262
+ let newDoc;
1263
+ try {
1264
+ oldDoc = (0, import_graphql.parse)(oldSdl);
1265
+ newDoc = (0, import_graphql.parse)(newSdl);
1266
+ } catch {
1267
+ return empty;
1268
+ }
1269
+ const oldTypes = collectTypeFields(oldDoc);
1270
+ const newTypes = collectTypeFields(newDoc);
1271
+ const oldFields = flattenFields(oldTypes, detectTypeRenames(oldTypes, newTypes));
1272
+ const newFields = flattenFields(newTypes, /* @__PURE__ */ new Map());
1273
+ const diff = {
1274
+ addedFields: [],
1275
+ removedFields: [],
1276
+ changedFields: []
1277
+ };
1278
+ for (const [key, newType] of newFields) {
1279
+ const oldType = oldFields.get(key);
1280
+ if (oldType === void 0) diff.addedFields.push(key);
1281
+ else if (oldType !== newType) diff.changedFields.push(`${key}: ${oldType} → ${newType}`);
1282
+ }
1283
+ for (const key of oldFields.keys()) if (!newFields.has(key)) diff.removedFields.push(key);
1284
+ return diff;
1285
+ }
1286
+ const SAFE = { kind: "safe" };
1287
+ function isBlank(value) {
1288
+ return !value || !value.trim() || value.trim() === "{}";
1289
+ }
1290
+ /**
1291
+ * True for a blank SDL, or an SDL whose types contain nothing but the
1292
+ * `_placeholder` field the editor seeds new state/operation schemas with
1293
+ * (see `makeInitialSchemaDoc` / `makeOperationInitialDoc` in ./helpers.ts).
1294
+ * Replacing a placeholder-only schema with real fields is a user's first
1295
+ * edit on a brand-new model, not a version-relevant change.
1296
+ */
1297
+ function isPlaceholderOnlySchema(sdl) {
1298
+ if (isBlank(sdl)) return true;
1299
+ let doc;
1300
+ try {
1301
+ doc = (0, import_graphql.parse)(sdl);
1302
+ } catch {
1303
+ return false;
1304
+ }
1305
+ return [...collectTypeFields(doc).values()].every((fields) => fields.size === 0 || fields.size === 1 && fields.has("_placeholder"));
1306
+ }
1307
+ function findOperation(spec, operationId) {
1308
+ for (const module of spec.modules) {
1309
+ const operation = module.operations.find((op) => op.id === operationId);
1310
+ if (operation) return operation;
1311
+ }
1312
+ }
1313
+ function addedSinceLastRelease(operationId, previousSpec) {
1314
+ return previousSpec !== void 0 && !findOperation(previousSpec, operationId);
1315
+ }
1316
+ function classifySetStateSchema(input, latestSpec) {
1317
+ const currentSchema = input.scope === "local" ? latestSpec.state.local.schema : latestSpec.state.global.schema;
1318
+ if (isPlaceholderOnlySchema(currentSchema)) return SAFE;
1319
+ const diff = diffSdlShapes(currentSchema, input.schema);
1320
+ if (!hasShapeChange(diff)) return SAFE;
1321
+ return {
1322
+ kind: "version-relevant",
1323
+ reason: input.scope === "local" ? `You're changing the local fields that version ${latestSpec.version} documents store.` : `You're changing the fields that version ${latestSpec.version} documents store.`,
1324
+ diff
1325
+ };
1326
+ }
1327
+ /**
1328
+ * The editor pre-fills a fresh model's initial value from the placeholder
1329
+ * schema, so a value that is blank or carries only the `_placeholder` key is
1330
+ * still being initialized rather than changed.
1331
+ */
1332
+ function isPlaceholderOnlyInitialValue(value) {
1333
+ if (isBlank(value)) return true;
1334
+ let parsed;
1335
+ try {
1336
+ parsed = JSON.parse(value);
1337
+ } catch {
1338
+ return false;
1339
+ }
1340
+ if (typeof parsed !== "object" || parsed === null) return false;
1341
+ return Object.keys(parsed).every((key) => key === "_placeholder");
1342
+ }
1343
+ function classifySetInitialState(input, latestSpec) {
1344
+ const currentValue = input.scope === "local" ? latestSpec.state.local.initialValue : latestSpec.state.global.initialValue;
1345
+ if (isPlaceholderOnlyInitialValue(currentValue)) return SAFE;
1346
+ if (compareStringsWithoutWhitespace(currentValue, input.initialValue)) return SAFE;
1347
+ return {
1348
+ kind: "version-relevant",
1349
+ reason: `You're changing the starting content that version ${latestSpec.version} documents are built on.`
1350
+ };
1351
+ }
1352
+ function classifyOperationChange(action, operationId, latestSpec, previousSpec) {
1353
+ if (addedSinceLastRelease(operationId, previousSpec)) return SAFE;
1354
+ const operation = findOperation(latestSpec, operationId);
1355
+ if (!operation) return SAFE;
1356
+ const operationLabel = operation.name || "an operation";
1357
+ switch (action.type) {
1358
+ case "DELETE_OPERATION": return {
1359
+ kind: "version-relevant",
1360
+ reason: `You're removing the "${operationLabel}" operation from version ${latestSpec.version}.`
1361
+ };
1362
+ case "SET_OPERATION_NAME":
1363
+ if (isBlank(operation.name)) return SAFE;
1364
+ return {
1365
+ kind: "version-relevant",
1366
+ reason: `You're renaming the "${operationLabel}" operation in version ${latestSpec.version}.`
1367
+ };
1368
+ case "SET_OPERATION_SCHEMA": {
1369
+ if (isPlaceholderOnlySchema(operation.schema ?? "")) return SAFE;
1370
+ if (isBlank(action.input.schema)) return {
1371
+ kind: "version-relevant",
1372
+ reason: `You're changing the information that the "${operationLabel}" operation accepts in version ${latestSpec.version}.`
1373
+ };
1374
+ const diff = diffSdlShapes(operation.schema ?? "", action.input.schema ?? "");
1375
+ if (!hasShapeChange(diff)) return SAFE;
1376
+ return {
1377
+ kind: "version-relevant",
1378
+ reason: `You're changing the information that the "${operationLabel}" operation accepts in version ${latestSpec.version}.`,
1379
+ diff
1380
+ };
1381
+ }
1382
+ default: return SAFE;
1383
+ }
1384
+ }
1385
+ function classifyDeleteModule(moduleId, latestSpec, previousSpec) {
1386
+ const module = latestSpec.modules.find((candidate) => candidate.id === moduleId);
1387
+ if (!module || module.operations.length === 0) return SAFE;
1388
+ if (module.operations.every((operation) => addedSinceLastRelease(operation.id, previousSpec))) return SAFE;
1389
+ return {
1390
+ kind: "version-relevant",
1391
+ reason: `You're removing the "${module.name}" module and all of its operations from version ${latestSpec.version}.`
1392
+ };
1393
+ }
1394
+ /**
1395
+ * Classifies a document-model action as version-relevant (would break
1396
+ * documents created with the current version) or safe. `previousSpec` is the
1397
+ * last released specification, used to exempt operations added since the
1398
+ * release.
1399
+ */
1400
+ function classifyDocumentModelAction(action, latestSpec, previousSpec) {
1401
+ switch (action.type) {
1402
+ case "SET_STATE_SCHEMA": return classifySetStateSchema(action.input, latestSpec);
1403
+ case "SET_INITIAL_STATE": return classifySetInitialState(action.input, latestSpec);
1404
+ case "DELETE_OPERATION":
1405
+ case "SET_OPERATION_NAME":
1406
+ case "SET_OPERATION_SCHEMA": return classifyOperationChange(action, action.input.id, latestSpec, previousSpec);
1407
+ case "DELETE_MODULE": return classifyDeleteModule(action.input.id, latestSpec, previousSpec);
1408
+ default: return SAFE;
1409
+ }
1410
+ }
1411
+ /**
1412
+ * Pure decision core of the version advisory: given the actions about to be
1413
+ * dispatched, decide whether to dispatch immediately or prompt the user.
1414
+ */
1415
+ function decideDispatch(actions, latestSpec, previousSpec, hasSessionChoice) {
1416
+ if (hasSessionChoice) return { kind: "dispatch" };
1417
+ for (const action of actions) {
1418
+ const classification = classifyDocumentModelAction(action, latestSpec, previousSpec);
1419
+ if (classification.kind === "version-relevant") return {
1420
+ kind: "prompt",
1421
+ reason: classification.reason,
1422
+ diff: classification.diff
1423
+ };
1424
+ }
1425
+ return { kind: "dispatch" };
1426
+ }
1427
+ //#endregion
1428
+ //#region editors/document-model-editor/hooks/useVersionAdvisory.ts
1429
+ /**
1430
+ * Versions the user has confirmed as "still in development" (or that were
1431
+ * just created via an explicit release) for this browser session. Keyed by
1432
+ * `${documentId}:${version}`. Deliberately in-memory: a publisher returning
1433
+ * in a later session is asked again, which is when the reminder matters.
1434
+ */
1435
+ const sessionVersionChoices = /* @__PURE__ */ new Set();
1436
+ function useVersionAdvisory(args) {
1437
+ const { documentId, latestSpec, previousSpec, dispatch, onReleaseError } = args;
1438
+ const [prompt, setPrompt] = useState(void 0);
1439
+ const pendingRef = useRef(void 0);
1440
+ const choiceKey = `${documentId}:${latestSpec.version}`;
1441
+ const guardedDispatch = (...dispatchArgs) => {
1442
+ const [action] = dispatchArgs;
1443
+ const decision = decideDispatch((Array.isArray(action) ? action : [action]).filter((candidate) => candidate !== void 0), latestSpec, previousSpec, sessionVersionChoices.has(choiceKey));
1444
+ if (decision.kind === "dispatch") {
1445
+ dispatch(...dispatchArgs);
1446
+ return;
1447
+ }
1448
+ pendingRef.current = dispatchArgs;
1449
+ setPrompt({
1450
+ version: latestSpec.version,
1451
+ reason: decision.reason,
1452
+ diff: decision.diff
1453
+ });
1454
+ };
1455
+ const flushPending = () => {
1456
+ const pending = pendingRef.current;
1457
+ pendingRef.current = void 0;
1458
+ if (pending) dispatch(...pending);
1459
+ };
1460
+ const releaseFirst = () => {
1461
+ setPrompt(void 0);
1462
+ if (!pendingRef.current) return;
1463
+ dispatch(releaseNewVersion(), (errors) => {
1464
+ if (errors.length > 0) {
1465
+ pendingRef.current = void 0;
1466
+ onReleaseError?.(errors[0].message);
1467
+ }
1468
+ }, () => {
1469
+ if (!pendingRef.current) return;
1470
+ sessionVersionChoices.add(`${documentId}:${latestSpec.version + 1}`);
1471
+ flushPending();
1472
+ });
1473
+ };
1474
+ const keepEditing = () => {
1475
+ sessionVersionChoices.add(choiceKey);
1476
+ setPrompt(void 0);
1477
+ flushPending();
1478
+ };
1479
+ const cancelAdvisory = () => {
1480
+ pendingRef.current = void 0;
1481
+ setPrompt(void 0);
1482
+ };
1483
+ const markVersionInDevelopment = (version) => {
1484
+ sessionVersionChoices.add(`${documentId}:${version}`);
1485
+ };
1486
+ return {
1487
+ guardedDispatch,
1488
+ prompt,
1489
+ releaseFirst,
1490
+ keepEditing,
1491
+ cancelAdvisory,
1492
+ markVersionInDevelopment
1493
+ };
1494
+ }
1495
+ //#endregion
1112
1496
  //#region editors/document-model-editor/editor.tsx
1113
- const StateSchemas = lazy(() => import("./state-schemas-Bl7nA8bB.mjs"));
1497
+ const StateSchemas = lazy(() => import("./state-schemas-DHQAxfto.mjs"));
1498
+ const noopSetStateSchema = () => void 0;
1499
+ const noopSetInitialState = () => void 0;
1114
1500
  function Editor() {
1115
1501
  useSetPHDocumentEditorConfig(editorConfig);
1116
1502
  const toast = usePHToast();
@@ -1118,9 +1504,17 @@ function Editor() {
1118
1504
  const [scope, setScope] = useState("global");
1119
1505
  const documentNodeName = document.header.name;
1120
1506
  const { name: modelName, id: documentType, extension, description, author: { name: authorName, website: authorWebsite } } = document.state.global;
1121
- const { state: { global: { schema: globalStateSchema, initialValue: globalStateInitialValue }, local: { schema: localStateSchema, initialValue: localStateInitialValue } }, modules } = document.state.global.specifications[0];
1507
+ const specifications = document.state.global.specifications;
1508
+ const latestSpec = specifications[specifications.length - 1];
1509
+ const previousSpec = specifications.length >= 2 ? specifications[specifications.length - 2] : void 0;
1510
+ const [viewedVersion, setViewedVersion] = useState("latest");
1511
+ const viewedSpec = viewedVersion === "latest" ? latestSpec : specifications.find((spec) => spec.version === viewedVersion) ?? latestSpec;
1512
+ const isViewingFrozenVersion = viewedSpec.version !== latestSpec.version;
1513
+ const { state: { global: { schema: globalStateSchema, initialValue: globalStateInitialValue }, local: { schema: localStateSchema, initialValue: localStateInitialValue } }, modules } = viewedSpec;
1122
1514
  const operations = modules.flatMap((module) => module.operations);
1123
- const shouldSetInitialName = useRef(!modelName && !!documentNodeName && operations.length === 0);
1515
+ const { state: { global: { schema: latestGlobalStateSchema, initialValue: latestGlobalStateInitialValue }, local: { schema: latestLocalStateSchema, initialValue: latestLocalStateInitialValue } }, modules: latestModules } = latestSpec;
1516
+ const latestOperations = latestModules.flatMap((module) => module.operations);
1517
+ const shouldSetInitialName = useRef(!modelName && !!documentNodeName && latestOperations.length === 0);
1124
1518
  useEffect(() => {
1125
1519
  if (!shouldSetInitialName.current || !documentNodeName) return;
1126
1520
  const initialSchemaDoc = initializeModelSchema(documentNodeName);
@@ -1130,41 +1524,59 @@ function Editor() {
1130
1524
  })]);
1131
1525
  shouldSetInitialName.current = false;
1132
1526
  }, [documentNodeName, dispatch]);
1527
+ const { guardedDispatch, prompt, releaseFirst, keepEditing, cancelAdvisory, markVersionInDevelopment } = useVersionAdvisory({
1528
+ documentId: document.header.id,
1529
+ latestSpec,
1530
+ previousSpec,
1531
+ dispatch,
1532
+ onReleaseError: (message) => {
1533
+ if (toast) toast(message, { type: "connect-warning" });
1534
+ }
1535
+ });
1536
+ const handleReleaseNewVersion = () => {
1537
+ const nextVersion = latestSpec.version + 1;
1538
+ dispatch(releaseNewVersion(), (errors) => {
1539
+ if (errors.length > 0 && toast) toast(errors[0].message, { type: "connect-warning" });
1540
+ }, () => {
1541
+ markVersionInDevelopment(nextVersion);
1542
+ setViewedVersion("latest");
1543
+ });
1544
+ };
1133
1545
  const operationSchemasSdl = operations.flatMap((operation) => operation.schema ?? []).join("\n");
1134
1546
  const handleSetModelId = (id) => {
1135
1547
  if (compareStringsWithoutWhitespace(id, documentType)) return;
1136
- dispatch([setModelId({ id })]);
1548
+ guardedDispatch([setModelId({ id })]);
1137
1549
  };
1138
1550
  const handleSetModelDescription = (newDescription) => {
1139
1551
  if (compareStringsWithoutWhitespace(newDescription, description)) return;
1140
- dispatch(setModelDescription({ description: newDescription }));
1552
+ guardedDispatch(setModelDescription({ description: newDescription }));
1141
1553
  };
1142
1554
  const handleSetModelExtension = (newExtension) => {
1143
1555
  if (compareStringsWithoutWhitespace(newExtension, extension)) return;
1144
- dispatch(setModelExtension({ extension: newExtension }));
1556
+ guardedDispatch(setModelExtension({ extension: newExtension }));
1145
1557
  };
1146
1558
  const handleSetModelName = (newName) => {
1147
1559
  if (compareStringsWithoutWhitespace(newName, modelName)) return;
1148
- dispatch(setModelName({ name: newName }));
1560
+ guardedDispatch(setModelName({ name: newName }));
1149
1561
  };
1150
1562
  const handleSetAuthorName = (newAuthorName) => {
1151
1563
  if (compareStringsWithoutWhitespace(newAuthorName, authorName)) return;
1152
- dispatch(setAuthorName({ authorName: newAuthorName }));
1564
+ guardedDispatch(setAuthorName({ authorName: newAuthorName }));
1153
1565
  };
1154
1566
  const handleSetAuthorWebsite = (newAuthorWebsite) => {
1155
1567
  if (compareStringsWithoutWhitespace(newAuthorWebsite, authorWebsite ?? "")) return;
1156
- dispatch(setAuthorWebsite({ authorWebsite: newAuthorWebsite }));
1568
+ guardedDispatch(setAuthorWebsite({ authorWebsite: newAuthorWebsite }));
1157
1569
  };
1158
1570
  const handleSetStateSchema = (newSchema, scope) => {
1159
- if (compareStringsWithoutWhitespace(newSchema, scope === "global" ? globalStateSchema : localStateSchema)) return;
1160
- dispatch(setStateSchema({
1571
+ if (compareStringsWithoutWhitespace(newSchema, scope === "global" ? latestGlobalStateSchema : latestLocalStateSchema)) return;
1572
+ guardedDispatch(setStateSchema({
1161
1573
  schema: newSchema,
1162
1574
  scope
1163
1575
  }));
1164
1576
  };
1165
1577
  const handleSetInitialState = (newInitialValue, scope) => {
1166
- if (compareStringsWithoutWhitespace(newInitialValue, scope === "global" ? globalStateInitialValue : localStateInitialValue)) return;
1167
- dispatch(setInitialState({
1578
+ if (compareStringsWithoutWhitespace(newInitialValue, scope === "global" ? latestGlobalStateInitialValue : latestLocalStateInitialValue)) return;
1579
+ guardedDispatch(setInitialState({
1168
1580
  initialValue: newInitialValue,
1169
1581
  scope
1170
1582
  }));
@@ -1172,12 +1584,12 @@ function Editor() {
1172
1584
  const handleAddModule = (name) => {
1173
1585
  return new Promise((resolve) => {
1174
1586
  try {
1175
- if (modules.some((module) => compareStringsWithoutWhitespace(module.name, name))) {
1587
+ if (latestModules.some((module) => compareStringsWithoutWhitespace(module.name, name))) {
1176
1588
  resolve(void 0);
1177
1589
  return;
1178
1590
  }
1179
1591
  const id = generateId();
1180
- dispatch(addModule({
1592
+ guardedDispatch(addModule({
1181
1593
  id,
1182
1594
  name
1183
1595
  }));
@@ -1189,19 +1601,19 @@ function Editor() {
1189
1601
  });
1190
1602
  };
1191
1603
  const handleSetModuleName = (id, name) => {
1192
- if (modules.some((module) => compareStringsWithoutWhitespace(module.name, name))) return;
1193
- dispatch(setModuleName({
1604
+ if (latestModules.some((module) => compareStringsWithoutWhitespace(module.name, name))) return;
1605
+ guardedDispatch(setModuleName({
1194
1606
  id,
1195
1607
  name
1196
1608
  }));
1197
1609
  };
1198
1610
  const handleDeleteModule = (id) => {
1199
- dispatch(deleteModule({ id }));
1611
+ guardedDispatch(deleteModule({ id }));
1200
1612
  };
1201
1613
  const handleAddOperation = (moduleId, name) => {
1202
1614
  return new Promise((resolve) => {
1203
1615
  const id = generateId();
1204
- dispatch(addOperation({
1616
+ guardedDispatch(addOperation({
1205
1617
  id,
1206
1618
  moduleId,
1207
1619
  name,
@@ -1215,7 +1627,7 @@ function Editor() {
1215
1627
  });
1216
1628
  };
1217
1629
  const handleSetOperationName = (id, name) => {
1218
- dispatch(setOperationName({
1630
+ guardedDispatch(setOperationName({
1219
1631
  id,
1220
1632
  name
1221
1633
  }), (errors) => {
@@ -1223,44 +1635,44 @@ function Editor() {
1223
1635
  });
1224
1636
  };
1225
1637
  const handleSetOperationSchema = (id, newSchema) => {
1226
- const operation = operations.find((operation) => operation.id === id);
1638
+ const operation = latestOperations.find((operation) => operation.id === id);
1227
1639
  if (operation?.schema && compareStringsWithoutWhitespace(newSchema, operation.schema)) return;
1228
- dispatch(setOperationSchema({
1640
+ guardedDispatch(setOperationSchema({
1229
1641
  id,
1230
1642
  schema: newSchema
1231
1643
  }));
1232
1644
  };
1233
1645
  const handleToggleNoInputRequired = (id, noInputRequired) => {
1234
- const operation = operations.find((op) => op.id === id);
1646
+ const operation = latestOperations.find((op) => op.id === id);
1235
1647
  if (!operation?.name) return;
1236
- if (noInputRequired) dispatch(setOperationSchema({
1648
+ if (noInputRequired) guardedDispatch(setOperationSchema({
1237
1649
  id,
1238
1650
  schema: makeEmptyOperationSchema(operation.name)
1239
1651
  }));
1240
- else dispatch(setOperationSchema({
1652
+ else guardedDispatch(setOperationSchema({
1241
1653
  id,
1242
1654
  schema: makeOperationInitialDoc(operation.name)
1243
1655
  }));
1244
1656
  };
1245
1657
  const handleSetOperationDescription = (id, newDescription) => {
1246
- if (compareStringsWithoutWhitespace(operations.find((operation) => operation.id === id)?.description ?? "", newDescription)) return;
1247
- dispatch(setOperationDescription({
1658
+ if (compareStringsWithoutWhitespace(latestOperations.find((operation) => operation.id === id)?.description ?? "", newDescription)) return;
1659
+ guardedDispatch(setOperationDescription({
1248
1660
  id,
1249
1661
  description: newDescription
1250
1662
  }));
1251
1663
  };
1252
1664
  const handleDeleteOperation = (id) => {
1253
- dispatch(deleteOperation({ id }));
1665
+ guardedDispatch(deleteOperation({ id }));
1254
1666
  };
1255
1667
  const handleAddOperationError = (operationId, errorName) => {
1256
1668
  return new Promise((resolve) => {
1257
1669
  try {
1258
- if ((operations.find((operation) => operation.id === operationId)?.errors.map((error) => error.name).filter(Boolean) ?? []).some((name) => compareStringsWithoutWhitespace(name, errorName))) {
1670
+ if ((latestOperations.find((operation) => operation.id === operationId)?.errors.map((error) => error.name).filter(Boolean) ?? []).some((name) => compareStringsWithoutWhitespace(name, errorName))) {
1259
1671
  resolve(void 0);
1260
1672
  return;
1261
1673
  }
1262
1674
  const id = generateId();
1263
- dispatch(addOperationError({
1675
+ guardedDispatch(addOperationError({
1264
1676
  id,
1265
1677
  operationId,
1266
1678
  errorName,
@@ -1274,11 +1686,11 @@ function Editor() {
1274
1686
  });
1275
1687
  };
1276
1688
  const handleDeleteOperationError = (id) => {
1277
- dispatch(deleteOperationError({ id }));
1689
+ guardedDispatch(deleteOperationError({ id }));
1278
1690
  };
1279
1691
  const handleSetOperationErrorName = (operationId, errorId, errorName) => {
1280
- if ((operations.find((operation) => operation.id === operationId)?.errors.map((error) => error.name).filter(Boolean) ?? []).some((name) => compareStringsWithoutWhitespace(name, errorName))) return;
1281
- dispatch(setOperationErrorName({
1692
+ if ((latestOperations.find((operation) => operation.id === operationId)?.errors.map((error) => error.name).filter(Boolean) ?? []).some((name) => compareStringsWithoutWhitespace(name, errorName))) return;
1693
+ guardedDispatch(setOperationErrorName({
1282
1694
  id: errorId,
1283
1695
  errorName
1284
1696
  }));
@@ -1301,74 +1713,97 @@ function Editor() {
1301
1713
  };
1302
1714
  return /* @__PURE__ */ jsxs("main", {
1303
1715
  className: "min-h-dvh bg-background p-6",
1304
- children: [/* @__PURE__ */ jsx(DocumentToolbar, {}), /* @__PURE__ */ jsx(SchemaContextProvider, {
1305
- globalStateSchemaSdl: globalStateSchema,
1306
- localStateSchemaSdl: localStateSchema,
1307
- operationSchemasSdl,
1308
- children: /* @__PURE__ */ jsxs("div", {
1309
- className: "mx-auto max-w-6xl px-4 pt-8",
1310
- children: [
1311
- /* @__PURE__ */ jsx(ModelMetadata, {
1312
- name: modelName,
1313
- documentType,
1314
- extension,
1315
- description,
1316
- authorName,
1317
- authorWebsite: authorWebsite ?? "",
1318
- globalStateSchema,
1319
- localStateSchema,
1320
- setModelId: handleSetModelId,
1321
- setModelDescription: handleSetModelDescription,
1322
- setModelExtension: handleSetModelExtension,
1323
- setModelName: handleSetModelName,
1324
- setAuthorName: handleSetAuthorName,
1325
- setAuthorWebsite: handleSetAuthorWebsite,
1326
- setStateSchema: handleSetStateSchema
1327
- }),
1328
- /* @__PURE__ */ jsx(Divider, {}),
1329
- /* @__PURE__ */ jsxs("div", { children: [
1330
- /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(StateSchemas, {
1331
- modelName,
1332
- globalStateSchema,
1333
- globalStateInitialValue,
1334
- localStateSchema,
1335
- localStateInitialValue,
1336
- setStateSchema: handleSetStateSchema,
1337
- setInitialState: handleSetInitialState,
1338
- currentScope: scope,
1339
- onScopeChange: setScope
1340
- }) }),
1716
+ children: [
1717
+ /* @__PURE__ */ jsx(DocumentToolbar, {}),
1718
+ /* @__PURE__ */ jsx(SchemaContextProvider, {
1719
+ globalStateSchemaSdl: globalStateSchema,
1720
+ localStateSchemaSdl: localStateSchema,
1721
+ operationSchemasSdl,
1722
+ children: /* @__PURE__ */ jsxs("div", {
1723
+ className: "mx-auto max-w-6xl px-4 pt-8",
1724
+ children: [
1725
+ /* @__PURE__ */ jsx(VersionControls, {
1726
+ specifications,
1727
+ viewedVersion: viewedSpec.version,
1728
+ onViewVersion: setViewedVersion,
1729
+ onReleaseNewVersion: handleReleaseNewVersion
1730
+ }),
1731
+ /* @__PURE__ */ jsx(ModelMetadata, {
1732
+ name: modelName,
1733
+ documentType,
1734
+ extension,
1735
+ description,
1736
+ authorName,
1737
+ authorWebsite: authorWebsite ?? "",
1738
+ globalStateSchema: latestGlobalStateSchema,
1739
+ localStateSchema: latestLocalStateSchema,
1740
+ setModelId: handleSetModelId,
1741
+ setModelDescription: handleSetModelDescription,
1742
+ setModelExtension: handleSetModelExtension,
1743
+ setModelName: handleSetModelName,
1744
+ setAuthorName: handleSetAuthorName,
1745
+ setAuthorWebsite: handleSetAuthorWebsite,
1746
+ setStateSchema: handleSetStateSchema
1747
+ }),
1341
1748
  /* @__PURE__ */ jsx(Divider, {}),
1342
- /* @__PURE__ */ jsxs("h3", {
1343
- className: "mb-6 text-lg text-foreground capitalize",
1344
- children: [scope, " Operations"]
1749
+ isViewingFrozenVersion && /* @__PURE__ */ jsx(FrozenVersionBanner, {
1750
+ latestVersion: latestSpec.version,
1751
+ viewedVersion: viewedSpec.version
1345
1752
  }),
1346
- /* @__PURE__ */ jsx(Modules, {
1347
- modules: modules.map((module) => ({
1348
- ...module,
1349
- operations: module.operations.filter((op) => op.scope === scope)
1350
- })),
1351
- allOperations: operations,
1352
- addModule: handleAddModule,
1353
- updateModuleName: handleSetModuleName,
1354
- deleteModule: handleDeleteModule,
1355
- updateOperationName: handleSetOperationName,
1356
- updateOperationSchema: handleSetOperationSchema,
1357
- setOperationDescription: handleSetOperationDescription,
1358
- deleteOperation: handleDeleteOperation,
1359
- addOperationError: handleAddOperationError,
1360
- deleteOperationError: handleDeleteOperationError,
1361
- setOperationErrorName: handleSetOperationErrorName,
1362
- addOperationAndInitialSchema,
1363
- toggleNoInputRequired: handleToggleNoInputRequired
1753
+ /* @__PURE__ */ jsxs("div", {
1754
+ className: isViewingFrozenVersion ? "pointer-events-none opacity-80 select-none" : void 0,
1755
+ inert: isViewingFrozenVersion || void 0,
1756
+ children: [
1757
+ /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(StateSchemas, {
1758
+ modelName,
1759
+ globalStateSchema,
1760
+ globalStateInitialValue,
1761
+ localStateSchema,
1762
+ localStateInitialValue,
1763
+ setStateSchema: isViewingFrozenVersion ? noopSetStateSchema : handleSetStateSchema,
1764
+ setInitialState: isViewingFrozenVersion ? noopSetInitialState : handleSetInitialState,
1765
+ currentScope: scope,
1766
+ onScopeChange: setScope
1767
+ }) }),
1768
+ /* @__PURE__ */ jsx(Divider, {}),
1769
+ /* @__PURE__ */ jsxs("h3", {
1770
+ className: "mb-6 text-lg text-foreground capitalize",
1771
+ children: [scope, " Operations"]
1772
+ }),
1773
+ /* @__PURE__ */ jsx(Modules, {
1774
+ modules: modules.map((module) => ({
1775
+ ...module,
1776
+ operations: module.operations.filter((op) => op.scope === scope)
1777
+ })),
1778
+ allOperations: operations,
1779
+ addModule: handleAddModule,
1780
+ updateModuleName: handleSetModuleName,
1781
+ deleteModule: handleDeleteModule,
1782
+ updateOperationName: handleSetOperationName,
1783
+ updateOperationSchema: handleSetOperationSchema,
1784
+ setOperationDescription: handleSetOperationDescription,
1785
+ deleteOperation: handleDeleteOperation,
1786
+ addOperationError: handleAddOperationError,
1787
+ deleteOperationError: handleDeleteOperationError,
1788
+ setOperationErrorName: handleSetOperationErrorName,
1789
+ addOperationAndInitialSchema,
1790
+ toggleNoInputRequired: handleToggleNoInputRequired
1791
+ })
1792
+ ]
1364
1793
  })
1365
- ] })
1366
- ]
1794
+ ]
1795
+ })
1796
+ }),
1797
+ /* @__PURE__ */ jsx(VersionAdvisoryModal, {
1798
+ prompt,
1799
+ onReleaseFirst: releaseFirst,
1800
+ onKeepEditing: keepEditing,
1801
+ onCancel: cancelAdvisory
1367
1802
  })
1368
- })]
1803
+ ]
1369
1804
  });
1370
1805
  }
1371
1806
  //#endregion
1372
1807
  export { Editor as default };
1373
1808
 
1374
- //# sourceMappingURL=editor-B1KhoF1f.mjs.map
1809
+ //# sourceMappingURL=editor-BGcLm6LA.mjs.map