kubernetes-fluent-client 2.0.0 → 2.0.1

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.
package/README.md CHANGED
@@ -20,13 +20,15 @@ async function demo() {
20
20
  // Now, we can use the fluent API to query for the resources we just created
21
21
 
22
22
  // You can use watch to monitor resources in the cluster and react to changes
23
- // This will run until the process is terminated or the watch is aborted
24
- const ctrl = await K8s(kind.Pod).Watch((pod, phase) => {
23
+ const watcher = K8s(kind.Pod).Watch((pod, phase) => {
25
24
  console.log(`Pod ${pod.metadata?.name} is ${phase}`);
26
25
  });
27
26
 
27
+ // This will run until the process is terminated or the watch is aborted
28
+ await watcher.start();
29
+
28
30
  // Let's abort the watch after 5 seconds
29
- setTimeout(ctrl.abort, 5 * 1000);
31
+ setTimeout(watcher.close, 5 * 1000);
30
32
 
31
33
  // Passing the name to Get() will return a single resource
32
34
  const ns = await K8s(kind.Namespace).Get(namespace);
@@ -68,9 +68,21 @@ export declare class Watcher<T extends GenericClass> {
68
68
  * Get a unique ID for the watch based on the model and filters.
69
69
  * This is useful for caching the watch data or resource versions.
70
70
  *
71
- * @returns the watch ID
71
+ * @returns the watch CacheID
72
72
  */
73
- get id(): string;
73
+ getCacheID(): string;
74
+ /**
75
+ * Get the current resource version.
76
+ *
77
+ * @returns the current resource version
78
+ */
79
+ get resourceVersion(): string | undefined;
80
+ /**
81
+ * Set the current resource version.
82
+ *
83
+ * @param resourceVersion - the new resource version
84
+ */
85
+ set resourceVersion(resourceVersion: string | undefined);
74
86
  /**
75
87
  * Subscribe to watch events. This is an EventEmitter that emits the following events:
76
88
  *
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":";;AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAG3D,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,2BAA2B;IAC3B,aAAa,kBAAkB;IAC/B,kDAAkD;IAClD,UAAU,eAAe;IACzB,0BAA0B;IAC1B,SAAS,cAAc;IACvB,8BAA8B;IAC9B,OAAO,YAAY;IACnB,sBAAsB;IACtB,KAAK,UAAU;IACf,uBAAuB;IACvB,MAAM,WAAW;IACjB,mCAAmC;IACnC,IAAI,SAAS;IACb,2BAA2B;IAC3B,QAAQ,aAAa;IACrB,iCAAiC;IACjC,gBAAgB,qBAAqB;IACrC,wCAAwC;IACxC,oBAAoB,yBAAyB;IAC7C,qCAAqC;IACrC,iBAAiB,sBAAsB;CACxC;AAED,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG;IACrB,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+HAA+H;IAC/H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0GAA0G;IAC1G,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,iDAAiD;AACjD,qBAAa,OAAO,CAAC,CAAC,SAAS,YAAY;;IA6BzC;;;;;;;;;;;OAWG;gBACS,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAE,QAAa;IAiBzF;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IAK9C,gGAAgG;IACzF,KAAK;IAMZ;;;;;OAKG;IACH,IAAW,EAAE,WAYZ;IAED;;;;;;OAMG;IACH,IAAW,MAAM,IAAI,YAAY,CAEhC;CAyOF"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":";;AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAG3D,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,2BAA2B;IAC3B,aAAa,kBAAkB;IAC/B,kDAAkD;IAClD,UAAU,eAAe;IACzB,0BAA0B;IAC1B,SAAS,cAAc;IACvB,8BAA8B;IAC9B,OAAO,YAAY;IACnB,sBAAsB;IACtB,KAAK,UAAU;IACf,uBAAuB;IACvB,MAAM,WAAW;IACjB,mCAAmC;IACnC,IAAI,SAAS;IACb,2BAA2B;IAC3B,QAAQ,aAAa;IACrB,iCAAiC;IACjC,gBAAgB,qBAAqB;IACrC,wCAAwC;IACxC,oBAAoB,yBAAyB;IAC7C,qCAAqC;IACrC,iBAAiB,sBAAsB;CACxC;AAED,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG;IACrB,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+HAA+H;IAC/H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0GAA0G;IAC1G,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,iDAAiD;AACjD,qBAAa,OAAO,CAAC,CAAC,SAAS,YAAY;;IAyBzC;;;;;;;;;;;OAWG;gBACS,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAE,QAAa;IAiBzF;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IAK9C,gGAAgG;IACzF,KAAK;IAMZ;;;;;OAKG;IACI,UAAU;IAWjB;;;;OAIG;IACH,IAAW,eAAe,IASkB,MAAM,GAAG,SAAS,CAP7D;IAED;;;;OAIG;IACH,IAAW,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,EAE7D;IAED;;;;;;OAMG;IACH,IAAW,MAAM,IAAI,YAAY,CAEhC;CAoOF"}
@@ -56,9 +56,6 @@ class Watcher {
56
56
  #events = new events_1.EventEmitter();
57
57
  // Create a timer to resync the watch
58
58
  #resyncTimer;
59
- // Unique ID for the watch
60
- #id;
61
- #hashedID;
62
59
  // Track if a reconnect is pending
63
60
  #pendingReconnect = false;
64
61
  /**
@@ -105,18 +102,32 @@ class Watcher {
105
102
  * Get a unique ID for the watch based on the model and filters.
106
103
  * This is useful for caching the watch data or resource versions.
107
104
  *
108
- * @returns the watch ID
105
+ * @returns the watch CacheID
109
106
  */
110
- get id() {
111
- // The ID must exist at this point
112
- if (!this.#id) {
113
- throw new Error("watch not started");
114
- }
107
+ getCacheID() {
108
+ // Build the URL, we don't care about the server URL or resourceVersion
109
+ const url = (0, utils_1.pathBuilder)("https://ignore", this.#model, this.#filters, false);
115
110
  // Hash and truncate the ID to 10 characters, cache the result
116
- if (!this.#hashedID) {
117
- this.#hashedID = (0, crypto_1.createHash)("sha224").update(this.#id).digest("hex").substring(0, 10);
118
- }
119
- return this.#hashedID;
111
+ return (0, crypto_1.createHash)("sha224")
112
+ .update(url.pathname + url.search)
113
+ .digest("hex")
114
+ .substring(0, 10);
115
+ }
116
+ /**
117
+ * Get the current resource version.
118
+ *
119
+ * @returns the current resource version
120
+ */
121
+ get resourceVersion() {
122
+ return this.#watchCfg.resourceVersion;
123
+ }
124
+ /**
125
+ * Set the current resource version.
126
+ *
127
+ * @param resourceVersion - the new resource version
128
+ */
129
+ set resourceVersion(resourceVersion) {
130
+ this.#watchCfg.resourceVersion = resourceVersion;
120
131
  }
121
132
  /**
122
133
  * Subscribe to watch events. This is an EventEmitter that emits the following events:
@@ -137,10 +148,6 @@ class Watcher {
137
148
  // Build the path and query params for the resource, excluding the name
138
149
  const { opts, serverUrl } = await (0, utils_1.k8sCfg)("GET");
139
150
  const url = (0, utils_1.pathBuilder)(serverUrl, this.#model, this.#filters, true);
140
- // Set the watch ID if it does not exist (this does not change on reconnect)
141
- if (!this.#id) {
142
- this.#id = url.pathname + url.search;
143
- }
144
151
  // Enable the watch query param
145
152
  url.searchParams.set("watch", "true");
146
153
  // If a name is specified, add it to the query params
@@ -109,17 +109,24 @@ const types_1 = require("./types");
109
109
  });
110
110
  watcher.start().catch(errMock);
111
111
  });
112
- (0, globals_1.it)("should return the cache id", done => {
113
- watcher
114
- .start()
115
- .then(() => {
116
- (0, globals_1.expect)(watcher.id).toEqual("d69b75a611");
117
- done();
118
- })
119
- .catch(errMock);
112
+ (0, globals_1.it)("should return the cache id", () => {
113
+ (0, globals_1.expect)(watcher.getCacheID()).toEqual("d69b75a611");
120
114
  });
121
- (0, globals_1.it)("should handle calling .id() before .start()", () => {
122
- (0, globals_1.expect)(() => watcher.id).toThrowError("watch not started");
115
+ (0, globals_1.it)("should use an updated resourceVersion", done => {
116
+ nock_1.default.cleanAll();
117
+ (0, nock_1.default)("http://jest-test:8080")
118
+ .get("/api/v1/pods")
119
+ .query({
120
+ watch: "true",
121
+ allowWatchBookmarks: "true",
122
+ resourceVersion: "35",
123
+ })
124
+ .reply(200);
125
+ // Update the resource version, could be combined with getCacheID to store the value
126
+ watcher.resourceVersion = "35";
127
+ setupAndStartWatcher(__1.WatchEvent.CONNECT, () => {
128
+ done();
129
+ });
123
130
  });
124
131
  (0, globals_1.it)("should handle the CONNECT event", done => {
125
132
  setupAndStartWatcher(__1.WatchEvent.CONNECT, () => {
@@ -150,6 +157,13 @@ const types_1 = require("./types");
150
157
  done();
151
158
  });
152
159
  });
160
+ (0, globals_1.it)("should handle the RESOURCE_VERSION event", done => {
161
+ setupAndStartWatcher(__1.WatchEvent.RESOURCE_VERSION, resourceVersion => {
162
+ (0, globals_1.expect)(watcher.resourceVersion).toEqual("2");
163
+ (0, globals_1.expect)(resourceVersion).toEqual("2");
164
+ done();
165
+ });
166
+ });
153
167
  (0, globals_1.it)("should handle the RECONNECT event", done => {
154
168
  nock_1.default.cleanAll();
155
169
  (0, nock_1.default)("http://jest-test:8080")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kubernetes-fluent-client",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "A @kubernetes/client-node fluent API wrapper that leverages K8s Server Side Apply",
5
5
  "bin": "./dist/cli.js",
6
6
  "main": "dist/index.js",
@@ -51,8 +51,8 @@
51
51
  "@types/byline": "4.2.36",
52
52
  "@types/readable-stream": "4.0.10",
53
53
  "@types/yargs": "17.0.32",
54
- "@typescript-eslint/eslint-plugin": "6.15.0",
55
- "@typescript-eslint/parser": "6.15.0",
54
+ "@typescript-eslint/eslint-plugin": "6.16.0",
55
+ "@typescript-eslint/parser": "6.16.0",
56
56
  "eslint-plugin-jsdoc": "46.9.1",
57
57
  "jest": "29.7.0",
58
58
  "nock": "13.4.0",
@@ -132,18 +132,27 @@ describe("Watcher", () => {
132
132
  watcher.start().catch(errMock);
133
133
  });
134
134
 
135
- it("should return the cache id", done => {
136
- watcher
137
- .start()
138
- .then(() => {
139
- expect(watcher.id).toEqual("d69b75a611");
140
- done();
141
- })
142
- .catch(errMock);
135
+ it("should return the cache id", () => {
136
+ expect(watcher.getCacheID()).toEqual("d69b75a611");
143
137
  });
144
138
 
145
- it("should handle calling .id() before .start()", () => {
146
- expect(() => watcher.id).toThrowError("watch not started");
139
+ it("should use an updated resourceVersion", done => {
140
+ nock.cleanAll();
141
+ nock("http://jest-test:8080")
142
+ .get("/api/v1/pods")
143
+ .query({
144
+ watch: "true",
145
+ allowWatchBookmarks: "true",
146
+ resourceVersion: "35",
147
+ })
148
+ .reply(200);
149
+
150
+ // Update the resource version, could be combined with getCacheID to store the value
151
+ watcher.resourceVersion = "35";
152
+
153
+ setupAndStartWatcher(WatchEvent.CONNECT, () => {
154
+ done();
155
+ });
147
156
  });
148
157
 
149
158
  it("should handle the CONNECT event", done => {
@@ -182,6 +191,14 @@ describe("Watcher", () => {
182
191
  });
183
192
  });
184
193
 
194
+ it("should handle the RESOURCE_VERSION event", done => {
195
+ setupAndStartWatcher(WatchEvent.RESOURCE_VERSION, resourceVersion => {
196
+ expect(watcher.resourceVersion).toEqual("2");
197
+ expect(resourceVersion).toEqual("2");
198
+ done();
199
+ });
200
+ });
201
+
185
202
  it("should handle the RECONNECT event", done => {
186
203
  nock.cleanAll();
187
204
  nock("http://jest-test:8080")
@@ -72,10 +72,6 @@ export class Watcher<T extends GenericClass> {
72
72
  // Create a timer to resync the watch
73
73
  #resyncTimer?: NodeJS.Timeout;
74
74
 
75
- // Unique ID for the watch
76
- #id?: string;
77
- #hashedID?: string;
78
-
79
75
  // Track if a reconnect is pending
80
76
  #pendingReconnect = false;
81
77
 
@@ -129,20 +125,35 @@ export class Watcher<T extends GenericClass> {
129
125
  * Get a unique ID for the watch based on the model and filters.
130
126
  * This is useful for caching the watch data or resource versions.
131
127
  *
132
- * @returns the watch ID
128
+ * @returns the watch CacheID
133
129
  */
134
- public get id() {
135
- // The ID must exist at this point
136
- if (!this.#id) {
137
- throw new Error("watch not started");
138
- }
130
+ public getCacheID() {
131
+ // Build the URL, we don't care about the server URL or resourceVersion
132
+ const url = pathBuilder("https://ignore", this.#model, this.#filters, false);
139
133
 
140
134
  // Hash and truncate the ID to 10 characters, cache the result
141
- if (!this.#hashedID) {
142
- this.#hashedID = createHash("sha224").update(this.#id).digest("hex").substring(0, 10);
143
- }
135
+ return createHash("sha224")
136
+ .update(url.pathname + url.search)
137
+ .digest("hex")
138
+ .substring(0, 10);
139
+ }
140
+
141
+ /**
142
+ * Get the current resource version.
143
+ *
144
+ * @returns the current resource version
145
+ */
146
+ public get resourceVersion() {
147
+ return this.#watchCfg.resourceVersion;
148
+ }
144
149
 
145
- return this.#hashedID;
150
+ /**
151
+ * Set the current resource version.
152
+ *
153
+ * @param resourceVersion - the new resource version
154
+ */
155
+ public set resourceVersion(resourceVersion: string | undefined) {
156
+ this.#watchCfg.resourceVersion = resourceVersion;
146
157
  }
147
158
 
148
159
  /**
@@ -166,11 +177,6 @@ export class Watcher<T extends GenericClass> {
166
177
  const { opts, serverUrl } = await k8sCfg("GET");
167
178
  const url = pathBuilder(serverUrl, this.#model, this.#filters, true);
168
179
 
169
- // Set the watch ID if it does not exist (this does not change on reconnect)
170
- if (!this.#id) {
171
- this.#id = url.pathname + url.search;
172
- }
173
-
174
180
  // Enable the watch query param
175
181
  url.searchParams.set("watch", "true");
176
182