@graph-knowledge/api 0.4.0 → 0.9.0

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 (42) hide show
  1. package/package.json +1 -1
  2. package/src/index.d.ts +2 -1
  3. package/src/lib/clients/firebase-auth-client.d.ts +7 -0
  4. package/src/lib/clients/firebase-auth-client.js +20 -2
  5. package/src/lib/clients/firebase-firestore-client.js +83 -29
  6. package/src/lib/graph-knowledge-api.d.ts +21 -2
  7. package/src/lib/graph-knowledge-api.js +35 -5
  8. package/src/lib/interfaces/auth-client.interface.d.ts +10 -0
  9. package/src/lib/interfaces/custom-shape-operations.interface.d.ts +82 -0
  10. package/src/lib/interfaces/custom-shape-operations.interface.js +2 -0
  11. package/src/lib/interfaces/node-operations.interface.d.ts +29 -1
  12. package/src/lib/interfaces/template-operations.interface.d.ts +22 -1
  13. package/src/lib/operations/batch-operations.d.ts +3 -15
  14. package/src/lib/operations/batch-operations.js +8 -80
  15. package/src/lib/operations/custom-shape-operations.d.ts +27 -0
  16. package/src/lib/operations/custom-shape-operations.js +175 -0
  17. package/src/lib/operations/document-operations.js +9 -2
  18. package/src/lib/operations/element-operations.d.ts +3 -22
  19. package/src/lib/operations/element-operations.js +6 -119
  20. package/src/lib/operations/node-operations.d.ts +9 -3
  21. package/src/lib/operations/node-operations.js +18 -5
  22. package/src/lib/operations/template-operations.d.ts +3 -1
  23. package/src/lib/operations/template-operations.js +50 -7
  24. package/src/lib/testing/mock-auth-client.d.ts +2 -0
  25. package/src/lib/testing/mock-auth-client.js +7 -0
  26. package/src/lib/types/api-types.d.ts +113 -2
  27. package/src/lib/types/element-input-types.d.ts +38 -10
  28. package/src/lib/utils/element-builder.d.ts +63 -0
  29. package/src/lib/utils/element-builder.js +258 -0
  30. package/src/lib/utils/rotation.d.ts +4 -0
  31. package/src/lib/utils/rotation.js +13 -0
  32. package/src/lib/validators/custom-shape-definition-validator.d.ts +17 -0
  33. package/src/lib/validators/custom-shape-definition-validator.js +135 -0
  34. package/src/lib/validators/element-type-validators/base-element-validator.d.ts +4 -0
  35. package/src/lib/validators/element-type-validators/base-element-validator.js +30 -0
  36. package/src/lib/validators/element-type-validators/basic-shape-validators.js +2 -0
  37. package/src/lib/validators/element-type-validators/block-arrow-validator.js +2 -0
  38. package/src/lib/validators/element-type-validators/line-validator.d.ts +1 -0
  39. package/src/lib/validators/element-type-validators/line-validator.js +12 -5
  40. package/src/lib/validators/element-type-validators/rectangle-validator.js +2 -0
  41. package/src/lib/validators/template-validator.d.ts +7 -1
  42. package/src/lib/validators/template-validator.js +21 -0
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeRotation = normalizeRotation;
4
+ /**
5
+ * Normalizes rotation to integer in range [0, 360).
6
+ */
7
+ function normalizeRotation(rotation) {
8
+ let normalized = rotation % 360;
9
+ if (normalized < 0) {
10
+ normalized += 360;
11
+ }
12
+ return Math.round(normalized);
13
+ }
@@ -0,0 +1,17 @@
1
+ import { CreateCustomShapeInput, UpdateCustomShapeInput } from "../types/api-types";
2
+ /**
3
+ * Validator for custom shape operations.
4
+ */
5
+ export declare class CustomShapeDefinitionValidator {
6
+ /**
7
+ * Validates input for custom shape creation.
8
+ */
9
+ validateCreate(input: CreateCustomShapeInput): void;
10
+ /**
11
+ * Validates input for custom shape update.
12
+ */
13
+ validateUpdate(input: UpdateCustomShapeInput): void;
14
+ private _validateViewBox;
15
+ private _validateDimension;
16
+ private _validateDefaultProperties;
17
+ }
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomShapeDefinitionValidator = void 0;
4
+ const api_errors_1 = require("../errors/api-errors");
5
+ /**
6
+ * Validator for custom shape operations.
7
+ */
8
+ class CustomShapeDefinitionValidator {
9
+ /**
10
+ * Validates input for custom shape creation.
11
+ */
12
+ validateCreate(input) {
13
+ if (!input.name || typeof input.name !== "string") {
14
+ throw new api_errors_1.ValidationError("name is required", "name");
15
+ }
16
+ if (input.name.trim().length === 0) {
17
+ throw new api_errors_1.ValidationError("name cannot be empty", "name");
18
+ }
19
+ if (input.name.length > 100) {
20
+ throw new api_errors_1.ValidationError("name must be 100 characters or less", "name");
21
+ }
22
+ if (!input.svgPathData || typeof input.svgPathData !== "string") {
23
+ throw new api_errors_1.ValidationError("svgPathData is required", "svgPathData");
24
+ }
25
+ if (input.svgPathData.trim().length === 0) {
26
+ throw new api_errors_1.ValidationError("svgPathData cannot be empty", "svgPathData");
27
+ }
28
+ if (!input.viewBox) {
29
+ throw new api_errors_1.ValidationError("viewBox is required", "viewBox");
30
+ }
31
+ this._validateViewBox(input.viewBox);
32
+ if (input.description !== undefined && typeof input.description !== "string") {
33
+ throw new api_errors_1.ValidationError("description must be a string", "description");
34
+ }
35
+ if (input.icon !== undefined && typeof input.icon !== "string") {
36
+ throw new api_errors_1.ValidationError("icon must be a string", "icon");
37
+ }
38
+ if (input.category !== undefined && typeof input.category !== "string") {
39
+ throw new api_errors_1.ValidationError("category must be a string", "category");
40
+ }
41
+ this._validateDimension(input.defaultWidth, "defaultWidth");
42
+ this._validateDimension(input.defaultHeight, "defaultHeight");
43
+ if (input.aspectRatioLocked !== undefined && typeof input.aspectRatioLocked !== "boolean") {
44
+ throw new api_errors_1.ValidationError("aspectRatioLocked must be a boolean", "aspectRatioLocked");
45
+ }
46
+ if (input.defaultProperties !== undefined) {
47
+ this._validateDefaultProperties(input.defaultProperties);
48
+ }
49
+ }
50
+ /**
51
+ * Validates input for custom shape update.
52
+ */
53
+ validateUpdate(input) {
54
+ if (input.name !== undefined) {
55
+ if (typeof input.name !== "string") {
56
+ throw new api_errors_1.ValidationError("name must be a string", "name");
57
+ }
58
+ if (input.name.trim().length === 0) {
59
+ throw new api_errors_1.ValidationError("name cannot be empty", "name");
60
+ }
61
+ if (input.name.length > 100) {
62
+ throw new api_errors_1.ValidationError("name must be 100 characters or less", "name");
63
+ }
64
+ }
65
+ if (input.svgPathData !== undefined) {
66
+ if (typeof input.svgPathData !== "string") {
67
+ throw new api_errors_1.ValidationError("svgPathData must be a string", "svgPathData");
68
+ }
69
+ if (input.svgPathData.trim().length === 0) {
70
+ throw new api_errors_1.ValidationError("svgPathData cannot be empty", "svgPathData");
71
+ }
72
+ }
73
+ if (input.viewBox !== undefined) {
74
+ this._validateViewBox(input.viewBox);
75
+ }
76
+ if (input.description !== undefined && typeof input.description !== "string") {
77
+ throw new api_errors_1.ValidationError("description must be a string", "description");
78
+ }
79
+ if (input.icon !== undefined && typeof input.icon !== "string") {
80
+ throw new api_errors_1.ValidationError("icon must be a string", "icon");
81
+ }
82
+ if (input.category !== undefined && typeof input.category !== "string") {
83
+ throw new api_errors_1.ValidationError("category must be a string", "category");
84
+ }
85
+ this._validateDimension(input.defaultWidth, "defaultWidth");
86
+ this._validateDimension(input.defaultHeight, "defaultHeight");
87
+ if (input.aspectRatioLocked !== undefined && typeof input.aspectRatioLocked !== "boolean") {
88
+ throw new api_errors_1.ValidationError("aspectRatioLocked must be a boolean", "aspectRatioLocked");
89
+ }
90
+ if (input.defaultProperties !== undefined) {
91
+ this._validateDefaultProperties(input.defaultProperties);
92
+ }
93
+ }
94
+ _validateViewBox(viewBox) {
95
+ if (typeof viewBox.width !== "number" || viewBox.width <= 0) {
96
+ throw new api_errors_1.ValidationError("viewBox.width must be a positive number", "viewBox.width");
97
+ }
98
+ if (typeof viewBox.height !== "number" || viewBox.height <= 0) {
99
+ throw new api_errors_1.ValidationError("viewBox.height must be a positive number", "viewBox.height");
100
+ }
101
+ if (typeof viewBox.minX !== "number" || isNaN(viewBox.minX)) {
102
+ throw new api_errors_1.ValidationError("viewBox.minX must be a valid number", "viewBox.minX");
103
+ }
104
+ if (typeof viewBox.minY !== "number" || isNaN(viewBox.minY)) {
105
+ throw new api_errors_1.ValidationError("viewBox.minY must be a valid number", "viewBox.minY");
106
+ }
107
+ }
108
+ _validateDimension(value, field) {
109
+ if (value !== undefined) {
110
+ if (typeof value !== "number" || isNaN(value)) {
111
+ throw new api_errors_1.ValidationError(`${field} must be a valid number`, field);
112
+ }
113
+ if (value < 10 || value > 2000) {
114
+ throw new api_errors_1.ValidationError(`${field} must be between 10 and 2000`, field);
115
+ }
116
+ }
117
+ }
118
+ _validateDefaultProperties(props) {
119
+ if (props.fillColor !== undefined && typeof props.fillColor !== "string") {
120
+ throw new api_errors_1.ValidationError("defaultProperties.fillColor must be a string", "defaultProperties.fillColor");
121
+ }
122
+ if (props.strokeColor !== undefined && typeof props.strokeColor !== "string") {
123
+ throw new api_errors_1.ValidationError("defaultProperties.strokeColor must be a string", "defaultProperties.strokeColor");
124
+ }
125
+ if (props.strokeWidth !== undefined) {
126
+ if (typeof props.strokeWidth !== "number" || isNaN(props.strokeWidth)) {
127
+ throw new api_errors_1.ValidationError("defaultProperties.strokeWidth must be a valid number", "defaultProperties.strokeWidth");
128
+ }
129
+ if (props.strokeWidth < 0 || props.strokeWidth > 50) {
130
+ throw new api_errors_1.ValidationError("defaultProperties.strokeWidth must be between 0 and 50", "defaultProperties.strokeWidth");
131
+ }
132
+ }
133
+ }
134
+ }
135
+ exports.CustomShapeDefinitionValidator = CustomShapeDefinitionValidator;
@@ -32,4 +32,8 @@ export declare abstract class BaseElementValidator {
32
32
  * Validates stroke width.
33
33
  */
34
34
  protected validateStrokeWidth(value: unknown, field: string): void;
35
+ /**
36
+ * Validates optional text label properties shared by basic shapes.
37
+ */
38
+ protected validateTextLabelProperties(input: Record<string, unknown>): void;
35
39
  }
