@powerhousedao/powerhouse-vetra-packages 6.2.2-dev.42 → 6.2.2-dev.44

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 (72) hide show
  1. package/dist/browser/assets/{entry-Db_lIhQq.js → entry-C2ClkbVN.js} +2 -2
  2. package/dist/browser/assets/{projection-entry-DqgHaUSy.js → projection-entry-S39DdeT-.js} +3 -3
  3. package/dist/browser/{linting-_AQWr8aE.js → button-CuO8Gh3v.js} +17 -4
  4. package/dist/browser/button-CuO8Gh3v.js.map +1 -0
  5. package/dist/browser/{connect-BUnNjGUW.js → connect-70_1bgIZ.js} +49 -7
  6. package/dist/browser/{connect-BUnNjGUW.js.map → connect-70_1bgIZ.js.map} +1 -1
  7. package/dist/browser/{dist-BatmWBzA.js → dist-CXIjN0Ex.js} +150 -25
  8. package/dist/browser/dist-CXIjN0Ex.js.map +1 -0
  9. package/dist/browser/{document-drive-D3Z9vXTQ.js → document-drive-PYPIaEvw.js} +197 -13
  10. package/dist/browser/document-drive-PYPIaEvw.js.map +1 -0
  11. package/dist/browser/document-models/index.js +1 -1
  12. package/dist/browser/{editor-BLeFoOh6.js → editor-DOJeQKlN.js} +5 -5
  13. package/dist/browser/{editor-BLeFoOh6.js.map → editor-DOJeQKlN.js.map} +1 -1
  14. package/dist/browser/{editor-Bn6uXvxG.js → editor-QW6D3wl8.js} +668 -101
  15. package/dist/browser/editor-QW6D3wl8.js.map +1 -0
  16. package/dist/browser/editors/document-model-editor/module.js +1 -1
  17. package/dist/browser/editors/generic-drive-explorer/index.js +4 -4
  18. package/dist/browser/editors/generic-drive-explorer/module.js +1 -1
  19. package/dist/browser/{folder-view-DNzFnfW2.js → folder-view-VM5cJbvv.js} +29 -10
  20. package/dist/browser/folder-view-VM5cJbvv.js.map +1 -0
  21. package/dist/browser/{graphql-editor-DWo8N_z4.js → graphql-editor-CjpiNMV0.js} +3 -3
  22. package/dist/browser/{graphql-editor-DWo8N_z4.js.map → graphql-editor-CjpiNMV0.js.map} +1 -1
  23. package/dist/browser/index.js +378 -9
  24. package/dist/browser/index.js.map +1 -1
  25. package/dist/browser/{json-editor-CEugjpFj.js → json-editor-CeIHor4v.js} +3 -3
  26. package/dist/browser/{json-editor-CEugjpFj.js.map → json-editor-CeIHor4v.js.map} +1 -1
  27. package/dist/browser/{lib-CiaHsAaR.js → lib-PZlA5c3e.js} +2 -2
  28. package/dist/browser/lib-PZlA5c3e.js.map +1 -0
  29. package/dist/browser/{state-schemas-VrticHe4.js → state-schemas-CbPirA44.js} +5 -15
  30. package/dist/browser/state-schemas-CbPirA44.js.map +1 -0
  31. package/dist/node/{linting-BjvRPjCY.mjs → button-Da7CxMn7.mjs} +17 -4
  32. package/dist/node/button-Da7CxMn7.mjs.map +1 -0
  33. package/dist/node/{connect-wMkkAckX.mjs → connect-CkBYxX_q.mjs} +49 -7
  34. package/dist/node/{connect-wMkkAckX.mjs.map → connect-CkBYxX_q.mjs.map} +1 -1
  35. package/dist/node/{dist-CUHBOv3P.mjs → dist-CS8QwZwZ.mjs} +150 -25
  36. package/dist/node/dist-CS8QwZwZ.mjs.map +1 -0
  37. package/dist/node/{document-drive-CI0J7nMj.mjs → document-drive-DrBAR9as.mjs} +197 -13
  38. package/dist/node/document-drive-DrBAR9as.mjs.map +1 -0
  39. package/dist/node/document-models/index.mjs +1 -1
  40. package/dist/node/{editor-Cr-mNQca.mjs → editor-ClZqmnoh.mjs} +670 -103
  41. package/dist/node/editor-ClZqmnoh.mjs.map +1 -0
  42. package/dist/node/{editor-aIeTo2EE.mjs → editor-Dv22q5WR.mjs} +5 -5
  43. package/dist/node/{editor-aIeTo2EE.mjs.map → editor-Dv22q5WR.mjs.map} +1 -1
  44. package/dist/node/editors/document-model-editor/module.mjs +1 -1
  45. package/dist/node/editors/generic-drive-explorer/index.mjs +4 -4
  46. package/dist/node/editors/generic-drive-explorer/module.mjs +1 -1
  47. package/dist/node/{folder-view-_x1OBYZN.mjs → folder-view-6H-dMp8X.mjs} +29 -10
  48. package/dist/node/folder-view-6H-dMp8X.mjs.map +1 -0
  49. package/dist/node/{graphql-editor-Dd2_z5QJ.mjs → graphql-editor-DP0o3W7f.mjs} +3 -3
  50. package/dist/node/{graphql-editor-Dd2_z5QJ.mjs.map → graphql-editor-DP0o3W7f.mjs.map} +1 -1
  51. package/dist/node/index.mjs +378 -9
  52. package/dist/node/index.mjs.map +1 -1
  53. package/dist/node/{json-editor-Dphg6ZeL.mjs → json-editor-CNbnXYz6.mjs} +3 -3
  54. package/dist/node/{json-editor-Dphg6ZeL.mjs.map → json-editor-CNbnXYz6.mjs.map} +1 -1
  55. package/dist/node/{main-Db0ei9wX.mjs → main-aITg389Z.mjs} +2 -2
  56. package/dist/node/main-aITg389Z.mjs.map +1 -0
  57. package/dist/node/{state-schemas-BSLgTw2O.mjs → state-schemas-CylQoH3Q.mjs} +6 -16
  58. package/dist/{browser/state-schemas-VrticHe4.js.map → node/state-schemas-CylQoH3Q.mjs.map} +1 -1
  59. package/package.json +7 -6
  60. package/dist/browser/dist-BatmWBzA.js.map +0 -1
  61. package/dist/browser/document-drive-D3Z9vXTQ.js.map +0 -1
  62. package/dist/browser/editor-Bn6uXvxG.js.map +0 -1
  63. package/dist/browser/folder-view-DNzFnfW2.js.map +0 -1
  64. package/dist/browser/lib-CiaHsAaR.js.map +0 -1
  65. package/dist/browser/linting-_AQWr8aE.js.map +0 -1
  66. package/dist/node/dist-CUHBOv3P.mjs.map +0 -1
  67. package/dist/node/document-drive-CI0J7nMj.mjs.map +0 -1
  68. package/dist/node/editor-Cr-mNQca.mjs.map +0 -1
  69. package/dist/node/folder-view-_x1OBYZN.mjs.map +0 -1
  70. package/dist/node/linting-BjvRPjCY.mjs.map +0 -1
  71. package/dist/node/main-Db0ei9wX.mjs.map +0 -1
  72. package/dist/node/state-schemas-BSLgTw2O.mjs.map +0 -1
