@backstage/backend-dev-utils 0.1.4 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @backstage/backend-dev-utils
2
2
 
3
+ ## 0.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 3a35172: Fix `EventEmitter` memory leak in the development utilities
8
+
3
9
  ## 0.1.4
4
10
 
5
11
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -1,57 +1,41 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var __accessCheck$1 = (obj, member, msg) => {
6
- if (!member.has(obj))
7
- throw TypeError("Cannot " + msg);
8
- };
9
- var __privateGet$1 = (obj, member, getter) => {
10
- __accessCheck$1(obj, member, "read from private field");
11
- return getter ? getter.call(obj) : member.get(obj);
12
- };
13
- var __privateAdd$1 = (obj, member, value) => {
14
- if (member.has(obj))
15
- throw TypeError("Cannot add the same private member more than once");
16
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
17
- };
18
- var __privateSet$1 = (obj, member, value, setter) => {
19
- __accessCheck$1(obj, member, "write to private field");
20
- setter ? setter.call(obj, value) : member.set(obj, value);
21
- return value;
22
- };
23
- var __privateWrapper = (obj, member, setter, getter) => ({
24
- set _(value) {
25
- __privateSet$1(obj, member, value, setter);
26
- },
27
- get _() {
28
- return __privateGet$1(obj, member, getter);
29
- }
30
- });
31
- var _messageId, _sendMessage;
32
3
  const requestType = "@backstage/cli/channel/request";
33
4
  const responseType = "@backstage/cli/channel/response";
34
5
  const IPC_TIMEOUT_MS = 5e3;
