firebase-tools 14.3.1 → 14.5.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 (162) hide show
  1. package/lib/api.js +10 -2
  2. package/lib/apphosting/backend.js +74 -18
  3. package/lib/apphosting/rollout.js +2 -2
  4. package/lib/apphosting/secrets/dialogs.js +4 -4
  5. package/lib/apphosting/secrets/index.js +2 -2
  6. package/lib/auth.js +22 -2
  7. package/lib/bin/cli.js +1 -33
  8. package/lib/bin/mcp.js +13 -2
  9. package/lib/checkValidTargetFilters.js +1 -0
  10. package/lib/command.js +3 -2
  11. package/lib/commands/apphosting-secrets-grantaccess.js +1 -1
  12. package/lib/commands/deploy.js +1 -0
  13. package/lib/commands/init.js +1 -4
  14. package/lib/commands/login-use.js +2 -11
  15. package/lib/commands/use.js +9 -8
  16. package/lib/config.js +43 -24
  17. package/lib/crashlytics/listTopIssues.js +44 -0
  18. package/lib/dataconnect/cloudAICompanionClient.js +72 -0
  19. package/lib/dataconnect/cloudAICompanionTypes.js +2 -0
  20. package/lib/dataconnect/fileUtils.js +11 -4
  21. package/lib/dataconnect/schemaMigration.js +6 -7
  22. package/lib/deploy/apphosting/args.js +2 -0
  23. package/lib/deploy/apphosting/deploy.js +77 -0
  24. package/lib/deploy/apphosting/index.js +9 -0
  25. package/lib/deploy/apphosting/prepare.js +147 -0
  26. package/lib/deploy/apphosting/release.js +56 -0
  27. package/lib/deploy/apphosting/util.js +65 -0
  28. package/lib/deploy/extensions/v2FunctionHelper.js +2 -1
  29. package/lib/deploy/firestore/deploy.js +47 -4
  30. package/lib/deploy/functions/checkIam.js +3 -3
  31. package/lib/deploy/functions/ensure.js +2 -1
  32. package/lib/deploy/functions/prepare.js +23 -16
  33. package/lib/deploy/functions/release/fabricator.js +4 -4
  34. package/lib/deploy/functions/release/index.js +1 -1
  35. package/lib/deploy/functions/runtimes/python/index.js +3 -0
  36. package/lib/deploy/functions/runtimes/supported/types.js +17 -11
  37. package/lib/deploy/index.js +2 -0
  38. package/lib/emulator/apphosting/index.js +1 -0
  39. package/lib/emulator/apphosting/serve.js +77 -3
  40. package/lib/emulator/auth/widget_ui.js +2 -1
  41. package/lib/emulator/controller.js +18 -4
  42. package/lib/emulator/dataconnectEmulator.js +9 -2
  43. package/lib/emulator/downloadableEmulatorInfo.json +81 -0
  44. package/lib/emulator/downloadableEmulators.js +28 -108
  45. package/lib/experiments.js +1 -1
  46. package/lib/extensions/manifest.js +2 -5
  47. package/lib/frameworks/angular/index.js +1 -1
  48. package/lib/frameworks/angular/utils.js +17 -6
  49. package/lib/fsAsync.js +9 -2
  50. package/lib/gcp/apphosting.js +13 -1
  51. package/lib/gcp/auth.js +32 -2
  52. package/lib/gcp/cloudbilling.js +12 -1
  53. package/lib/gcp/cloudfunctions.js +1 -2
  54. package/lib/gcp/cloudfunctionsv2.js +1 -2
  55. package/lib/gcp/cloudscheduler.js +2 -2
  56. package/lib/gcp/computeEngine.js +19 -2
  57. package/lib/gcp/devConnect.js +6 -1
  58. package/lib/gcp/firestore.js +24 -1
  59. package/lib/gcp/iam.js +1 -5
  60. package/lib/gcp/run.js +19 -1
  61. package/lib/gcp/storage.js +25 -1
  62. package/lib/index.js +1 -2
  63. package/lib/init/features/apphosting.js +85 -6
  64. package/lib/init/features/database.js +63 -52
  65. package/lib/init/features/dataconnect/index.js +78 -79
  66. package/lib/init/features/dataconnect/sdk.js +19 -6
  67. package/lib/init/features/emulators.js +12 -7
  68. package/lib/init/features/firestore/index.js +80 -39
  69. package/lib/init/features/firestore/indexes.js +29 -31
  70. package/lib/init/features/firestore/rules.js +35 -48
  71. package/lib/init/features/functions/index.js +2 -0
  72. package/lib/init/features/functions/javascript.js +3 -2
  73. package/lib/init/features/functions/typescript.js +3 -2
  74. package/lib/init/features/genkit/index.js +18 -10
  75. package/lib/init/features/hosting/github.js +3 -2
  76. package/lib/init/features/hosting/index.js +9 -8
  77. package/lib/init/features/index.js +10 -5
  78. package/lib/init/features/remoteconfig.js +3 -2
  79. package/lib/init/features/storage.js +31 -8
  80. package/lib/init/index.js +80 -24
  81. package/lib/logger.js +71 -7
  82. package/lib/management/projects.js +24 -1
  83. package/lib/mcp/errors.js +1 -1
  84. package/lib/mcp/index.js +142 -46
  85. package/lib/mcp/tool.js +2 -1
  86. package/lib/mcp/tools/apphosting/fetch_logs.js +69 -0
  87. package/lib/mcp/tools/apphosting/index.js +6 -0
  88. package/lib/mcp/tools/apphosting/list_backends.js +51 -0
  89. package/lib/mcp/tools/auth/get_user.js +16 -7
  90. package/lib/mcp/tools/auth/index.js +8 -1
  91. package/lib/mcp/tools/auth/list_users.js +47 -0
  92. package/lib/mcp/tools/auth/set_claims.js +20 -11
  93. package/lib/mcp/tools/auth/set_sms_region_policy.js +1 -1
  94. package/lib/mcp/tools/core/consult_assistant.js +1 -1
  95. package/lib/mcp/tools/core/create_android_sha.js +40 -0
  96. package/lib/mcp/tools/core/create_app.js +90 -0
  97. package/lib/mcp/tools/core/create_project.js +68 -0
  98. package/lib/mcp/tools/core/get_admin_sdk_config.js +26 -0
  99. package/lib/mcp/tools/core/get_environment.js +51 -0
  100. package/lib/mcp/tools/core/get_sdk_config.js +6 -3
  101. package/lib/mcp/tools/core/index.js +21 -2
  102. package/lib/mcp/tools/core/init.js +153 -0
  103. package/lib/mcp/tools/core/list_apps.js +10 -5
  104. package/lib/mcp/tools/core/list_projects.js +45 -0
  105. package/lib/mcp/tools/core/update_environment.js +55 -0
  106. package/lib/mcp/tools/crashlytics/index.js +5 -0
  107. package/lib/mcp/tools/crashlytics/list_top_issues.js +34 -0
  108. package/lib/mcp/tools/dataconnect/converter.js +13 -1
  109. package/lib/mcp/tools/dataconnect/emulator.js +32 -0
  110. package/lib/mcp/tools/dataconnect/execute_graphql.js +24 -8
  111. package/lib/mcp/tools/dataconnect/execute_graphql_read.js +24 -8
  112. package/lib/mcp/tools/dataconnect/execute_mutation.js +27 -15
  113. package/lib/mcp/tools/dataconnect/execute_query.js +26 -14
  114. package/lib/mcp/tools/dataconnect/generate_operation.js +7 -7
  115. package/lib/mcp/tools/dataconnect/generate_schema.js +1 -1
  116. package/lib/mcp/tools/dataconnect/get_connector.js +7 -7
  117. package/lib/mcp/tools/dataconnect/get_schema.js +5 -5
  118. package/lib/mcp/tools/dataconnect/index.js +1 -5
  119. package/lib/mcp/tools/dataconnect/list_services.js +1 -1
  120. package/lib/mcp/tools/firestore/converter.js +47 -1
  121. package/lib/mcp/tools/firestore/delete_document.js +37 -0
  122. package/lib/mcp/tools/firestore/index.js +12 -2
  123. package/lib/mcp/tools/firestore/list_collections.js +1 -6
  124. package/lib/mcp/tools/firestore/query_collection.js +122 -0
  125. package/lib/mcp/tools/index.js +37 -16
  126. package/lib/mcp/tools/messaging/index.js +5 -0
  127. package/lib/mcp/tools/messaging/send_message.js +42 -0
  128. package/lib/mcp/tools/remoteconfig/get_template.js +27 -0
  129. package/lib/mcp/tools/remoteconfig/index.js +7 -0
  130. package/lib/mcp/tools/remoteconfig/publish_template.js +34 -0
  131. package/lib/mcp/tools/remoteconfig/rollback_template.js +29 -0
  132. package/lib/mcp/tools/rules/get_rules.js +29 -0
  133. package/lib/mcp/tools/rules/validate_rules.js +98 -0
  134. package/lib/mcp/tools/storage/get_download_url.js +8 -5
  135. package/lib/mcp/tools/storage/index.js +7 -2
  136. package/lib/mcp/types.js +10 -1
  137. package/lib/mcp/util.js +165 -2
  138. package/lib/mcp/util.test.js +468 -0
  139. package/lib/messaging/interfaces.js +2 -0
  140. package/lib/messaging/sendMessage.js +48 -0
  141. package/lib/prompt.js +1 -1
  142. package/lib/remoteconfig/publish.js +39 -0
  143. package/lib/requireAuth.js +2 -2
  144. package/lib/track.js +1 -1
  145. package/lib/utils.js +2 -37
  146. package/package.json +2 -1
  147. package/schema/connector-yaml.json +12 -0
  148. package/schema/extension-yaml.json +17 -4
  149. package/schema/firebase-config.json +65 -10
  150. package/standalone/package.json +1 -1
  151. package/templates/dataconnect-prompts/operation-generation-cursor-windsurf-rule.txt +273 -0
  152. package/templates/dataconnect-prompts/schema-generation-cursor-windsurf-rule.txt +653 -0
  153. package/templates/genkit/firebase.1.0.0.template +5 -0
  154. package/templates/init/firestore/firestore.rules +2 -0
  155. package/templates/init/functions/javascript/package.lint.json +1 -1
  156. package/templates/init/functions/javascript/package.nolint.json +1 -1
  157. package/templates/init/functions/typescript/package.lint.json +2 -2
  158. package/templates/init/functions/typescript/package.nolint.json +3 -3
  159. package/lib/mcp/tools/directory/get_project_directory.js +0 -20
  160. package/lib/mcp/tools/directory/index.js +0 -6
  161. package/lib/mcp/tools/directory/set_project_directory.js +0 -33
  162. package/lib/mcp/tools/firestore/get_rules.js +0 -26
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateRulesTool = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const rules_js_1 = require("../../../gcp/rules.js");
8
+ const path_1 = require("path");
9
+ function formatRulesetIssues(issues, rulesSource) {
10
+ const sourceLines = rulesSource.split("\n");
11
+ const formattedOutput = [];
12
+ for (const issue of issues) {
13
+ const { sourcePosition, description, severity } = issue;
14
+ let issueString = `${severity}: ${description} [Ln ${sourcePosition.line}, Col ${sourcePosition.column}]`;
15
+ if (sourcePosition.line) {
16
+ const lineIndex = sourcePosition.line - 1;
17
+ if (lineIndex >= 0 && lineIndex < sourceLines.length) {
18
+ const errorLine = sourceLines[lineIndex];
19
+ issueString += `\n\`\`\`\n${errorLine}`;
20
+ if (sourcePosition.column &&
21
+ sourcePosition.currentOffset &&
22
+ sourcePosition.endOffset &&
23
+ sourcePosition.column > 0 &&
24
+ sourcePosition.endOffset > sourcePosition.currentOffset) {
25
+ const startColumnOnLine = sourcePosition.column - 1;
26
+ const errorTokenLength = sourcePosition.endOffset - sourcePosition.currentOffset;
27
+ if (startColumnOnLine >= 0 &&
28
+ errorTokenLength > 0 &&
29
+ startColumnOnLine <= errorLine.length) {
30
+ const padding = " ".repeat(startColumnOnLine);
31
+ const carets = "^".repeat(errorTokenLength);
32
+ issueString += `\n${padding}${carets}\n\`\`\``;
33
+ }
34
+ }
35
+ }
36
+ }
37
+ formattedOutput.push(issueString);
38
+ }
39
+ return formattedOutput.join("\n\n");
40
+ }
41
+ function validateRulesTool(productName) {
42
+ return (0, tool_js_1.tool)({
43
+ name: "validate_rules",
44
+ description: `Checks the provided ${productName} Rules source for syntax and validation errors. Provide EITHER the source code to validate OR a path to a source file.`,
45
+ inputSchema: zod_1.z.object({
46
+ source: zod_1.z
47
+ .string()
48
+ .optional()
49
+ .describe("the rules source code to check. provide either this OR a path"),
50
+ source_file: zod_1.z
51
+ .string()
52
+ .optional()
53
+ .describe("a file path, relative to the project root, to a file containing the rules source you want to validate. provide this OR source, not both"),
54
+ }),
55
+ annotations: {
56
+ title: `Validate ${productName} Rules`,
57
+ readOnlyHint: true,
58
+ },
59
+ _meta: {
60
+ requiresProject: true,
61
+ requiresAuth: true,
62
+ },
63
+ }, async ({ source, source_file }, { projectId, config, host }) => {
64
+ var _a, _b;
65
+ if (source && source_file) {
66
+ return (0, util_js_1.mcpError)("Must supply `source` or `source_file`, not both.");
67
+ }
68
+ let rulesSourceContent;
69
+ if (source_file) {
70
+ try {
71
+ const filePath = (0, path_1.resolve)(source_file, host.cachedProjectRoot);
72
+ if (filePath.includes("../"))
73
+ return (0, util_js_1.mcpError)("Cannot read files outside of the project directory.");
74
+ rulesSourceContent = config.readProjectFile(source_file);
75
+ }
76
+ catch (e) {
77
+ return (0, util_js_1.mcpError)(`Failed to read source_file '${source_file}': ${e.message}`);
78
+ }
79
+ }
80
+ else if (source) {
81
+ rulesSourceContent = source;
82
+ }
83
+ else {
84
+ rulesSourceContent = "";
85
+ }
86
+ const result = await (0, rules_js_1.testRuleset)(projectId, [
87
+ { name: "test.rules", content: rulesSourceContent },
88
+ ]);
89
+ if ((_b = (_a = result.body) === null || _a === void 0 ? void 0 : _a.issues) === null || _b === void 0 ? void 0 : _b.length) {
90
+ const issues = result.body.issues;
91
+ let out = `Found ${issues.length} issues in rules source:\n\n`;
92
+ out += formatRulesetIssues(issues, rulesSourceContent);
93
+ return (0, util_js_1.toContent)(out);
94
+ }
95
+ return (0, util_js_1.toContent)("OK: No errors detected.");
96
+ });
97
+ }
98
+ exports.validateRulesTool = validateRulesTool;
@@ -9,23 +9,26 @@ exports.get_object_download_url = (0, tool_js_1.tool)({
9
9
  name: "get_object_download_url",
10
10
  description: "Retrieves the download URL for an object in Firebase Storage.",
11
11
  inputSchema: zod_1.z.object({
12
- bucket: zod_1.z.string().nullish().describe("The bucket name in Firebase Storage."),
13
- objectPath: zod_1.z
12
+ bucket: zod_1.z
13
+ .string()
14
+ .optional()
15
+ .describe("The bucket name in Firebase Storage. If not provided, defaults to the project's default bucket (e.g., `{projectid}.firebasestorage.app`)."),
16
+ object_path: zod_1.z
14
17
  .string()
15
18
  .describe("The path to the object in Firebase storage without the bucket name attached"),
16
19
  }),
17
20
  annotations: {
18
- title: "Get the download url for an obejct in Firebase Storage.",
21
+ title: "Get Storage Object Download URL",
19
22
  readOnlyHint: true,
20
23
  },
21
24
  _meta: {
22
25
  requiresProject: true,
23
26
  requiresAuth: true,
24
27
  },
25
- }, async ({ bucket, objectPath }, { projectId }) => {
28
+ }, async ({ bucket, object_path }, { projectId }) => {
26
29
  if (!bucket) {
27
30
  bucket = `${projectId}.firebasestorage.app`;
28
31
  }
29
- const downloadUrl = await (0, storage_js_1.getDownloadUrl)(bucket, objectPath);
32
+ const downloadUrl = await (0, storage_js_1.getDownloadUrl)(bucket, object_path);
30
33
  return (0, util_js_1.toContent)(downloadUrl);
31
34
  });
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.storageTools = void 0;
4
+ const get_rules_1 = require("../rules/get_rules");
5
+ const validate_rules_1 = require("../rules/validate_rules");
4
6
  const get_download_url_1 = require("./get_download_url");
