kubernetes-fluent-client 3.5.6 → 3.6.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 (46) hide show
  1. package/dist/cli.js +9 -16
  2. package/dist/fetch.js +5 -8
  3. package/dist/fluent/index.d.ts +2 -1
  4. package/dist/fluent/index.d.ts.map +1 -1
  5. package/dist/fluent/index.js +27 -29
  6. package/dist/fluent/shared-types.d.ts +49 -0
  7. package/dist/fluent/shared-types.d.ts.map +1 -0
  8. package/dist/fluent/shared-types.js +23 -0
  9. package/dist/fluent/types.d.ts +2 -37
  10. package/dist/fluent/types.d.ts.map +1 -1
  11. package/dist/fluent/types.js +1 -14
  12. package/dist/fluent/utils.d.ts +1 -1
  13. package/dist/fluent/utils.d.ts.map +1 -1
  14. package/dist/fluent/utils.js +25 -35
  15. package/dist/fluent/watch.d.ts +1 -8
  16. package/dist/fluent/watch.d.ts.map +1 -1
  17. package/dist/fluent/watch.js +23 -43
  18. package/dist/generate.js +22 -65
  19. package/dist/helpers.js +5 -10
  20. package/dist/index.js +13 -60
  21. package/dist/kinds.js +2 -7
  22. package/dist/normalization.d.ts +97 -0
  23. package/dist/normalization.d.ts.map +1 -0
  24. package/dist/normalization.js +152 -0
  25. package/dist/patch.js +1 -2
  26. package/dist/postProcessing.d.ts +6 -127
  27. package/dist/postProcessing.d.ts.map +1 -1
  28. package/dist/postProcessing.js +24 -279
  29. package/dist/types.d.ts +3 -2
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/types.js +1 -5
  32. package/dist/upstream.js +2 -53
  33. package/package.json +11 -8
  34. package/src/cli.ts +1 -3
  35. package/src/fluent/index.ts +12 -11
  36. package/src/fluent/shared-types.ts +55 -0
  37. package/src/fluent/types.ts +3 -54
  38. package/src/fluent/utils.ts +2 -2
  39. package/src/fluent/watch.ts +2 -21
  40. package/src/normalization.ts +181 -0
  41. package/src/postProcessing.ts +11 -239
  42. package/src/types.ts +3 -4
  43. package/dist/fileSystem.d.ts +0 -11
  44. package/dist/fileSystem.d.ts.map +0 -1
  45. package/dist/fileSystem.js +0 -52
  46. package/src/fileSystem.ts +0 -25
@@ -9,7 +9,8 @@ import type { PartialDeep } from "type-fest";
9
9
  import { fetch } from "../fetch";
10
10
  import { modelToGroupVersionKind } from "../kinds";
11
11
  import { GenericClass } from "../types";
12
- import { ApplyCfg, FetchMethods, Filters, K8sInit, Paths, WatchAction } from "./types";
12
+ import { K8sInit, Paths } from "./types";
13
+ import { Filters, WatchAction, FetchMethods, ApplyCfg } from "./shared-types";
13
14
  import { k8sCfg, k8sExec } from "./utils";
14
15
  import { WatchCfg, Watcher } from "./watch";
15
16
  import { hasLogs } from "../helpers";
@@ -114,7 +115,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
114
115
  }
115
116
 