@@ -96,5 +96,35 @@ class BaseElementValidator {
96
96
  throw new api_errors_1.ValidationError(`${field} must be non-negative`, field);
97
97
  }
98
98
  }
99
+ /**
100
+ * Validates optional text label properties shared by basic shapes.
101
+ */
102
+ validateTextLabelProperties(input) {
103
+ if (input["text"] !== undefined && typeof input["text"] !== "string") {
104
+ throw new api_errors_1.ValidationError("text must be a string", "text");
105
+ }
106
+ if (input["fontSize"] !== undefined) {
107
+ const fs = input["fontSize"];
108
+ if (typeof fs !== "number" || isNaN(fs)) {
109
+ throw new api_errors_1.ValidationError("fontSize must be a valid number", "fontSize");
110
+ }
111
+ if (fs < 1 || fs > 200) {
112
+ throw new api_errors_1.ValidationError("fontSize must be between 1 and 200", "fontSize");
113
+ }
114
+ }
115
+ this.validateColor(input["textColor"], "textColor");
116
+ if (input["textAlign"] !== undefined) {
117
+ const valid = ["left", "center", "right"];
118
+ if (!valid.includes(input["textAlign"])) {
119
+ throw new api_errors_1.ValidationError(`textAlign must be one of: ${valid.join(", ")}`, "textAlign");
120
+ }
121
+ }
122
+ if (input["verticalAlign"] !== undefined) {
123
+ const valid = ["top", "middle", "bottom"];
124
+ if (!valid.includes(input["verticalAlign"])) {
125
+ throw new api_errors_1.ValidationError(`verticalAlign must be one of: ${valid.join(", ")}`, "verticalAlign");
126
+ }
127
+ }
128
+ }
99
129
  }