5
- const get_rules_1 = require("./get_rules");
6
- exports.storageTools = [get_rules_1.get_rules, get_download_url_1.get_object_download_url];
7
+ exports.storageTools = [
8
+ (0, get_rules_1.getRulesTool)("Storage", "firebase.storage"),
9
+ (0, validate_rules_1.validateRulesTool)("Storage"),
10
+ get_download_url_1.get_object_download_url,
11
+ ];
package/lib/mcp/types.js CHANGED
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SERVER_FEATURES = void 0;
4
- exports.SERVER_FEATURES = ["firestore", "storage", "dataconnect", "auth"];
4
+ exports.SERVER_FEATURES = [
5
+ "firestore",
6
+ "storage",
7
+ "dataconnect",
8
+ "auth",
9
+ "messaging",
10
+ "remoteconfig",
11
+ "crashlytics",
12
+ "apphosting",
13
+ ];
package/lib/mcp/util.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.commandExistsSync = exports.mcpError = exports.toContent = void 0;
3
+ exports.cleanSchema = exports.checkFeatureActive = exports.commandExistsSync = exports.mcpError = exports.toContent = void 0;
4
4
  const child_process_1 = require("child_process");
5
5
  const js_yaml_1 = require("js-yaml");
6
6
  const os_1 = require("os");