116
117
  try {
117
- const object = await k8sExec<T, K>(model, filters, "GET");
118
+ const object = await k8sExec<T, K>(model, filters, FetchMethods.GET);
118
119
 
119
120
  if (kind !== "Pod") {
120
121
  if (kind === "Service") {
@@ -144,7 +145,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
144
145
 
145
146
  const podModel = { ...model, name: "V1Pod" };
146
147
  const logPromises = podList.map(po =>
147
- k8sExec<T, string>(podModel, { ...filters, name: po.metadata!.name! }, "LOG"),
148
+ k8sExec<T, string>(podModel, { ...filters, name: po.metadata!.name! }, FetchMethods.LOG),
148
149
  );
149
150
 
150
151
  const responses = await Promise.all(logPromises);
@@ -179,7 +180,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
179
180
  filters.name = name;
180
181
  }
181
182
 
182
- return k8sExec<T, K | KubernetesListObject<K>>(model, filters, "GET");
183
+ return k8sExec<T, K | KubernetesListObject<K>>(model, filters, FetchMethods.GET);
183
184
  }
184
185
 
185
186
  /**
@@ -195,7 +196,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
195
196
 
196
197
  try {
197
198
  // Try to delete the resource
198
- await k8sExec<T, void>(model, filters, "DELETE");
199
+ await k8sExec<T, void>(model, filters, FetchMethods.DELETE);
199
200
  } catch (e) {
200
201
  // If the resource doesn't exist, ignore the error
201
202
  if (e.status === StatusCodes.NOT_FOUND) {
@@ -215,7 +216,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
215
216
  applyCfg: ApplyCfg = { force: false },
216
217
  ): Promise<K> {
217
218
  syncFilters(resource as K);
218
- return k8sExec(model, filters, "APPLY", resource, applyCfg);
219
+ return k8sExec(model, filters, FetchMethods.APPLY, resource, applyCfg);
219
220
  }
220
221
 
221
222
  /**
@@ -224,7 +225,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
224
225
  */
225
226
  async function Create(resource: K): Promise<K> {
226
227
  syncFilters(resource);
227
- return k8sExec(model, filters, "POST", resource);
228
+ return k8sExec(model, filters, FetchMethods.POST, resource);
228
229
  }
229
230
 
230
231
  /**
@@ -248,7 +249,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
248
249
  },
249
250
  };
250
251
  // Try to evict the resource
251
- await k8sExec<T, void>(model, filters, "POST", evictionPayload);
252
+ await k8sExec<T, void>(model, filters, FetchMethods.POST, evictionPayload);
252
253
  } catch (e) {
253
254
  // If the resource doesn't exist, ignore the error
254
255
  if (e.status === StatusCodes.NOT_FOUND) {
@@ -268,7 +269,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
268
269
  throw new Error("No operations specified");
269
270
  }
270
271
 
271
- return k8sExec(model, filters, "PATCH", payload);
272
+ return k8sExec(model, filters, FetchMethods.PATCH, payload);
272
273
  }
273
274
 
274
275
  /**
@@ -277,7 +278,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
277
278
  */
278
279
  async function PatchStatus(resource: PartialDeep<K>): Promise<K> {
279
280
  syncFilters(resource as K);
280
- return k8sExec(model, filters, "PATCH_STATUS", resource);
281
+ return k8sExec(model, filters, FetchMethods.PATCH_STATUS, resource);
281
282
  }
282
283
 
283
284
  /**
@@ -292,7 +293,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
292
293
  * @inheritdoc
293
294
  * @see {@link K8sInit.Raw}
294
295
  */
295
- async function Raw(url: string, method: FetchMethods = "GET") {
296
+ async function Raw(url: string, method: FetchMethods = FetchMethods.GET) {
296
297
  const thing = await k8sCfg(method);
297
298
  const { opts, serverUrl } = thing;
298
299
  const resp = await fetch<K>(`${serverUrl}${url}`, opts);
@@ -0,0 +1,55 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
3
+ import { GenericClass, GroupVersionKind } from "../types";
4
+ import { RequestInit } from "undici";
5
+ import { KubernetesObject } from "@kubernetes/client-node";
6
+ /**
7
+ * Fetch options and server URL
8
+ */
9
+ export type K8sConfigPromise = Promise<{ opts: RequestInit; serverUrl: string | URL }>;
10
+
11
+ /**
12
+ * The Phase matched when using the K8s Watch API.
13
+ */
14
+ export enum WatchPhase {
15
+ Added = "ADDED",
16
+ Modified = "MODIFIED",
17
+ Deleted = "DELETED",
18
+ Bookmark = "BOOKMARK",
19
+ Error = "ERROR",
20
+ }
21
+
22
+ export type WatchAction<T extends GenericClass, K extends KubernetesObject = InstanceType<T>> = (
23
+ update: K,
24
+ phase: WatchPhase,
25
+ ) => Promise<void> | void;
26
+
27
+ export interface Filters {
28
+ kindOverride?: GroupVersionKind;
29
+ fields?: Record<string, string>;
30
+ labels?: Record<string, string>;
31
+ name?: string;
32
+ namespace?: string;
33
+ }
34
+
35
+ /**
36
+ * Configuration for the apply function.
37
+ */
38
+ export type ApplyCfg = {
39
+ /**
40
+ * Force the apply to be a create.
41
+ */
42
+ force?: boolean;
43
+ };
44
+
45
+ export enum FetchMethods {
46
+ APPLY = "APPLY",
47
+ DELETE = "DELETE",
48
+ GET = "GET",
49
+ LOG = "LOG",
50
+ PATCH = "PATCH",
51
+ PATCH_STATUS = "PATCH_STATUS",
52
+ POST = "POST",
53
+ PUT = "PUT",
54
+ WATCH = "WATCH",
55
+ }
@@ -4,22 +4,16 @@
4
4
  import { KubernetesListObject, KubernetesObject } from "@kubernetes/client-node";
5
5
  import { Operation } from "fast-json-patch";
6
6
  import type { PartialDeep } from "type-fest";
7
- import { RequestInit } from "undici";
8
- import { GenericClass, GroupVersionKind } from "../types";
7
+ import { GenericClass } from "../types";
9
8
  import { WatchCfg, Watcher } from "./watch";
10
9
  import https from "https";
11
10
  import { SecureClientSessionOptions } from "http2";
12
-
11
+ import { WatchAction, FetchMethods, ApplyCfg } from "./shared-types";
13
12
  /*
14
- * Watch Class Type
13
+ * Watch Class Type - Used in Pepr Watch Processor
15
14
  */
16
15
  export type WatcherType<T extends GenericClass> = Watcher<T>;
17
16
 
18
- /**
19
- * Fetch options and server URL
20
- */
21
- export type K8sConfigPromise = Promise<{ opts: RequestInit; serverUrl: string | URL }>;
22
-
23
17
  /**
24
18
  * Agent options for the the http2Watch
25
19
  */
@@ -35,36 +29,6 @@ export interface Options {
35
29
  agent?: https.Agent & { options?: AgentOptions };
36
30
  }
37
31
 
38
- /**
39
- * The Phase matched when using the K8s Watch API.
40
- */
41
- export enum WatchPhase {
42
- Added = "ADDED",
43
- Modified = "MODIFIED",
44
- Deleted = "DELETED",
45
- Bookmark = "BOOKMARK",
46
- Error = "ERROR",
47
- }
48
-
49
- export type FetchMethods =
50
- | "APPLY"
51
- | "DELETE"
52
- | "GET"
53
- | "LOG"
54
- | "PATCH"
55
- | "PATCH_STATUS"
56
- | "POST"
57
- | "PUT"
58
- | "WATCH";
59
-
60
- export interface Filters {
61
- kindOverride?: GroupVersionKind;
62
- fields?: Record<string, string>;
63
- labels?: Record<string, string>;
64
- name?: string;
65
- namespace?: string;
66
- }
67
-
68
32
  /**
69
33
  * Get the resource or resources matching the filters.
70
34
  * If no filters are specified, all resources will be returned.
@@ -225,16 +189,6 @@ export type K8sWithFilters<T extends GenericClass, K extends KubernetesObject> =
225
189
  WithLabel: (key: string, value?: string) => K8sWithFilters<T, K>;
226
190
  };
227
191
 
228
- /**
229
- * Configuration for the apply function.
230
- */
231
- export type ApplyCfg = {
232
- /**
233
- * Force the apply to be a create.
234
- */
235
- force?: boolean;
236
- };
237
-
238
192
  export type K8sInit<T extends GenericClass, K extends KubernetesObject> = K8sWithFilters<T, K> &
239
193
  K8sUnfilteredActions<K> & {
240
194
  /**
@@ -246,11 +200,6 @@ export type K8sInit<T extends GenericClass, K extends KubernetesObject> = K8sWit
246
200
  InNamespace: (namespace: string) => K8sWithFilters<T, K>;
247
201
  };
248
202
 
249
- export type WatchAction<T extends GenericClass, K extends KubernetesObject = InstanceType<T>> = (
250
- update: K,
251
- phase: WatchPhase,
252
- ) => Promise<void> | void;
253
-
254
203
  // Special types to handle the recursive keyof typescript lookup
255
204
  type Join<K, P> = K extends string | number
256
205
  ? P extends string | number
@@ -9,7 +9,7 @@ import { Agent as httpsAgent } from "https";
9
9
  import { fetch } from "../fetch";
10
10
  import { modelToGroupVersionKind } from "../kinds";
11
11
  import { GenericClass } from "../types";
12
- import { ApplyCfg, FetchMethods, Filters, K8sConfigPromise } from "./types";
12
+ import { ApplyCfg, Filters, K8sConfigPromise, FetchMethods } from "./shared-types";
13
13
  import fs from "fs";
14
14
  import { V1Eviction as Eviction } from "@kubernetes/client-node";
15
15
  const SSA_CONTENT_TYPE = "application/apply-patch+yaml";
@@ -222,7 +222,7 @@ export async function k8sExec<T extends GenericClass, K>(
222
222
  applyCfg: ApplyCfg = { force: false },
223
223
  ) {
224
224
  const reconstruct = async (method: FetchMethods): K8sConfigPromise => {
225
- const configMethod = method === "LOG" ? "GET" : method;
225
+ const configMethod = method === FetchMethods.LOG ? FetchMethods.GET : method;
226
226
  const { opts, serverUrl } = await k8sCfg(configMethod);
227
227
 
228
228
  // Build the base path once, using excludeName only for standard POST requests
@@ -1,15 +1,13 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
3
3
 
4
- import { createHash } from "crypto";
5
4
  import { EventEmitter } from "events";
6
5
  import { fetch } from "undici";
7
6
  import { fetch as wrappedFetch } from "../fetch";
8
7
  import { GenericClass, KubernetesListObject } from "../types";
9
- import { Filters, WatchAction, WatchPhase, K8sConfigPromise } from "./types";
10
8
  import { k8sCfg, pathBuilder, getHeaders } from "./utils";
11
9
  import { Readable } from "stream";
12
-
10
+ import { K8sConfigPromise, WatchPhase, WatchAction, Filters, FetchMethods } from "./shared-types";
13
11
  export enum WatchEvent {
14
12
  /** Watch is connected successfully */
15
13
  CONNECT = "connect",
@@ -171,23 +169,6 @@ export class Watcher<T extends GenericClass> {
171
169
  this.#abortController.abort();
172
170
  }
173
171
 
174
- /**
175
- * Get a unique ID for the watch based on the model and filters.
176
- * This is useful for caching the watch data or resource versions.
177
- *
178
- * @returns the watch CacheID
179
- */
180
- public getCacheID() {
181
- // Build the URL, we don't care about the server URL or resourceVersion
182
- const url = pathBuilder("https://ignore", this.#model, this.#filters, false);
183
-
184
- // Hash and truncate the ID to 10 characters, cache the result
185
- return createHash("sha224")
186
- .update(url.pathname + url.search)
187
- .digest("hex")
188
- .substring(0, 10);
189
- }
190
-
191
172
  /**
192
173
  * Subscribe to watch events. This is an EventEmitter that emits the following events:
193
174
  *
@@ -214,7 +195,7 @@ export class Watcher<T extends GenericClass> {
214
195
  continueToken?: string,
215
196
  ): K8sConfigPromise => {
216
197
  // Build the path and query params for the resource, excluding the name
217
- const { opts, serverUrl } = await k8sCfg("GET");
198
+ const { opts, serverUrl } = await k8sCfg(FetchMethods.GET);
218
199
  const k8sUrl = serverUrl instanceof URL ? serverUrl.toString() : serverUrl;
219
200
  const url = pathBuilder(k8sUrl, this.#model, this.#filters, true);
220
201
 
@@ -0,0 +1,181 @@
1
+ import { GenerateOptions } from "./generate";
2
+
3
+ /**
4
+ * Normalizes indentation for TypeScript lines to a consistent format.
5
+ *
6
+ * @param lines The generated TypeScript lines.
7
+ * @returns The lines with normalized indentation.
8
+ */
9
+ export function normalizeIndentation(lines: string[]): string[] {
10
+ return lines.map(line => line.replace(/^ {4}/, " "));
11
+ }
12
+
13
+ /**
14
+ * Normalizes the indentation of a single line to use two spaces instead of four.
15
+ *
16
+ * @param line The line of code to normalize.
17
+ * @returns The line with normalized indentation.
18
+ */
19
+ export function normalizeLineIndentation(line: string): string {
20
+ return line.replace(/^ {4}/, " ");
21
+ }
22
+
23
+ /**
24
+ * Normalizes spacing between property names and types in TypeScript lines.
25
+ *
26
+ * @param lines The generated TypeScript lines.
27
+ * @returns The lines with normalized property spacing.
28
+ */
29
+ export function normalizePropertySpacing(lines: string[]): string[] {
30
+ // https://regex101.com/r/XEv3pL/1
31
+ return lines.map(line => line.replace(/\s*\?\s*:\s*/, "?: "));
32
+ }
33
+
34
+ /**
35
+ * Processes a single line inside a class extending `GenericKind`.
36
+ *
37
+ * @param line The current line of code.
38
+ * @param genericKindProperties The list of properties from `GenericKind`.
39
+ * @param foundInterfaces The set of found interfaces in the file.
40
+ * @returns The modified line.
41
+ */
42
+ export function modifyAndNormalizeClassProperties(
43
+ line: string,
44
+ genericKindProperties: string[],
45
+ foundInterfaces: Set<string>,
46
+ ): string {
47
+ line = modifyPropertiesAndAddEslintDirective(line, genericKindProperties, foundInterfaces);
48
+ line = normalizeLineIndentation(line);
49
+ return line;
50
+ }
51
+
52
+ /**
53
+ * Normalizes lines after processing, including indentation, spacing, and removing unnecessary lines.
54
+ *
55
+ * @param lines The lines of the file content.
56
+ * @param opts The options for processing.
57
+ * @returns The normalized lines.
58
+ */
59
+ export function normalizeIndentationAndSpacing(lines: string[], opts: GenerateOptions): string[] {
60
+ let normalizedLines = normalizeIndentation(lines);
61
+ normalizedLines = normalizePropertySpacing(normalizedLines);
62
+ return removePropertyStringAny(normalizedLines, opts);
63
+ }
64
+
65
+ /**
66
+ * Removes lines containing `[property: string]: any;` from TypeScript files.
67
+ *
68
+ * @param lines The generated TypeScript lines.
69
+ * @param opts The options for processing.
70
+ * @returns The lines with `[property: string]: any;` removed.
71
+ */
72
+ export function removePropertyStringAny(lines: string[], opts: GenerateOptions): string[] {
73
+ if (opts.language === "ts" || opts.language === "typescript") {
74
+ return lines.filter(line => !line.includes("[property: string]: any;"));
75
+ }
76
+ return lines;
77
+ }
78
+
79
+ /**
80
+ * Applies ESLint and property modifiers to a line of code.
81
+ *
82
+ * @param line - The current line of code.
83
+ * @param genericKindProperties - The list of properties from `GenericKind`.
84
+ * @param foundInterfaces - The set of found interfaces in the file.
85
+ * @returns The modified line.
86
+ */
87
+ export function modifyPropertiesAndAddEslintDirective(
88
+ line: string,
89
+ genericKindProperties: string[],
90
+ foundInterfaces: Set<string>,
91
+ ): string {
92
+ line = addDeclareAndOptionalModifiersToProperties(line, genericKindProperties, foundInterfaces);
93
+ line = processEslintDisable(line, genericKindProperties);
94
+ return line;
95
+ }
96
+
97
+ /**
98
+ * Adds an ESLint disable comment for `[key: string]: any` if it's not part of `GenericKind`.
99
+ *
100
+ * @param line The current line of code.
101
+ * @param genericKindProperties The list of properties from `GenericKind`.
102
+ * @returns The modified line with the ESLint disable comment.
103
+ */
104
+ export function processEslintDisable(line: string, genericKindProperties: string[]): string {
105
+ if (line.includes("[key: string]: any") && !genericKindProperties.includes("[key: string]")) {
106
+ return ` // eslint-disable-next-line @typescript-eslint/no-explicit-any\n${line}`;
107
+ }
108
+ return line;
109
+ }
110
+
111
+ /**
112
+ * Applies property modifiers to a line of code.
113
+ *
114
+ * @param line The current line of code.
115
+ * @param genericKindProperties The list of properties from `GenericKind`.
116
+ * @param foundInterfaces The set of found interfaces in the file.
117
+ * @returns The modified line.
118
+ */
119
+ export function addDeclareAndOptionalModifiersToProperties(
120
+ line: string,
121
+ genericKindProperties: string[],
122
+ foundInterfaces: Set<string>,
123
+ ): string {
124
+ line = addDeclareToGenericKindProperties(line, genericKindProperties);
125
+ line = makePropertiesOptional(line, foundInterfaces);
126
+ line = normalizeLineIndentation(line);
127
+ return line;
128
+ }
129
+
130
+ /**
131
+ * Adds the `declare` keyword to `GenericKind` properties.
132
+ *
133
+ * @param line The current line of code.
134
+ * @param genericKindProperties The list of properties from `GenericKind`.
135
+ * @returns The modified line with the `declare` keyword, if applicable.
136
+ */
137
+ export function addDeclareToGenericKindProperties(
138
+ line: string,
139
+ genericKindProperties: string[],
140
+ ): string {
141
+ for (const prop of genericKindProperties) {
142
+ const propertyPattern = getPropertyPattern(prop);
143
+ if (propertyPattern.test(line)) {
144
+ return line.replace(prop, `declare ${prop}`);
145
+ }
146
+ }
147
+ return line;
148
+ }
149
+
150
+ /**
151
+ * Makes a property optional if its type matches one of the found interfaces and it is not already optional.
152
+ *
153
+ * @param line The current line of code.
154
+ * @param foundInterfaces The set of found interfaces in the file.
155
+ * @returns The modified line with the optional `?` symbol.
156
+ */
157
+ export function makePropertiesOptional(line: string, foundInterfaces: Set<string>): string {
158
+ // https://regex101.com/r/kX8TCj/1
159
+ const propertyTypePattern = /:\s*(?<propertyType>\w+)\s*;/;
160
+ const match = line.match(propertyTypePattern);
161
+
162
+ if (match?.groups?.propertyType) {
163
+ const { propertyType } = match.groups;
164
+ if (foundInterfaces.has(propertyType) && !line.includes("?")) {
165
+ return line.replace(":", "?:");
166
+ }
167
+ }
168
+ return line;
169
+ }
170
+
171
+ /**
172
+ * Generates a regular expression to match a property pattern in TypeScript.
173
+ *
174
+ * @param prop The property name to match.
175
+ * @returns A regular expression to match the property pattern.
176
+ */
177
+ export function getPropertyPattern(prop: string): RegExp {
178
+ // For prop="kind", the pattern will match "kind ? :" or "kind :"
179
+ // https://regex101.com/r/mF8kXn/1
180
+ return new RegExp(`\\b${prop}\\b\\s*\\?\\s*:|\\b${prop}\\b\\s*:`);
181
+ }