100
130
  exports.BaseElementValidator = BaseElementValidator;
@@ -19,6 +19,8 @@ class BasicShapeValidator extends base_element_validator_1.BaseElementValidator
19
19
  this.validateColor(shapeInput.fillColor, "fillColor");
20
20
  this.validateColor(shapeInput.strokeColor, "strokeColor");
21
21
  this.validateStrokeWidth(shapeInput.strokeWidth, "strokeWidth");
22
+ // Validate text label properties
23
+ this.validateTextLabelProperties(shapeInput);
22
24
  }
23
25
  }
24
26
  /**
@@ -20,6 +20,8 @@ class BlockArrowValidator extends base_element_validator_1.BaseElementValidator
20
20
  this.validateColor(blockArrowInput.strokeColor, "strokeColor");
21
21
  this.validateStrokeWidth(blockArrowInput.strokeWidth, "strokeWidth");
22
22
  this.validateDirection(blockArrowInput.direction);
23
+ // Validate text label properties
24
+ this.validateTextLabelProperties(blockArrowInput);
23
25
  }
24
26
  validateDirection(value) {
25
27
  if (value === undefined)
@@ -8,4 +8,5 @@ export declare class LineValidator extends BaseElementValidator implements IElem
8
8
  readonly elementType = "line";
9
9
  validate(input: AnyElementInput): void;
10
10
  private validateLineStyle;
11
+ private validateMarker;
11
12
  }
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LineValidator = void 0;
4
4
  const api_errors_1 = require("../../errors/api-errors");
5
5
  const base_element_validator_1 = require("./base-element-validator");
6
+ const VALID_LINE_STYLES = ["solid", "dashed", "dotted"];
7
+ const VALID_MARKERS = ["none", "arrow", "diamond", "circle"];
6
8
  /**
7
9
  * Validator for line elements.
8
10
  */