7
+ const api_1 = require("../api");
8
+ const ensureApiEnabled_1 = require("../ensureApiEnabled");
7
9
  function toContent(data, options) {
8
10
  if (typeof data === "string")
9
11
  return { content: [{ type: "text", text: data }] };
@@ -17,8 +19,10 @@ function toContent(data, options) {
17
19
  text = (0, js_yaml_1.dump)(data);
18
20
  break;
19
21
  }
22
+ const prefix = (options === null || options === void 0 ? void 0 : options.contentPrefix) || "";
23
+ const suffix = (options === null || options === void 0 ? void 0 : options.contentSuffix) || "";
20
24
  return {
21
- content: [{ type: "text", text }],
25
+ content: [{ type: "text", text: `${prefix}${text}${suffix}` }],
22
26
  };
23
27
  }
24
28
  exports.toContent = toContent;
@@ -50,3 +54,162 @@ function commandExistsSync(command) {
50
54
  }
51
55
  }
52
56
  exports.commandExistsSync = commandExistsSync;
57
+ const SERVER_FEATURE_APIS = {
58
+ firestore: (0, api_1.firestoreOrigin)(),
59
+ storage: (0, api_1.storageOrigin)(),
60
+ dataconnect: (0, api_1.dataconnectOrigin)(),
61
+ auth: (0, api_1.authManagementOrigin)(),
62
+ messaging: (0, api_1.messagingApiOrigin)(),
63
+ remoteconfig: (0, api_1.remoteConfigApiOrigin)(),
64
+ crashlytics: (0, api_1.crashlyticsApiOrigin)(),
65
+ apphosting: (0, api_1.apphostingOrigin)(),
66
+ };
67
+ async function checkFeatureActive(feature, projectId, options) {
68
+ var _a;
69
+ if (feature in (((_a = options === null || options === void 0 ? void 0 : options.config) === null || _a === void 0 ? void 0 : _a.data) || {}))
70
+ return true;
71
+ try {
72
+ if (projectId)
73
+ return await (0, ensureApiEnabled_1.check)(projectId, SERVER_FEATURE_APIS[feature], "", true);
74
+ }
75
+ catch (e) {
76
+ return true;
77
+ }
78
+ return false;
79
+ }
80
+ exports.checkFeatureActive = checkFeatureActive;
81
+ function deepClean(obj, isRootLevel = false) {
82
+ if (typeof obj !== "object" || obj === null) {
83
+ return obj;
84
+ }
85
+ const cleanedObj = Object.assign({}, obj);
86
+ if (cleanedObj.hasOwnProperty("$schema")) {
87
+ delete cleanedObj.$schema;
88
+ }
89
+ if (cleanedObj.hasOwnProperty("additionalProperties")) {
90
+ delete cleanedObj.additionalProperties;
91
+ }
92
+ if (cleanedObj.hasOwnProperty("type")) {
93
+ const currentType = cleanedObj.type;
94
+ if (Array.isArray(currentType)) {
95
+ let filteredTypes = currentType.filter((t) => t !== "null");
96
+ if (isRootLevel) {
97
+ filteredTypes = filteredTypes.filter((t) => t !== "array");
98
+ }
99
+ if (filteredTypes.length === 0) {
100
+ return null;
101
+ }
102
+ else if (filteredTypes.length === 1) {
103
+ cleanedObj.type = filteredTypes[0];
104
+ }
105
+ else {
106
+ delete cleanedObj.type;
107
+ cleanedObj.anyOf = filteredTypes
108
+ .map((t) => {
109
+ return deepClean({ type: t }, false);
110
+ })
111
+ .filter((subSchema) => subSchema !== null);
112
+ if (cleanedObj.anyOf.length === 0) {
113
+ return null;
114
+ }
115
+ if (cleanedObj.anyOf.length === 1) {
116
+ const singleSchema = cleanedObj.anyOf[0];
117
+ delete cleanedObj.anyOf;
118
+ Object.assign(cleanedObj, singleSchema);
119
+ }
120
+ }
121
+ }
122
+ else if (typeof currentType === "string") {
123
+ if (currentType === "null") {
124
+ return null;
125
+ }
126
+ if (isRootLevel && currentType === "array") {
127
+ return null;
128
+ }
129
+ }
130
+ }
131
+ if (cleanedObj.hasOwnProperty("properties") &&
132
+ typeof cleanedObj.properties === "object" &&
133
+ cleanedObj.properties !== null) {
134
+ const newProperties = {};
135
+ for (const key in cleanedObj.properties) {
136
+ if (cleanedObj.properties.hasOwnProperty(key)) {
137
+ const cleanedPropertySchema = deepClean(cleanedObj.properties[key], false);
138
+ if (cleanedPropertySchema !== null) {
139
+ newProperties[key] = cleanedPropertySchema;
140
+ }
141
+ }
142
+ }
143
+ if (Object.keys(newProperties).length === 0) {
144
+ delete cleanedObj.properties;
145
+ }
146
+ else {
147
+ cleanedObj.properties = newProperties;
148
+ }
149
+ }
150
+ if (cleanedObj.hasOwnProperty("items") &&
151
+ typeof cleanedObj.items === "object" &&
152
+ cleanedObj.items !== null) {
153
+ const cleanedItemsSchema = deepClean(cleanedObj.items, false);
154
+ if (cleanedItemsSchema === null) {
155
+ delete cleanedObj.items;
156
+ }
157
+ else {
158
+ cleanedObj.items = cleanedItemsSchema;
159
+ }
160
+ }
161
+ const defKeywords = ["$defs", "definitions"];
162
+ for (const keyword of defKeywords) {
163
+ if (cleanedObj.hasOwnProperty(keyword) &&
164
+ typeof cleanedObj[keyword] === "object" &&
165
+ cleanedObj[keyword] !== null) {
166
+ const newDefs = {};
167
+ for (const defKey in cleanedObj[keyword]) {
168
+ if (cleanedObj[keyword].hasOwnProperty(defKey)) {
169
+ const cleanedDef = deepClean(cleanedObj[keyword][defKey], false);
170
+ if (cleanedDef !== null) {
171
+ newDefs[defKey] = cleanedDef;
172
+ }
173
+ }
174
+ }
175
+ if (Object.keys(newDefs).length === 0) {
176
+ delete cleanedObj[keyword];
177
+ }
178
+ else {
179
+ cleanedObj[keyword] = newDefs;
180
+ }
181
+ }
182
+ }
183
+ const schemaArrayKeywords = ["anyOf", "allOf", "oneOf"];
184
+ for (const keyword of schemaArrayKeywords) {
185
+ if (cleanedObj.hasOwnProperty(keyword) && Array.isArray(cleanedObj[keyword])) {
186
+ const newSchemaArray = cleanedObj[keyword]
187
+ .map((subSchema) => deepClean(subSchema, false))
188
+ .filter((subSchema) => subSchema !== null);
189
+ if (newSchemaArray.length === 0) {
190
+ delete cleanedObj[keyword];
191
+ }
192
+ else {
193
+ cleanedObj[keyword] = newSchemaArray;
194
+ }
195
+ }
196
+ }
197
+ return cleanedObj;
198
+ }
199
+ function cleanSchema(schema) {
200
+ if (schema && schema.hasOwnProperty("type")) {
201
+ const topLevelType = schema.type;
202
+ if (topLevelType === "array") {
203
+ return {};
204
+ }
205
+ if (Array.isArray(topLevelType)) {
206
+ const filteredRootTypes = topLevelType.filter((t) => t !== "null" && t !== "array");
207
+ if (filteredRootTypes.length === 0 && topLevelType.includes("array")) {
208
+ return {};
209
+ }
210
+ }
211
+ }
212
+ const result = deepClean(schema, true);
213
+ return result === null ? {} : result;
214
+ }
215
+ exports.cleanSchema = cleanSchema;