@@ -1,13 +1,14 @@
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, x as url, y as union } from "./dist-DT7jI9ol.mjs";
2
- import { $ as generateId, B as setModelId, D as deleteModule, F as setAuthorName, G as setOperationErrorName, H as setModuleName, I as setAuthorWebsite, J as setStateSchema, K as setOperationName, L as setInitialState, O as deleteOperation, R as setModelDescription, V as setModelName, W as setOperationDescription, h as addOperationError, k as deleteOperationError, m as addOperation, p as addModule, q as setOperationSchema, z as setModelExtension } from "./document-drive-CI0J7nMj.mjs";
3
- import { _ as Primitive, c as Controller, d as get, f as set, i as DocumentToolbar, l as FormProvider, m as useFormContext, p as useForm, u as appendErrors, v as Slot } from "./connect-wMkkAckX.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 setOperationSchema, G as setModelExtension, H as setAuthorWebsite, J as setModuleName, K as setModelId, M as deleteModule, N as deleteOperation, P as deleteOperationError, Q as setOperationName, U as setInitialState, V as setAuthorName, W as setModelDescription, X as setOperationDescription, Z as setOperationErrorName, _ as addOperationError, at as generateId, et as setStateSchema, g as addOperation, h as addModule, q as setModelName, z as releaseNewVersion } from "./document-drive-DrBAR9as.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-CkBYxX_q.mjs";
4
5
  import { w as twMerge } from "./dist-CzYOpeXN.mjs";