@@ -19,16 +21,21 @@ class LineValidator extends base_element_validator_1.BaseElementValidator {
19
21
  this.validateColor(lineInput.strokeColor, "strokeColor");
20
22
  this.validateStrokeWidth(lineInput.strokeWidth, "strokeWidth");
21
23
  this.validateLineStyle(lineInput.lineStyle);
24
+ this.validateMarker(lineInput.startMarker, "startMarker");
25
+ this.validateMarker(lineInput.endMarker, "endMarker");
22
26
  }
23
27
  validateLineStyle(value) {
24
28
  if (value === undefined)
25
29
  return;
26
- if (typeof value !== "string") {
27
- throw new api_errors_1.ValidationError("lineStyle must be a string", "lineStyle");
30
+ if (!VALID_LINE_STYLES.includes(value)) {
31
+ throw new api_errors_1.ValidationError(`lineStyle must be one of: ${VALID_LINE_STYLES.join(", ")}`, "lineStyle");
28
32
  }
29
- const validStyles = ["solid", "dashed", "dotted"];
30
- if (!validStyles.includes(value)) {
31
- throw new api_errors_1.ValidationError(`lineStyle must be one of: ${validStyles.join(", ")}`, "lineStyle");
33
+ }
34
+ validateMarker(value, field) {
35
+ if (value === undefined)
36
+ return;
37
+ if (!VALID_MARKERS.includes(value)) {
38
+ throw new api_errors_1.ValidationError(`${field} must be one of: ${VALID_MARKERS.join(", ")}`, field);
32
39
  }
33
40
  }
34
41
  }
@@ -20,6 +20,8 @@ class RectangleValidator extends base_element_validator_1.BaseElementValidator {
20
20
  this.validateColor(rectangleInput.strokeColor, "strokeColor");
21
21
  this.validateStrokeWidth(rectangleInput.strokeWidth, "strokeWidth");
22
22
  this.validateCornerRadius(rectangleInput.cornerRadius);
23
+ // Validate text label properties
24
+ this.validateTextLabelProperties(rectangleInput);
23
25
  }
24
26
  validateCornerRadius(value) {
25
27
  if (value === undefined)
@@ -1,4 +1,4 @@
1
- import { CreateTemplateInput } from "../types/api-types";
1
+ import { CreateTemplateInput, UpdateTemplateInput } from "../types/api-types";
2
2
  /**
3
3
  * Validator for template operations.
4
4
  */
@@ -9,6 +9,12 @@ export declare class TemplateValidator {
9
9
  * @throws ValidationError if validation fails
10
10
  */
11
11
  validateCreate(input: CreateTemplateInput): void;
12
+ /**
13
+ * Validates input for template update.
14
+ * @param input The update input to validate
15
+ * @throws ValidationError if validation fails
16
+ */
17
+ validateUpdate(input: UpdateTemplateInput): void;
12
18
  /**
13
19
  * Validates canvas dimensions.
14
20
  */
@@ -26,6 +26,27 @@ class TemplateValidator {
26
26
  }
27
27
  this.validateCanvasDimensions(input.canvasWidth, input.canvasHeight);
28
28
  }
29
+ /**
30
+ * Validates input for template update.
31
+ * @param input The update input to validate
32
+ * @throws ValidationError if validation fails
33
+ */
34
+ validateUpdate(input) {
35
+ if (input.title !== undefined) {
36
+ if (typeof input.title !== "string") {
37
+ throw new api_errors_1.ValidationError("title must be a string", "title");
38
+ }
39
+ if (input.title.trim().length === 0) {
40
+ throw new api_errors_1.ValidationError("title cannot be empty", "title");
41
+ }
42
+ if (input.title.length > 200) {
43
+ throw new api_errors_1.ValidationError("title must be 200 characters or less", "title");
44
+ }
45
+ }
46
+ if (input.content !== undefined && typeof input.content !== "string") {
47
+ throw new api_errors_1.ValidationError("content must be a string", "content");
48
+ }
49
+ }
29
50
  /**
30
51
  * Validates canvas dimensions.
31
52
  */