35
- const _BackstageIpcClient = class _BackstageIpcClient {
36
- constructor(sendMessage) {
37
- __privateAdd$1(this, _messageId, 0);
38
- __privateAdd$1(this, _sendMessage, void 0);
39
- __privateSet$1(this, _sendMessage, sendMessage);
40
- }
6
+ class BackstageIpcClient {
7
+ #messageId = 0;
8
+ #sendMessage;
9
+ #handlers = /* @__PURE__ */ new Map();
41
10
  /**
42
11
  * Creates a new client if we're in a child process with IPC and BACKSTAGE_CLI_CHANNEL is set.
43
12
  */
44
13
  static create() {
45
- var _a;
46
- const sendMessage = (_a = process.send) == null ? void 0 : _a.bind(process);
47
- return sendMessage && process.env.BACKSTAGE_CLI_CHANNEL ? new _BackstageIpcClient(sendMessage) : void 0;
14
+ const sendMessage = process.send?.bind(process);
15
+ const client = sendMessage && process.env.BACKSTAGE_CLI_CHANNEL ? new BackstageIpcClient(sendMessage) : void 0;
16
+ if (client) {
17
+ process.on(
18
+ "message",
19
+ (message, _sendHandle) => client.handleMessage(message, _sendHandle)
20
+ );
21
+ }
22
+ return client;
23
+ }
24
+ constructor(sendMessage) {
25
+ this.#sendMessage = sendMessage;
26
+ }
27
+ handleMessage(message, _sendHandle) {
28
+ const isResponse = (msg) => msg?.type === responseType;
29
+ if (isResponse(message)) {
30
+ this.#handlers.get(message.id)?.(message);
31
+ }
48
32
  }
49
33
  /**
50
34
  * Send a request to the parent process and wait for a response.
51
35
  */
52
36
  async request(method, body) {
53
37
  return new Promise((resolve, reject) => {
54
- const id = __privateWrapper(this, _messageId)._++;
38
+ const id = this.#messageId++;
55
39
  const request = {
56
40
  type: requestType,
57
41
  id,
@@ -59,16 +43,10 @@ const _BackstageIpcClient = class _BackstageIpcClient {
59
43
  body
60
44
  };
61
45
  let timeout = void 0;
62
- const messageHandler = (response) => {
63
- if ((response == null ? void 0 : response.type) !== responseType) {
64
- return;
65
- }
66
- if (response.id !== id) {
67
- return;
68
- }
46
+ const responseHandler = (response) => {
69
47
  clearTimeout(timeout);
70
48
  timeout = void 0;
71
- process.removeListener("message", messageHandler);
49
+ this.#handlers.delete(id);
72
50
  if ("error" in response) {
73
51
  const error = new Error(response.error.message);
74
52
  if (response.error.name) {
@@ -81,47 +59,22 @@ const _BackstageIpcClient = class _BackstageIpcClient {
81
59
  };
82
60
  timeout = setTimeout(() => {
83
61
  reject(new Error(`IPC request '${method}' with ID ${id} timed out`));
84
- process.removeListener("message", messageHandler);
62
+ this.#handlers.delete(id);
85
63
  }, IPC_TIMEOUT_MS);
86
64
  timeout.unref();
87
- process.addListener("message", messageHandler);
88
- __privateGet$1(this, _sendMessage).call(this, request, (e) => {
65
+ this.#handlers.set(id, responseHandler);
66
+ this.#sendMessage(request, (e) => {
89
67
  if (e) {
90
68
  reject(e);
91
69
  }
92
70
  });
93
71
  });
94
72
  }
95
- };
96
- _messageId = new WeakMap();
97
- _sendMessage = new WeakMap();
98
- let BackstageIpcClient = _BackstageIpcClient;
73
+ }
99
74
  const ipcClient = BackstageIpcClient.create();
100
75
 
101
- var __accessCheck = (obj, member, msg) => {
102
- if (!member.has(obj))
103
- throw TypeError("Cannot " + msg);
104
- };
105
- var __privateGet = (obj, member, getter) => {
106
- __accessCheck(obj, member, "read from private field");
107
- return getter ? getter.call(obj) : member.get(obj);
108
- };
109
- var __privateAdd = (obj, member, value) => {
110
- if (member.has(obj))
111
- throw TypeError("Cannot add the same private member more than once");
112
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
113
- };
114
- var __privateSet = (obj, member, value, setter) => {
115
- __accessCheck(obj, member, "write to private field");
116
- setter ? setter.call(obj, value) : member.set(obj, value);
117
- return value;
118
- };
119
- var _instance, _client;
120
- const _DevDataStore = class _DevDataStore {
121
- constructor(client) {
122
- __privateAdd(this, _client, void 0);
123
- __privateSet(this, _client, client);
124
- }
76
+ class DevDataStore {
77
+ static #instance;
125
78
  /**
126
79
  * Tries to acquire a DevDataStore instance. This will only succeed when the backend
127
80
  * process is being run through the `@backstage/cli` in development mode.
@@ -130,16 +83,20 @@ const _DevDataStore = class _DevDataStore {
130
83
  */
131
84
  static get() {
132
85
  if (ipcClient) {
133
- if (!__privateGet(this, _instance)) {
134
- __privateSet(this, _instance, new _DevDataStore(ipcClient));
86
+ if (!this.#instance) {
87
+ this.#instance = new DevDataStore(ipcClient);
135
88
  }
136
- return __privateGet(this, _instance);
89
+ return this.#instance;
137
90
  }
138
91
  return void 0;
139
92
  }
140
93
  /** @internal */
141
94
  static forTest(client) {
142
- return new _DevDataStore(client);
95
+ return new DevDataStore(client);
96
+ }
97
+ #client;
98
+ constructor(client) {
99
+ this.#client = client;
143
100
  }
144
101
  /**
145
102
  * Save data to the data store.
@@ -149,7 +106,7 @@ const _DevDataStore = class _DevDataStore {
149
106
  * @returns A promise that resolves to a result object that indicates whether the data was saved.
150
107
  */
151
108
  async save(key, data) {
152
- return __privateGet(this, _client).request(
109
+ return this.#client.request(
153
110
  "DevDataStore.save",
154
111
  { key, data }
155
112
  );
@@ -161,17 +118,13 @@ const _DevDataStore = class _DevDataStore {
161
118
  * @returns A promise that resolves to a result object that indicates whether the data was loaded, as well as the data.
162
119
  */
163
120
  async load(key) {
164
- const result = await __privateGet(this, _client).request(
121
+ const result = await this.#client.request(
165
122
  "DevDataStore.load",
166
123
  { key }
167
124
  );
168
125
  return result;
169
126
  }
170
- };
171
- _instance = new WeakMap();
172
- _client = new WeakMap();
173
- __privateAdd(_DevDataStore, _instance, void 0);
174
- let DevDataStore = _DevDataStore;
127
+ }
175
128
 
176
129
  exports.DevDataStore = DevDataStore;
177
130
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/ipcClient.ts","../src/DevDataStore.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ntype SendMessage = Exclude<typeof process.send, undefined>;\n\ninterface Request {\n id: number;\n method: string;\n body: unknown;\n type: string;\n}\n\ntype Response =\n | {\n type: string;\n id: number;\n body: unknown;\n }\n | {\n type: string;\n id: number;\n error: Error;\n };\n\nconst requestType = '@backstage/cli/channel/request';\nconst responseType = '@backstage/cli/channel/response';\n\nconst IPC_TIMEOUT_MS = 5000;\n\n/**\n * The client side of an IPC communication channel.\n *\n * @internal\n */\nexport class BackstageIpcClient {\n #messageId = 0;\n #sendMessage: SendMessage;\n\n /**\n * Creates a new client if we're in a child process with IPC and BACKSTAGE_CLI_CHANNEL is set.\n */\n static create(): BackstageIpcClient | undefined {\n const sendMessage = process.send?.bind(process);\n return sendMessage && process.env.BACKSTAGE_CLI_CHANNEL\n ? new BackstageIpcClient(sendMessage)\n : undefined;\n }\n\n constructor(sendMessage: SendMessage) {\n this.#sendMessage = sendMessage;\n }\n\n /**\n * Send a request to the parent process and wait for a response.\n */\n async request<TRequestBody, TResponseBody>(\n method: string,\n body: TRequestBody,\n ): Promise<TResponseBody> {\n return new Promise((resolve, reject) => {\n const id = this.#messageId++;\n\n const request: Request = {\n type: requestType,\n id,\n method,\n body,\n };\n\n let timeout: NodeJS.Timeout | undefined = undefined;\n\n const messageHandler = (response: Response) => {\n if (response?.type !== responseType) {\n return;\n }\n if (response.id !== id) {\n return;\n }\n\n clearTimeout(timeout);\n timeout = undefined;\n process.removeListener('message', messageHandler);\n\n if ('error' in response) {\n const error = new Error(response.error.message);\n if (response.error.name) {\n error.name = response.error.name;\n }\n reject(error);\n } else {\n resolve(response.body as TResponseBody);\n }\n };\n\n timeout = setTimeout(() => {\n reject(new Error(`IPC request '${method}' with ID ${id} timed out`));\n process.removeListener('message', messageHandler);\n }, IPC_TIMEOUT_MS);\n timeout.unref();\n\n process.addListener('message', messageHandler as () => void);\n\n this.#sendMessage(request, (e: Error) => {\n if (e) {\n reject(e);\n }\n });\n });\n }\n}\n\nexport const ipcClient = BackstageIpcClient.create();\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BackstageIpcClient, ipcClient } from './ipcClient';\n\ninterface SaveRequest {\n key: string;\n data: unknown;\n}\n\ninterface SaveResponse {\n saved: boolean;\n}\n\ninterface LoadRequest {\n key: string;\n}\n\ninterface LoadResponse {\n loaded: boolean;\n data: unknown;\n}\n\n/**\n * A data store that can be used to store temporary data during development.\n *\n * @public\n */\nexport class DevDataStore {\n static #instance?: DevDataStore;\n\n /**\n * Tries to acquire a DevDataStore instance. This will only succeed when the backend\n * process is being run through the `@backstage/cli` in development mode.\n *\n * @returns A DevDataStore instance, or undefined if not available.\n */\n static get(): DevDataStore | undefined {\n if (ipcClient) {\n if (!this.#instance) {\n this.#instance = new DevDataStore(ipcClient);\n }\n return this.#instance;\n }\n return undefined;\n }\n\n /** @internal */\n static forTest(client: Pick<BackstageIpcClient, 'request'>): DevDataStore {\n return new DevDataStore(client as BackstageIpcClient);\n }\n\n #client: BackstageIpcClient;\n\n private constructor(client: BackstageIpcClient) {\n this.#client = client;\n }\n\n /**\n * Save data to the data store.\n *\n * @param key - The key used to identify the data.\n * @param data - The data to save. The data will be serialized using advanced IPC serialization.\n * @returns A promise that resolves to a result object that indicates whether the data was saved.\n */\n async save<T>(key: string, data: T): Promise<{ saved: boolean }> {\n return this.#client.request<SaveRequest, SaveResponse>(\n 'DevDataStore.save',\n { key, data },\n );\n }\n\n /**\n * Loads data from the data store.\n *\n * @param key - The key used to identify the data.\n * @returns A promise that resolves to a result object that indicates whether the data was loaded, as well as the data.\n */\n async load<T>(key: string): Promise<{ loaded: boolean; data: T }> {\n const result = await this.#client.request<LoadRequest, LoadResponse>(\n 'DevDataStore.load',\n { key },\n );\n return result as { loaded: boolean; data: T };\n }\n}\n"],"names":["__privateAdd","__privateSet","__privateGet"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/ipcClient.ts","../src/DevDataStore.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ntype SendMessage = Exclude<typeof process.send, undefined>;\n\ninterface Request {\n id: number;\n method: string;\n body: unknown;\n type: string;\n}\n\ntype Response =\n | {\n type: string;\n id: number;\n body: unknown;\n }\n | {\n type: string;\n id: number;\n error: Error;\n };\n\ntype ResponseHandler = (response: Response) => void;\n\nconst requestType = '@backstage/cli/channel/request';\nconst responseType = '@backstage/cli/channel/response';\n\nconst IPC_TIMEOUT_MS = 5000;\n\n/**\n * The client side of an IPC communication channel.\n *\n * @internal\n */\nexport class BackstageIpcClient {\n #messageId = 0;\n #sendMessage: SendMessage;\n #handlers: Map<number, ResponseHandler> = new Map();\n\n /**\n * Creates a new client if we're in a child process with IPC and BACKSTAGE_CLI_CHANNEL is set.\n */\n static create(): BackstageIpcClient | undefined {\n const sendMessage = process.send?.bind(process);\n const client =\n sendMessage && process.env.BACKSTAGE_CLI_CHANNEL\n ? new BackstageIpcClient(sendMessage)\n : undefined;\n\n if (client) {\n process.on('message', (message, _sendHandle) =>\n client.handleMessage(message, _sendHandle),\n );\n }\n\n return client;\n }\n\n constructor(sendMessage: SendMessage) {\n this.#sendMessage = sendMessage;\n }\n\n private handleMessage(message: unknown, _sendHandle: unknown) {\n const isResponse = (msg: unknown): msg is Response =>\n (msg as Response)?.type === responseType;\n\n if (isResponse(message)) {\n this.#handlers.get(message.id)?.(message);\n }\n }\n\n /**\n * Send a request to the parent process and wait for a response.\n */\n async request<TRequestBody, TResponseBody>(\n method: string,\n body: TRequestBody,\n ): Promise<TResponseBody> {\n return new Promise((resolve, reject) => {\n const id = this.#messageId++;\n\n const request: Request = {\n type: requestType,\n id,\n method,\n body,\n };\n\n let timeout: NodeJS.Timeout | undefined = undefined;\n\n const responseHandler: ResponseHandler = (response: Response) => {\n clearTimeout(timeout);\n timeout = undefined;\n this.#handlers.delete(id);\n\n if ('error' in response) {\n const error = new Error(response.error.message);\n if (response.error.name) {\n error.name = response.error.name;\n }\n reject(error);\n } else {\n resolve(response.body as TResponseBody);\n }\n };\n\n timeout = setTimeout(() => {\n reject(new Error(`IPC request '${method}' with ID ${id} timed out`));\n this.#handlers.delete(id);\n }, IPC_TIMEOUT_MS);\n timeout.unref();\n\n this.#handlers.set(id, responseHandler);\n this.#sendMessage(request, (e: Error) => {\n if (e) {\n reject(e);\n }\n });\n });\n }\n}\n\nexport const ipcClient = BackstageIpcClient.create();\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BackstageIpcClient, ipcClient } from './ipcClient';\n\ninterface SaveRequest {\n key: string;\n data: unknown;\n}\n\ninterface SaveResponse {\n saved: boolean;\n}\n\ninterface LoadRequest {\n key: string;\n}\n\ninterface LoadResponse {\n loaded: boolean;\n data: unknown;\n}\n\n/**\n * A data store that can be used to store temporary data during development.\n *\n * @public\n */\nexport class DevDataStore {\n static #instance?: DevDataStore;\n\n /**\n * Tries to acquire a DevDataStore instance. This will only succeed when the backend\n * process is being run through the `@backstage/cli` in development mode.\n *\n * @returns A DevDataStore instance, or undefined if not available.\n */\n static get(): DevDataStore | undefined {\n if (ipcClient) {\n if (!this.#instance) {\n this.#instance = new DevDataStore(ipcClient);\n }\n return this.#instance;\n }\n return undefined;\n }\n\n /** @internal */\n static forTest(client: Pick<BackstageIpcClient, 'request'>): DevDataStore {\n return new DevDataStore(client as BackstageIpcClient);\n }\n\n #client: BackstageIpcClient;\n\n private constructor(client: BackstageIpcClient) {\n this.#client = client;\n }\n\n /**\n * Save data to the data store.\n *\n * @param key - The key used to identify the data.\n * @param data - The data to save. The data will be serialized using advanced IPC serialization.\n * @returns A promise that resolves to a result object that indicates whether the data was saved.\n */\n async save<T>(key: string, data: T): Promise<{ saved: boolean }> {\n return this.#client.request<SaveRequest, SaveResponse>(\n 'DevDataStore.save',\n { key, data },\n );\n }\n\n /**\n * Loads data from the data store.\n *\n * @param key - The key used to identify the data.\n * @returns A promise that resolves to a result object that indicates whether the data was loaded, as well as the data.\n */\n async load<T>(key: string): Promise<{ loaded: boolean; data: T }> {\n const result = await this.#client.request<LoadRequest, LoadResponse>(\n 'DevDataStore.load',\n { key },\n );\n return result as { loaded: boolean; data: T };\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,36 +1,36 @@
1
1
  {
2
2
  "name": "@backstage/backend-dev-utils",
3
- "version": "0.1.4",
4
- "main": "dist/index.cjs.js",
5
- "types": "dist/index.d.ts",
6
- "license": "Apache-2.0",
3
+ "version": "0.1.5",
4
+ "backstage": {
5
+ "role": "node-library"
6
+ },
7
7
  "publishConfig": {
8
8
  "access": "public",
9
9
  "main": "dist/index.cjs.js",
10
10
  "types": "dist/index.d.ts"
11
11
  },
12
- "backstage": {
13
- "role": "node-library"
14
- },
15
12
  "homepage": "https://backstage.io",
16
13
  "repository": {
17
14
  "type": "git",
18
15
  "url": "https://github.com/backstage/backstage",
19
16
  "directory": "packages/backend-dev-utils"
20
17
  },
18
+ "license": "Apache-2.0",
19
+ "main": "dist/index.cjs.js",
20
+ "types": "dist/index.d.ts",
21
+ "files": [
22
+ "dist"
23
+ ],
21
24
  "scripts": {
22
- "start": "backstage-cli package start",
23
25
  "build": "backstage-cli package build",
24
- "lint": "backstage-cli package lint",
25
- "test": "backstage-cli package test",
26
26
  "clean": "backstage-cli package clean",
27
+ "lint": "backstage-cli package lint",
27
28
  "prepack": "backstage-cli package prepack",
28
- "postpack": "backstage-cli package postpack"
29
+ "postpack": "backstage-cli package postpack",
30
+ "start": "backstage-cli package start",
31
+ "test": "backstage-cli package test"
29
32
  },
30
33
  "devDependencies": {
31
- "@backstage/cli": "^0.25.2"
32
- },
33
- "files": [
34
- "dist"
35
- ]
34
+ "@backstage/cli": "^0.27.0"
35
+ }
36
36
  }