5
- import { M as usePHToast, p as useSelectedDocumentOfType, v as useSetPHDocumentEditorConfig } from "./dist-CUHBOv3P.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-BjvRPjCY.mjs";
6
+ import { P as usePHToast, m as useSelectedDocumentOfType, y as useSetPHDocumentEditorConfig } from "./dist-CS8QwZwZ.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";
7
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 { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
12
  //#region ../../node_modules/.pnpm/clsx@2.0.0/node_modules/clsx/dist/clsx.mjs
12
13
  function r$1(e) {
13
14
  var t, f, n = "";
@@ -196,7 +197,7 @@ function a(o$1, a, u) {
196
197
  }(o$1)) return function(s, c, f) {
197
198
  try {
198
199
  return Promise.resolve(t(function() {
199
- 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) {
200
201
  return f.shouldUseNativeValidation && o({}, f), {
201
202
  errors: {},
202
203
  values: u.raw ? Object.assign({}, s) : e
@@ -756,7 +757,7 @@ function OperationErrors({ operation, addOperationError, deleteOperationError, s
756
757
  }
757
758
  //#endregion
758
759
  //#region editors/document-model-editor/components/operation.tsx
759
- const GraphqlEditor = lazy(() => import("./graphql-editor-Dd2_z5QJ.mjs"));
760
+ const GraphqlEditor = lazy(() => import("./graphql-editor-DP0o3W7f.mjs"));
760
761
  function Operation(props) {
761
762
  const { operation, module, allOperationNames, lastCreatedOperationId, onAddOperationAndInitialSchema, updateOperationName, deleteOperation, updateOperationSchema, setOperationDescription, addOperationError, deleteOperationError, setOperationErrorName, toggleNoInputRequired } = props;
762
763
  const noInputRequired = isEmptyOperationSchema(operation.schema);
@@ -969,6 +970,226 @@ function Modules({ modules, allOperations, addModule, updateModuleName, deleteMo
969
970
  });
970
971
  }
971
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
972
1193
  //#region editors/document-model-editor/config.ts
973
1194
  const editorConfig = { isExternalControlsEnabled: false };
974
1195
  //#endregion
@@ -977,8 +1198,305 @@ function useSelectedDocumentModelDocument() {
977
1198
  return useSelectedDocumentOfType("powerhouse/document-model");
978
1199
  }
979
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
980
1496
  //#region editors/document-model-editor/editor.tsx
981
- const StateSchemas = lazy(() => import("./state-schemas-BSLgTw2O.mjs"));
1497
+ const StateSchemas = lazy(() => import("./state-schemas-CylQoH3Q.mjs"));
1498
+ const noopSetStateSchema = () => void 0;
1499
+ const noopSetInitialState = () => void 0;
982
1500
  function Editor() {
983
1501
  useSetPHDocumentEditorConfig(editorConfig);
984
1502
  const toast = usePHToast();
@@ -986,9 +1504,17 @@ function Editor() {
986
1504
  const [scope, setScope] = useState("global");
987
1505
  const documentNodeName = document.header.name;
988
1506
  const { name: modelName, id: documentType, extension, description, author: { name: authorName, website: authorWebsite } } = document.state.global;
989
- 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;
990
1514
  const operations = modules.flatMap((module) => module.operations);
991
- 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);
992
1518
  useEffect(() => {
993
1519
  if (!shouldSetInitialName.current || !documentNodeName) return;
994
1520
  const initialSchemaDoc = initializeModelSchema(documentNodeName);
@@ -998,41 +1524,59 @@ function Editor() {
998
1524
  })]);
999
1525
  shouldSetInitialName.current = false;
1000
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
+ };
1001
1545
  const operationSchemasSdl = operations.flatMap((operation) => operation.schema ?? []).join("\n");
1002
1546
  const handleSetModelId = (id) => {
1003
1547
  if (compareStringsWithoutWhitespace(id, documentType)) return;
1004
- dispatch([setModelId({ id })]);
1548
+ guardedDispatch([setModelId({ id })]);
1005
1549
  };
1006
1550
  const handleSetModelDescription = (newDescription) => {
1007
1551
  if (compareStringsWithoutWhitespace(newDescription, description)) return;
1008
- dispatch(setModelDescription({ description: newDescription }));
1552
+ guardedDispatch(setModelDescription({ description: newDescription }));
1009
1553
  };
1010
1554
  const handleSetModelExtension = (newExtension) => {
1011
1555
  if (compareStringsWithoutWhitespace(newExtension, extension)) return;
1012
- dispatch(setModelExtension({ extension: newExtension }));
1556
+ guardedDispatch(setModelExtension({ extension: newExtension }));
1013
1557
  };
1014
1558
  const handleSetModelName = (newName) => {
1015
1559
  if (compareStringsWithoutWhitespace(newName, modelName)) return;
1016
- dispatch(setModelName({ name: newName }));
1560
+ guardedDispatch(setModelName({ name: newName }));
1017
1561
  };
1018
1562
  const handleSetAuthorName = (newAuthorName) => {
1019
1563
  if (compareStringsWithoutWhitespace(newAuthorName, authorName)) return;
1020
- dispatch(setAuthorName({ authorName: newAuthorName }));
1564
+ guardedDispatch(setAuthorName({ authorName: newAuthorName }));
1021
1565
  };
1022
1566
  const handleSetAuthorWebsite = (newAuthorWebsite) => {
1023
1567
  if (compareStringsWithoutWhitespace(newAuthorWebsite, authorWebsite ?? "")) return;
1024
- dispatch(setAuthorWebsite({ authorWebsite: newAuthorWebsite }));
1568
+ guardedDispatch(setAuthorWebsite({ authorWebsite: newAuthorWebsite }));
1025
1569
  };
1026
1570
  const handleSetStateSchema = (newSchema, scope) => {
1027
- if (compareStringsWithoutWhitespace(newSchema, scope === "global" ? globalStateSchema : localStateSchema)) return;
1028
- dispatch(setStateSchema({
1571
+ if (compareStringsWithoutWhitespace(newSchema, scope === "global" ? latestGlobalStateSchema : latestLocalStateSchema)) return;
1572
+ guardedDispatch(setStateSchema({
1029
1573
  schema: newSchema,
1030
1574
  scope
1031
1575
  }));
1032
1576
  };
1033
1577
  const handleSetInitialState = (newInitialValue, scope) => {
1034
- if (compareStringsWithoutWhitespace(newInitialValue, scope === "global" ? globalStateInitialValue : localStateInitialValue)) return;
1035
- dispatch(setInitialState({
1578
+ if (compareStringsWithoutWhitespace(newInitialValue, scope === "global" ? latestGlobalStateInitialValue : latestLocalStateInitialValue)) return;
1579
+ guardedDispatch(setInitialState({
1036
1580
  initialValue: newInitialValue,
1037
1581
  scope
1038
1582
  }));
@@ -1040,12 +1584,12 @@ function Editor() {
1040
1584
  const handleAddModule = (name) => {
1041
1585
  return new Promise((resolve) => {
1042
1586
  try {
1043
- if (modules.some((module) => compareStringsWithoutWhitespace(module.name, name))) {
1587
+ if (latestModules.some((module) => compareStringsWithoutWhitespace(module.name, name))) {
1044
1588
  resolve(void 0);
1045
1589
  return;
1046
1590
  }
1047
1591
  const id = generateId();
1048
- dispatch(addModule({
1592
+ guardedDispatch(addModule({
1049
1593
  id,
1050
1594
  name
1051
1595
  }));
@@ -1057,19 +1601,19 @@ function Editor() {
1057
1601
  });
1058
1602
  };
1059
1603
  const handleSetModuleName = (id, name) => {
1060
- if (modules.some((module) => compareStringsWithoutWhitespace(module.name, name))) return;
1061
- dispatch(setModuleName({
1604
+ if (latestModules.some((module) => compareStringsWithoutWhitespace(module.name, name))) return;
1605
+ guardedDispatch(setModuleName({
1062
1606
  id,
1063
1607
  name
1064
1608
  }));
1065
1609
  };
1066
1610
  const handleDeleteModule = (id) => {
1067
- dispatch(deleteModule({ id }));
1611
+ guardedDispatch(deleteModule({ id }));
1068
1612
  };
1069
1613
  const handleAddOperation = (moduleId, name) => {
1070
1614
  return new Promise((resolve) => {
1071
1615
  const id = generateId();
1072
- dispatch(addOperation({
1616
+ guardedDispatch(addOperation({
1073
1617
  id,
1074
1618
  moduleId,
1075
1619
  name,
@@ -1083,7 +1627,7 @@ function Editor() {
1083
1627
  });
1084
1628
  };
1085
1629
  const handleSetOperationName = (id, name) => {
1086
- dispatch(setOperationName({
1630
+ guardedDispatch(setOperationName({
1087
1631
  id,
1088
1632
  name
1089
1633
  }), (errors) => {
@@ -1091,44 +1635,44 @@ function Editor() {
1091
1635
  });
1092
1636
  };
1093
1637
  const handleSetOperationSchema = (id, newSchema) => {
1094
- const operation = operations.find((operation) => operation.id === id);
1638
+ const operation = latestOperations.find((operation) => operation.id === id);
1095
1639
  if (operation?.schema && compareStringsWithoutWhitespace(newSchema, operation.schema)) return;
1096
- dispatch(setOperationSchema({
1640
+ guardedDispatch(setOperationSchema({
1097
1641
  id,
1098
1642
  schema: newSchema
1099
1643
  }));
1100
1644
  };
1101
1645
  const handleToggleNoInputRequired = (id, noInputRequired) => {
1102
- const operation = operations.find((op) => op.id === id);
1646
+ const operation = latestOperations.find((op) => op.id === id);
1103
1647
  if (!operation?.name) return;
1104
- if (noInputRequired) dispatch(setOperationSchema({
1648
+ if (noInputRequired) guardedDispatch(setOperationSchema({
1105
1649
  id,
1106
1650
  schema: makeEmptyOperationSchema(operation.name)
1107
1651
  }));
1108
- else dispatch(setOperationSchema({
1652
+ else guardedDispatch(setOperationSchema({
1109
1653
  id,
1110
1654
  schema: makeOperationInitialDoc(operation.name)
1111
1655
  }));
1112
1656
  };
1113
1657
  const handleSetOperationDescription = (id, newDescription) => {
1114
- if (compareStringsWithoutWhitespace(operations.find((operation) => operation.id === id)?.description ?? "", newDescription)) return;
1115
- dispatch(setOperationDescription({
1658
+ if (compareStringsWithoutWhitespace(latestOperations.find((operation) => operation.id === id)?.description ?? "", newDescription)) return;
1659
+ guardedDispatch(setOperationDescription({
1116
1660
  id,
1117
1661
  description: newDescription
1118
1662
  }));
1119
1663
  };
1120
1664
  const handleDeleteOperation = (id) => {
1121
- dispatch(deleteOperation({ id }));
1665
+ guardedDispatch(deleteOperation({ id }));
1122
1666
  };
1123
1667
  const handleAddOperationError = (operationId, errorName) => {
1124
1668
  return new Promise((resolve) => {
1125
1669
  try {
1126
- 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))) {
1127
1671
  resolve(void 0);
1128
1672
  return;
1129
1673
  }
1130
1674
  const id = generateId();
1131
- dispatch(addOperationError({
1675
+ guardedDispatch(addOperationError({
1132
1676
  id,
1133
1677
  operationId,
1134
1678
  errorName,
@@ -1142,11 +1686,11 @@ function Editor() {
1142
1686
  });
1143
1687
  };
1144
1688
  const handleDeleteOperationError = (id) => {
1145
- dispatch(deleteOperationError({ id }));
1689
+ guardedDispatch(deleteOperationError({ id }));
1146
1690
  };
1147
1691
  const handleSetOperationErrorName = (operationId, errorId, errorName) => {
1148
- if ((operations.find((operation) => operation.id === operationId)?.errors.map((error) => error.name).filter(Boolean) ?? []).some((name) => compareStringsWithoutWhitespace(name, errorName))) return;
1149
- 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({
1150
1694
  id: errorId,
1151
1695
  errorName
1152
1696
  }));
@@ -1169,74 +1713,97 @@ function Editor() {
1169
1713
  };
1170
1714
  return /* @__PURE__ */ jsxs("main", {
1171
1715
  className: "min-h-dvh bg-background p-6",
1172
- children: [/* @__PURE__ */ jsx(DocumentToolbar, {}), /* @__PURE__ */ jsx(SchemaContextProvider, {
1173
- globalStateSchemaSdl: globalStateSchema,
1174
- localStateSchemaSdl: localStateSchema,
1175
- operationSchemasSdl,
1176
- children: /* @__PURE__ */ jsxs("div", {
1177
- className: "mx-auto max-w-6xl px-4 pt-8",
1178
- children: [
1179
- /* @__PURE__ */ jsx(ModelMetadata, {
1180
- name: modelName,
1181
- documentType,
1182
- extension,
1183
- description,
1184
- authorName,
1185
- authorWebsite: authorWebsite ?? "",
1186
- globalStateSchema,
1187
- localStateSchema,
1188
- setModelId: handleSetModelId,
1189
- setModelDescription: handleSetModelDescription,
1190
- setModelExtension: handleSetModelExtension,
1191
- setModelName: handleSetModelName,
1192
- setAuthorName: handleSetAuthorName,
1193
- setAuthorWebsite: handleSetAuthorWebsite,
1194
- setStateSchema: handleSetStateSchema
1195
- }),
1196
- /* @__PURE__ */ jsx(Divider, {}),
1197
- /* @__PURE__ */ jsxs("div", { children: [
1198
- /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(StateSchemas, {
1199
- modelName,
1200
- globalStateSchema,
1201
- globalStateInitialValue,
1202
- localStateSchema,
1203
- localStateInitialValue,
1204
- setStateSchema: handleSetStateSchema,
1205
- setInitialState: handleSetInitialState,
1206
- currentScope: scope,
1207
- onScopeChange: setScope
1208
- }) }),
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
+ }),
1209
1748
  /* @__PURE__ */ jsx(Divider, {}),
1210
- /* @__PURE__ */ jsxs("h3", {
1211
- className: "mb-6 text-lg text-foreground capitalize",
1212
- children: [scope, " Operations"]
1749
+ isViewingFrozenVersion && /* @__PURE__ */ jsx(FrozenVersionBanner, {
1750
+ latestVersion: latestSpec.version,
1751
+ viewedVersion: viewedSpec.version
1213
1752
  }),
1214
- /* @__PURE__ */ jsx(Modules, {
1215
- modules: modules.map((module) => ({
1216
- ...module,
1217
- operations: module.operations.filter((op) => op.scope === scope)
1218
- })),
1219
- allOperations: operations,
1220
- addModule: handleAddModule,
1221
- updateModuleName: handleSetModuleName,
1222
- deleteModule: handleDeleteModule,
1223
- updateOperationName: handleSetOperationName,
1224
- updateOperationSchema: handleSetOperationSchema,
1225
- setOperationDescription: handleSetOperationDescription,
1226
- deleteOperation: handleDeleteOperation,
1227
- addOperationError: handleAddOperationError,
1228
- deleteOperationError: handleDeleteOperationError,
1229
- setOperationErrorName: handleSetOperationErrorName,
1230
- addOperationAndInitialSchema,
1231
- 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
+ ]
1232
1793
  })
1233
- ] })
1234
- ]
1794
+ ]
1795
+ })
1796
+ }),
1797
+ /* @__PURE__ */ jsx(VersionAdvisoryModal, {
1798
+ prompt,
1799
+ onReleaseFirst: releaseFirst,
1800
+ onKeepEditing: keepEditing,
1801
+ onCancel: cancelAdvisory
1235
1802
  })
1236
- })]
1803
+ ]
1237
1804
  });
1238
1805
  }
1239
1806
  //#endregion
1240
1807
  export { Editor as default };
1241
1808
 
1242
- //# sourceMappingURL=editor-Cr-mNQca.mjs.map
1809
+ //# sourceMappingURL=editor-ClZqmnoh.mjs.map