@shellicar/build-azure-local-settings 1.0.0 → 1.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +107 -11
  3. package/dist/cjs/chunks/StartHostAction-PUOHB3U4.cjs +344 -0
  4. package/dist/cjs/chunks/StartHostAction-PUOHB3U4.cjs.map +1 -0
  5. package/dist/cjs/chunks/chunk-KAEGRUUU.cjs +213 -0
  6. package/dist/cjs/chunks/chunk-KAEGRUUU.cjs.map +1 -0
  7. package/dist/cjs/chunks/chunk-X6BO6XFB.cjs +7 -0
  8. package/dist/cjs/chunks/chunk-X6BO6XFB.cjs.map +1 -0
  9. package/dist/cjs/esbuild.cjs +8 -1
  10. package/dist/cjs/esbuild.cjs.map +1 -1
  11. package/dist/cjs/index.cjs +11 -1
  12. package/dist/cjs/index.cjs.map +1 -1
  13. package/dist/cjs/runtime.cjs +14 -1
  14. package/dist/cjs/runtime.cjs.map +1 -1
  15. package/dist/esm/chunks/StartHostAction-X2BBLBUB.js +344 -0
  16. package/dist/esm/chunks/StartHostAction-X2BBLBUB.js.map +1 -0
  17. package/dist/esm/chunks/chunk-GOUAOFCH.js +7 -0
  18. package/dist/esm/chunks/chunk-GOUAOFCH.js.map +1 -0
  19. package/dist/esm/chunks/chunk-S524MWOE.js +213 -0
  20. package/dist/esm/chunks/chunk-S524MWOE.js.map +1 -0
  21. package/dist/esm/cjs-shim.js +8 -1
  22. package/dist/esm/cjs-shim.js.map +1 -1
  23. package/dist/esm/esbuild.js +8 -1
  24. package/dist/esm/esbuild.js.map +1 -1
  25. package/dist/esm/index.js +11 -1
  26. package/dist/esm/index.js.map +1 -1
  27. package/dist/esm/runtime.js +14 -1
  28. package/dist/esm/runtime.js.map +1 -1
  29. package/package.json +14 -15
  30. package/dist/cjs/StartHostAction-XMDH7T6E.cjs +0 -1
  31. package/dist/cjs/StartHostAction-XMDH7T6E.cjs.map +0 -1
  32. package/dist/cjs/chunk-PK6SKIKE.cjs +0 -1
  33. package/dist/cjs/chunk-PK6SKIKE.cjs.map +0 -1
  34. package/dist/cjs/chunk-X2PGEG2F.cjs +0 -1
  35. package/dist/cjs/chunk-X2PGEG2F.cjs.map +0 -1
  36. package/dist/esm/StartHostAction-IGJTX6EF.js +0 -1
  37. package/dist/esm/StartHostAction-IGJTX6EF.js.map +0 -1
  38. package/dist/esm/chunk-5M5J2O2I.js +0 -1
  39. package/dist/esm/chunk-5M5J2O2I.js.map +0 -1
  40. package/dist/esm/chunk-7QVYU63E.js +0 -1
  41. package/dist/esm/chunk-7QVYU63E.js.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.1] - 2026-04-15
9
+
10
+ ### Changed
11
+
12
+ - Updated dependencies to latest versions
13
+
14
+ ## [1.0.0] - 2026-03-11
15
+
16
+ ### Added
17
+
18
+ - Initial release.
19
+
20
+ [1.0.1]: https://github.com/shellicar/ecosystem/releases/tag/build-azure-local-settings@1.0.1
21
+ [1.0.0]: https://github.com/shellicar/ecosystem/releases/tag/1.0.0
package/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # @shellicar/build-azure-local-settings
2
2
 
3
- > Build plugin that loads Azure `local.settings.json` with Key Vault reference resolution for non-Azure-Functions apps.
3
+ [![npm package](https://img.shields.io/npm/v/@shellicar/build-azure-local-settings.svg)](https://npmjs.com/package/@shellicar/build-azure-local-settings)
4
+ [![build status](https://github.com/shellicar/ecosystem/actions/workflows/node.js.yml/badge.svg)](https://github.com/shellicar/ecosystem/actions/workflows/node.js.yml)
5
+
6
+ Build plugin that loads Azure `local.settings.json` with [Key Vault reference](https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references) resolution for non-Azure-Functions apps.
7
+
8
+ - **Loads `local.settings.json`** - Reads values and sets them as `process.env` variables before your app starts
9
+ - **Resolves Key Vault references** - Fetches secrets from Azure Key Vault using `DefaultAzureCredential` (e.g. Azure CLI)
10
+ - **Local development only** - Controlled via the `loadLocalSettings` option, typically tied to watch/dev mode
4
11
 
5
12
  ## Installation & Quick Start
6
13
 
@@ -12,27 +19,45 @@ npm i --save-dev @shellicar/build-azure-local-settings
12
19
  pnpm add -D @shellicar/build-azure-local-settings
13
20
  ```
14
21
 
22
+ ### esbuild
23
+
15
24
  ```ts
16
- // tsup.config.ts
25
+ // build.ts
17
26
  import plugin from '@shellicar/build-azure-local-settings/esbuild';
18
- import { defineConfig } from 'tsup';
27
+ import esbuild from 'esbuild';
19
28
 
20
- export default defineConfig({
21
- esbuildPlugins: [
29
+ const watch = process.argv.includes('--watch');
30
+
31
+ const ctx = await esbuild.context({
32
+ outdir: 'dist',
33
+ bundle: true,
34
+ platform: 'node',
35
+ format: 'esm',
36
+ plugins: [
22
37
  plugin({
23
38
  mainModule: './src/main.ts',
39
+ loadLocalSettings: watch,
24
40
  }),
25
41
  ],
26
42
  });
43
+
44
+ if (watch) {
45
+ await ctx.watch();
46
+ } else {
47
+ await ctx.rebuild();
48
+ ctx.dispose();
49
+ }
27
50
  ```
28
51
 
52
+ ### tsup
53
+
29
54
  ```ts
30
- // build.ts (esbuild)
55
+ // tsup.config.ts
31
56
  import plugin from '@shellicar/build-azure-local-settings/esbuild';
57
+ import { defineConfig } from 'tsup';
32
58
 
33
- await build({
34
- bundle: true,
35
- plugins: [
59
+ export default defineConfig({
60
+ esbuildPlugins: [
36
61
  plugin({
37
62
  mainModule: './src/main.ts',
38
63
  }),
@@ -40,6 +65,77 @@ await build({
40
65
  });
41
66
  ```
42
67
 
43
- ## Documentation
68
+ ## How It Works
69
+
70
+ The plugin generates a virtual entry point that:
71
+
72
+ 1. Reads `local.settings.json` from the working directory
73
+ 2. Resolves any [Key Vault references](https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references) to their secret values
74
+ 3. Sets the resolved values as `process.env` variables
75
+ 4. Imports and runs your main module
76
+
77
+ Your application code accesses the values through `process.env` as normal:
78
+
79
+ ```ts
80
+ // src/main.ts
81
+ export default async () => {
82
+ console.log('Greeting:', process.env.GREETING_MESSAGE);
83
+ };
84
+ ```
85
+
86
+ See [examples](../../examples/build-azure-local-settings) for full working implementations.
87
+
88
+ <!-- BEGIN_ECOSYSTEM -->
89
+
90
+ ## @shellicar TypeScript Ecosystem
91
+
92
+ ### Core Libraries
93
+
94
+ - [`@shellicar/core-config`](https://github.com/shellicar/ecosystem/tree/main/packages/core-config) - A library for securely handling sensitive configuration values like connection strings, URLs, and secrets.
95
+ - [`@shellicar/core-di`](https://github.com/shellicar/ecosystem/tree/main/packages/core-di) - A basic dependency injection library.
96
+
97
+ ### Reference Architectures
98
+
99
+ - [`@shellicar/reference-foundation`](https://github.com/shellicar/reference-foundation) - A comprehensive starter repository. Illustrates individual concepts.
100
+ - [`@shellicar/reference-enterprise`](https://github.com/shellicar/reference-enterprise) - A comprehensive starter repository. Can be used as the basis for creating a new Azure application workload.
101
+
102
+ ### Build Tools
103
+
104
+ - [`@shellicar/build-azure-local-settings`](https://github.com/shellicar/ecosystem/tree/main/packages/build-azure-local-settings) - Build plugin that loads Azure `local.settings.json` with Key Vault reference resolution.
105
+ - [`@shellicar/build-clean`](https://github.com/shellicar/ecosystem/tree/main/packages/build-clean) - Build plugin that automatically cleans unused files from output directories.
106
+ - [`@shellicar/build-version`](https://github.com/shellicar/ecosystem/tree/main/packages/build-version) - Build plugin that calculates and exposes version information through a virtual module import.
107
+ - [`@shellicar/build-graphql`](https://github.com/shellicar/ecosystem/tree/main/packages/build-graphql) - Build plugin that loads GraphQL files and makes them available through a virtual module import.
108
+ - [`@shellicar/graphql-codegen-treeshake`](https://github.com/shellicar/ecosystem/tree/main/packages/graphql-codegen-treeshake) - A graphql-codegen preset that tree-shakes unused types from TypeScript output.
109
+
110
+ ### Framework
111
+
112
+ - [`@shellicar/svelte-adapter-azure-functions`](https://github.com/shellicar/ecosystem/tree/main/packages/svelte-adapter-azure-functions) - A [SvelteKit adapter](https://kit.svelte.dev/docs/adapters) that builds your app into an Azure Function.
113
+ - [`@shellicar/cosmos-query-builder`](https://github.com/shellicar/ecosystem/tree/main/packages/cosmos-query-builder) - Helper class for type safe advanced queries for Cosmos DB (Sql Core).
114
+ - [`@shellicar/ui-shadcn`](https://github.com/shellicar/ui-shadcn) - Shared Svelte 5 component library built on shadcn-svelte with Tailwind CSS v4 theming.
115
+
116
+ ### Logging & Monitoring
117
+
118
+ - [`@shellicar/winston-azure-application-insights`](https://github.com/shellicar/ecosystem/tree/main/packages/winston-azure-application-insights) - An [Azure Application Insights](https://azure.microsoft.com/en-us/services/application-insights/) transport for [Winston](https://github.com/winstonjs/winston) logging library.
119
+ - [`@shellicar/pino-applicationinsights-transport`](https://github.com/shellicar/pino-applicationinsights-transport) - [Azure Application Insights](https://azure.microsoft.com/en-us/services/application-insights) transport for [pino](https://github.com/pinojs/pino)
120
+
121
+ <!-- END_ECOSYSTEM -->
122
+
123
+ ## Motivation
124
+
125
+ Azure Functions automatically loads `local.settings.json` and resolves Key Vault references during local development. Azure App Services and other Node.js apps don't have this capability.
126
+
127
+ This plugin brings that same behaviour to non-Functions apps, so you can:
128
+
129
+ - Use the same `local.settings.json` config approach across Functions and App Services
130
+ - Commit Key Vault references instead of secrets
131
+ - Set up local dev with just Azure CLI access to Key Vault
132
+
133
+ ## Options
134
+
135
+ See [types.ts](./src/types.ts) for detailed options documentation.
136
+
137
+ ## Credits
44
138
 
45
- For full documentation, visit [the GitHub repository](https://github.com/shellicar/build-azure-local-settings).
139
+ - [Azure Functions Core Tools](https://github.com/Azure/azure-functions-core-tools) - Key Vault reference resolution logic ported from the .NET source
140
+ - [esbuild](https://github.com/evanw/esbuild)
141
+ - [Azure Key Vault](https://azure.microsoft.com/en-us/products/key-vault)
@@ -0,0 +1,344 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3;
2
+
3
+ var _chunkX6BO6XFBcjs = require('./chunk-X6BO6XFB.cjs');
4
+
5
+ // src/local-settings/StartHostAction.ts
6
+ var _nodeprocess = require('node:process');
7
+
8
+ // src/local-settings/KeyVaultReferencesManager.ts
9
+ var _identity = require('@azure/identity');
10
+ var _keyvaultsecrets = require('@azure/keyvault-secrets');
11
+
12
+ // src/local-settings/KeyVaultIdentifier.ts
13
+ var KeyVaultIdentifier = (_class = class _KeyVaultIdentifier {
14
+ static {
15
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "KeyVaultIdentifier");
16
+ }
17
+ static __initStatic() {this.SecretsCollection = "secrets"}
18
+ static __initStatic2() {this.KeysCollection = "keys"}
19
+ static __initStatic3() {this.CertificatesCollection = "certificates"}
20
+
21
+
22
+
23
+
24
+
25
+ constructor() {
26
+ this.id = new URL("http://localhost");
27
+ this.vaultUri = new URL("http://localhost");
28
+ this.name = "";
29
+ this.collection = "";
30
+ this.version = null;
31
+ }
32
+ static parse(id) {
33
+ if (id === null || id === void 0) {
34
+ throw new Error("id cannot be null");
35
+ }
36
+ const result = _KeyVaultIdentifier.tryParse(id);
37
+ if (!result.success) {
38
+ throw new Error(`Invalid ObjectIdentifier: ${id}. Bad number of segments: ${id.pathname.split("/").length}`);
39
+ }
40
+ return result.identifier;
41
+ }
42
+ static parseWithCollection(id, collection) {
43
+ const identifier = _KeyVaultIdentifier.parse(id);
44
+ if (identifier.collection.toLowerCase() !== collection.toLowerCase()) {
45
+ throw new Error(`Invalid ObjectIdentifier: ${id}. segment [1] should be '${collection}/', found '${identifier.collection}'`);
46
+ }
47
+ return identifier;
48
+ }
49
+ static tryParse(id) {
50
+ if (id === null) {
51
+ return { success: false };
52
+ }
53
+ const segments = id.pathname.split("/");
54
+ if (segments.length !== 3 && segments.length !== 4) {
55
+ return { success: false };
56
+ }
57
+ const identifier = new _KeyVaultIdentifier();
58
+ identifier.id = id;
59
+ identifier.vaultUri = new URL(`${id.protocol}//${id.host}`);
60
+ identifier.collection = segments[1].replace(/\/$/, "");
61
+ identifier.name = segments[2].replace(/\/$/, "");
62
+ identifier.version = segments.length === 4 ? segments[3].replace(/\/$/, "") : null;
63
+ return { success: true, identifier };
64
+ }
65
+ }, _class.__initStatic(), _class.__initStatic2(), _class.__initStatic3(), _class);
66
+
67
+ // src/local-settings/KeyVaultSecretIdentifier.ts
68
+ var KeyVaultSecretIdentifier = class {
69
+ static {
70
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "KeyVaultSecretIdentifier");
71
+ }
72
+ /**
73
+ * Gets the source URL passed to KeyVaultSecretIdentifier constructor.
74
+ */
75
+
76
+ /**
77
+ * Gets the URL of the Key Vault.
78
+ */
79
+
80
+ /**
81
+ * Gets the name of the secret.
82
+ */
83
+
84
+ /**
85
+ * Gets the optional version of the secret.
86
+ */
87
+
88
+ /**
89
+ * Creates a new instance of the KeyVaultSecretIdentifier class.
90
+ * @param id The URL to a secret or deleted secret.
91
+ * @throws Error if id is not a valid Key Vault secret ID.
92
+ */
93
+ constructor(id) {
94
+ if (id === null || id === void 0) {
95
+ throw new Error("id cannot be null");
96
+ }
97
+ const result = KeyVaultIdentifier.tryParse(id);
98
+ if (result.success && result.identifier) {
99
+ this.sourceId = id;
100
+ this.vaultUri = result.identifier.vaultUri;
101
+ this.name = result.identifier.name;
102
+ this.version = result.identifier.version;
103
+ } else {
104
+ throw new Error(`${id} is not a valid secret ID`);
105
+ }
106
+ }
107
+ };
108
+
109
+ // src/local-settings/KeyVaultReferencesManager.ts
110
+ var KeyVaultReferencesManager = (_class2 = class _KeyVaultReferencesManager {constructor() { _class2.prototype.__init.call(this);_class2.prototype.__init2.call(this); }
111
+ static {
112
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "KeyVaultReferencesManager");
113
+ }
114
+ static __initStatic4() {this.VaultUriSuffix = "vault.azure.net"}
115
+ static __initStatic5() {this._basicKeyVaultReferenceRegex = /^@Microsoft\.KeyVault\((?<ReferenceString>.*)\)$/}
116
+ __init() {this._clients = /* @__PURE__ */ new Map()}
117
+ __init2() {this._credential = new (0, _identity.DefaultAzureCredential)()}
118
+ // CodeQL [SM05137] This is never deployed to production, only used in CLI context in a local dev environment.
119
+ async resolveKeyVaultReferences(settings) {
120
+ const keys = Object.keys(settings);
121
+ for (const key of keys) {
122
+ try {
123
+ const keyVaultValue = await this.getSecretValue(key, settings[key]);
124
+ if (keyVaultValue != null) {
125
+ settings[key] = keyVaultValue;
126
+ }
127
+ } catch (e) {
128
+ }
129
+ }
130
+ }
131
+ async getSecretValue(key, value) {
132
+ const result = this.parseSecret(key, value);
133
+ if (result != null) {
134
+ const client = this.getSecretClient(result.uri);
135
+ const secret = await client.getSecret(result.name, result.version ? { version: result.version } : void 0);
136
+ return secret.value;
137
+ }
138
+ return null;
139
+ }
140
+ parseSecret(key, value) {
141
+ if (value == null) {
142
+ return null;
143
+ }
144
+ const keyVaultReferenceMatch = _KeyVaultReferencesManager._basicKeyVaultReferenceRegex.exec(value);
145
+ if (_optionalChain([keyVaultReferenceMatch, 'optionalAccess', _ => _.groups])) {
146
+ const referenceString = keyVaultReferenceMatch.groups["ReferenceString"];
147
+ let result = null;
148
+ try {
149
+ if (referenceString != null) {
150
+ result = this.parseVaultReference(referenceString);
151
+ }
152
+ } catch (e2) {
153
+ }
154
+ if (result == null) {
155
+ console.warn(`Unable to parse the Key Vault reference for setting: ${key}`);
156
+ }
157
+ return result;
158
+ }
159
+ return null;
160
+ }
161
+ parseVaultReference(vaultReference) {
162
+ const secretUriString = this.getValueFromVaultReference("SecretUri", vaultReference);
163
+ if (secretUriString && secretUriString.length > 0) {
164
+ const secretUri = new URL(secretUriString);
165
+ const secretIdentifier = new KeyVaultSecretIdentifier(secretUri);
166
+ return new _KeyVaultReferencesManager.ParseSecretResult(secretIdentifier.vaultUri, secretIdentifier.name, secretIdentifier.version);
167
+ }
168
+ const vaultName = this.getValueFromVaultReference("VaultName", vaultReference);
169
+ const secretName = this.getValueFromVaultReference("SecretName", vaultReference);
170
+ const version = this.getValueFromVaultReference("SecretVersion", vaultReference);
171
+ if (vaultName && vaultName.length > 0 && secretName && secretName.length > 0) {
172
+ return new _KeyVaultReferencesManager.ParseSecretResult(new URL(`https://${vaultName}.${_KeyVaultReferencesManager.VaultUriSuffix}`), secretName, version);
173
+ }
174
+ return null;
175
+ }
176
+ getValueFromVaultReference(key, vaultReference) {
177
+ const regex = new RegExp(key + "=(?<Value>[^;]+)(;|$)");
178
+ const match = regex.exec(vaultReference);
179
+ if (_optionalChain([match, 'optionalAccess', _2 => _2.groups])) {
180
+ return _nullishCoalesce(match.groups["Value"], () => ( null));
181
+ }
182
+ return null;
183
+ }
184
+ getSecretClient(vaultUri) {
185
+ const uriString = vaultUri.toString();
186
+ let client = this._clients.get(uriString);
187
+ if (!client) {
188
+ client = new (0, _keyvaultsecrets.SecretClient)(uriString, this._credential);
189
+ this._clients.set(uriString, client);
190
+ }
191
+ return client;
192
+ }
193
+ }, _class2.__initStatic4(), _class2.__initStatic5(), _class2);
194
+ ((KeyVaultReferencesManager2) => {
195
+ class ParseSecretResult {
196
+ static {
197
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "ParseSecretResult");
198
+ }
199
+
200
+
201
+
202
+ constructor(uri, name, version) {
203
+ this.uri = uri;
204
+ this.name = name;
205
+ this.version = version;
206
+ }
207
+ }
208
+ KeyVaultReferencesManager2.ParseSecretResult = ParseSecretResult;
209
+ })(KeyVaultReferencesManager || (KeyVaultReferencesManager = {}));
210
+
211
+ // src/local-settings/SecretsManager.ts
212
+ var _nodepath = require('node:path');
213
+
214
+ // src/local-settings/AppSettingsFile.ts
215
+ var _nodefs = require('node:fs');
216
+ var AppSettingsFile = class {
217
+ constructor(filePath) {
218
+ this.filePath = filePath;
219
+ this.values = {};
220
+ this.connectionStrings = {};
221
+ this.isEncrypted = true;
222
+ try {
223
+ const content = _nodefs.readFileSync.call(void 0, this.filePath, "utf8");
224
+ const appSettings = JSON.parse(content);
225
+ this.isEncrypted = _nullishCoalesce(appSettings.IsEncrypted, () => ( true));
226
+ this.values = _nullishCoalesce(appSettings.Values, () => ( {}));
227
+ this.connectionStrings = _nullishCoalesce(appSettings.ConnectionStrings, () => ( {}));
228
+ this.host = _nullishCoalesce(appSettings.Host, () => ( {}));
229
+ } catch (ex) {
230
+ console.warn(`Failed to read app settings file at '${this.filePath}'. Ensure it is a valid JSON file.`, ex);
231
+ this.values = {};
232
+ this.connectionStrings = {};
233
+ this.isEncrypted = true;
234
+ }
235
+ }
236
+
237
+ static {
238
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "AppSettingsFile");
239
+ }
240
+
241
+
242
+
243
+
244
+ getValues() {
245
+ if (this.isEncrypted) {
246
+ throw new Error("Encrypted settings are not supported in this TypeScript port.");
247
+ }
248
+ return { ...this.values };
249
+ }
250
+ getConnectionStrings() {
251
+ return [];
252
+ }
253
+ };
254
+
255
+ // src/local-settings/SecretsManager.ts
256
+ var SecretsManager = (_class3 = class _SecretsManager {
257
+ static {
258
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "SecretsManager");
259
+ }
260
+ static __initStatic6() {this._lazySettings = null}
261
+ static get Settings() {
262
+ if (!_SecretsManager._lazySettings) {
263
+ _SecretsManager._lazySettings = new AppSettingsFile(_SecretsManager.AppSettingsFilePath);
264
+ }
265
+ return _SecretsManager._lazySettings;
266
+ }
267
+ static get AppSettingsFilePath() {
268
+ const secretsFile = "local.settings.json";
269
+ const rootPath = process.cwd();
270
+ const secretsFilePath = _nodepath.join.call(void 0, rootPath, secretsFile);
271
+ console.log(`'${secretsFile}' found in root directory (${rootPath}).`);
272
+ return secretsFilePath;
273
+ }
274
+ static get AppSettingsFileName() {
275
+ return "local.settings.json";
276
+ }
277
+ getSecrets(refreshSecrets = false) {
278
+ if (refreshSecrets) {
279
+ return new AppSettingsFile(_SecretsManager.AppSettingsFilePath).getValues();
280
+ }
281
+ return _SecretsManager.Settings.getValues();
282
+ }
283
+ getConnectionStrings() {
284
+ return _SecretsManager.Settings.getConnectionStrings();
285
+ }
286
+ }, _class3.__initStatic6(), _class3);
287
+
288
+ // src/local-settings/StartHostAction.ts
289
+ var StartHostAction = class {
290
+ static {
291
+ _chunkX6BO6XFBcjs.__name.call(void 0, this, "StartHostAction");
292
+ }
293
+
294
+
295
+ constructor() {
296
+ this._secretsManager = new SecretsManager();
297
+ this._keyVaultReferencesManager = new KeyVaultReferencesManager();
298
+ }
299
+ async buildWebHost() {
300
+ const settings = await this.getConfigurationSettings("", new URL("http://localhost:7071"));
301
+ await this._keyVaultReferencesManager.resolveKeyVaultReferences(settings);
302
+ this.updateEnvironmentVariables(settings);
303
+ }
304
+ async getConfigurationSettings(scriptPath, uri) {
305
+ const settings = this._secretsManager.getSecrets();
306
+ settings["WebsiteHostname"] = uri.host;
307
+ const connectionStrings = this._secretsManager.getConnectionStrings();
308
+ for (const connectionString of connectionStrings) {
309
+ settings[`ConnectionStrings:${connectionString.name}`] = connectionString.value;
310
+ }
311
+ settings["AzureWebJobsScriptRoot"] = scriptPath;
312
+ const environment = {};
313
+ for (const [key, value] of Object.entries(_nodeprocess.env)) {
314
+ if (typeof value === "string") {
315
+ environment[key] = value;
316
+ }
317
+ }
318
+ if (settings["AZURE_FUNCTIONS_ENVIRONMENT"]) {
319
+ const oldValue = settings["AZURE_FUNCTIONS_ENVIRONMENT"];
320
+ console.warn(`AZURE_FUNCTIONS_ENVIRONMENT already exists with value '${oldValue}', overriding to 'Development'.`);
321
+ }
322
+ settings["AZURE_FUNCTIONS_ENVIRONMENT"] = "Development";
323
+ return settings;
324
+ }
325
+ updateEnvironmentVariables(secrets) {
326
+ for (const [key, value] of Object.entries(secrets)) {
327
+ if (!key) {
328
+ console.warn("Skipping local setting with empty key.");
329
+ } else if (_nodeprocess.env[key] !== void 0) {
330
+ console.warn(`Skipping '${key}' from local settings as it's already defined in current environment variables.`);
331
+ } else if (value) {
332
+ _nodeprocess.env[key] = value;
333
+ } else if (value === "") {
334
+ _nodeprocess.env[key] = "";
335
+ } else {
336
+ console.warn(`Skipping '${key}' because value is null`);
337
+ }
338
+ }
339
+ }
340
+ };
341
+
342
+
343
+ exports.StartHostAction = StartHostAction;
344
+ //# sourceMappingURL=StartHostAction-PUOHB3U4.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/ecosystem/ecosystem/packages/build-azure-local-settings/dist/cjs/chunks/StartHostAction-PUOHB3U4.cjs","../../../src/local-settings/StartHostAction.ts","../../../src/local-settings/KeyVaultReferencesManager.ts","../../../src/local-settings/KeyVaultIdentifier.ts","../../../src/local-settings/KeyVaultSecretIdentifier.ts","../../../src/local-settings/SecretsManager.ts","../../../src/local-settings/AppSettingsFile.ts"],"names":[],"mappings":"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","file":"/home/runner/work/ecosystem/ecosystem/packages/build-azure-local-settings/dist/cjs/chunks/StartHostAction-PUOHB3U4.cjs","sourcesContent":[null,"/**\n * Port of StartHostAction from Azure Functions Core Tools (partial)\n * @see https://github.com/Azure/azure-functions-core-tools/blob/b367a5155d7bf299c4719dc37051082ae8ddebaf/src/Cli/func/Actions/HostActions/StartHostAction.cs\n */\n\nimport { env } from 'node:process';\nimport { KeyVaultReferencesManager } from './KeyVaultReferencesManager';\nimport { SecretsManager } from './SecretsManager';\n\nexport class StartHostAction {\n private readonly _secretsManager: SecretsManager;\n private readonly _keyVaultReferencesManager: KeyVaultReferencesManager;\n\n constructor() {\n this._secretsManager = new SecretsManager();\n this._keyVaultReferencesManager = new KeyVaultReferencesManager();\n }\n\n public async buildWebHost(): Promise<void> {\n const settings = await this.getConfigurationSettings('', new URL('http://localhost:7071'));\n await this._keyVaultReferencesManager.resolveKeyVaultReferences(settings);\n this.updateEnvironmentVariables(settings);\n }\n\n private async getConfigurationSettings(scriptPath: string, uri: URL): Promise<Record<string, string>> {\n const settings = this._secretsManager.getSecrets();\n settings['WebsiteHostname'] = uri.host;\n\n const connectionStrings = this._secretsManager.getConnectionStrings();\n for (const connectionString of connectionStrings) {\n settings[`ConnectionStrings:${connectionString.name}`] = connectionString.value;\n }\n settings['AzureWebJobsScriptRoot'] = scriptPath;\n\n const environment: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (typeof value === 'string') {\n environment[key] = value;\n }\n }\n\n if (settings['AZURE_FUNCTIONS_ENVIRONMENT']) {\n const oldValue = settings['AZURE_FUNCTIONS_ENVIRONMENT'];\n console.warn(`AZURE_FUNCTIONS_ENVIRONMENT already exists with value '${oldValue}', overriding to 'Development'.`);\n }\n\n settings['AZURE_FUNCTIONS_ENVIRONMENT'] = 'Development';\n\n return settings;\n }\n\n private updateEnvironmentVariables(secrets: Record<string, string>): void {\n for (const [key, value] of Object.entries(secrets)) {\n if (!key) {\n console.warn('Skipping local setting with empty key.');\n } else if (env[key] !== undefined) {\n console.warn(`Skipping '${key}' from local settings as it's already defined in current environment variables.`);\n } else if (value) {\n env[key] = value;\n } else if (value === '') {\n env[key] = '';\n } else {\n console.warn(`Skipping '${key}' because value is null`);\n }\n }\n }\n}\n","/**\n * Port of azure-functions-core-tools reading from local.settings.json\n * @see https://github.com/Azure/azure-functions-core-tools/blob/b367a5155d7bf299c4719dc37051082ae8ddebaf/src/Cli/func/Common/KeyVaultReferencesManager.cs\n */\n\n// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the MIT License. See LICENSE in the project root for license information.\n\nimport { DefaultAzureCredential, type TokenCredential } from '@azure/identity';\nimport { SecretClient } from '@azure/keyvault-secrets';\nimport { KeyVaultSecretIdentifier } from './KeyVaultSecretIdentifier';\n\nexport class KeyVaultReferencesManager {\n private static readonly VaultUriSuffix = 'vault.azure.net';\n private static readonly _basicKeyVaultReferenceRegex = /^@Microsoft\\.KeyVault\\((?<ReferenceString>.*)\\)$/;\n\n private readonly _clients = new Map<string, SecretClient>();\n private readonly _credential: TokenCredential = new DefaultAzureCredential(); // CodeQL [SM05137] This is never deployed to production, only used in CLI context in a local dev environment.\n\n public async resolveKeyVaultReferences(settings: { [key: string]: string | undefined }): Promise<void> {\n const keys = Object.keys(settings);\n\n for (const key of keys) {\n try {\n const keyVaultValue = await this.getSecretValue(key, settings[key]);\n if (keyVaultValue != null) {\n settings[key] = keyVaultValue;\n }\n } catch {}\n }\n }\n\n private async getSecretValue(key: string, value: string | undefined): Promise<string | null> {\n const result = this.parseSecret(key, value);\n\n if (result != null) {\n const client = this.getSecretClient(result.uri);\n const secret = await client.getSecret(result.name, result.version ? { version: result.version } : undefined);\n // biome-ignore lint/style/noNonNullAssertion: Key Vault SDK types value as optional but a successfully retrieved secret always has a value in local dev context\n return secret.value!;\n }\n\n return null;\n }\n\n public parseSecret(key: string, value: string | undefined): KeyVaultReferencesManager.ParseSecretResult | null {\n // If the value is null, then we return nothing, as the subsequent call to\n // UpdateEnvironmentVariables(settings) will log to the user that the setting\n // is skipped. We check here, because Regex.Match throws when supplied with a\n // null value.\n if (value == null) {\n return null;\n }\n\n // Determine if the secret value is attempting to use a key vault reference\n const keyVaultReferenceMatch = KeyVaultReferencesManager._basicKeyVaultReferenceRegex.exec(value);\n if (keyVaultReferenceMatch?.groups) {\n const referenceString = keyVaultReferenceMatch.groups['ReferenceString'];\n let result: KeyVaultReferencesManager.ParseSecretResult | null = null;\n try {\n if (referenceString != null) {\n result = this.parseVaultReference(referenceString);\n }\n } catch {\n // ignore and show warning below\n }\n\n // If we detect that a key vault reference was attempted, but did not match any of\n // the supported formats, we write a warning to the console.\n if (result == null) {\n console.warn(`Unable to parse the Key Vault reference for setting: ${key}`);\n }\n\n return result;\n }\n\n return null;\n }\n\n public parseVaultReference(vaultReference: string): KeyVaultReferencesManager.ParseSecretResult | null {\n const secretUriString = this.getValueFromVaultReference('SecretUri', vaultReference);\n if (secretUriString && secretUriString.length > 0) {\n const secretUri = new URL(secretUriString);\n const secretIdentifier = new KeyVaultSecretIdentifier(secretUri);\n return new KeyVaultReferencesManager.ParseSecretResult(secretIdentifier.vaultUri, secretIdentifier.name, secretIdentifier.version);\n }\n\n const vaultName = this.getValueFromVaultReference('VaultName', vaultReference);\n const secretName = this.getValueFromVaultReference('SecretName', vaultReference);\n const version = this.getValueFromVaultReference('SecretVersion', vaultReference);\n if (vaultName && vaultName.length > 0 && secretName && secretName.length > 0) {\n return new KeyVaultReferencesManager.ParseSecretResult(new URL(`https://${vaultName}.${KeyVaultReferencesManager.VaultUriSuffix}`), secretName, version);\n }\n\n return null;\n }\n\n public getValueFromVaultReference(key: string, vaultReference: string): string | null {\n const regex = new RegExp(key + '=(?<Value>[^;]+)(;|$)');\n const match = regex.exec(vaultReference);\n if (match?.groups) {\n return match.groups['Value'] ?? null;\n }\n\n return null;\n }\n\n private getSecretClient(vaultUri: URL): SecretClient {\n const uriString = vaultUri.toString();\n let client = this._clients.get(uriString);\n if (!client) {\n client = new SecretClient(uriString, this._credential);\n this._clients.set(uriString, client);\n }\n return client;\n }\n}\n\nexport namespace KeyVaultReferencesManager {\n export class ParseSecretResult {\n public uri: URL;\n public name: string;\n public version: string | null;\n\n constructor(uri: URL, name: string, version: string | null) {\n this.uri = uri;\n this.name = name;\n this.version = version;\n }\n }\n}\n","/**\n * Port of KeyVaultIdentifier from Azure SDK for .NET\n * @see https://github.com/Azure/azure-sdk-for-net/blob/3dad5181b332bf12d5298810f73347ee1bc9980b/sdk/keyvault/Azure.Security.KeyVault.Shared/src/KeyVaultIdentifier.cs\n */\n\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n\n// Ported from sdk/keyvault/Azure.Security.KeyVault.Shared/src/KeyVaultIdentifier.cs\nexport class KeyVaultIdentifier {\n public static readonly SecretsCollection = 'secrets';\n public static readonly KeysCollection = 'keys';\n public static readonly CertificatesCollection = 'certificates';\n\n public id: URL;\n public vaultUri: URL;\n public name: string;\n public collection: string;\n public version: string | null;\n\n constructor() {\n // Initialize with defaults - will be set by static methods\n this.id = new URL('http://localhost');\n this.vaultUri = new URL('http://localhost');\n this.name = '';\n this.collection = '';\n this.version = null;\n }\n\n public static parse(id: URL): KeyVaultIdentifier {\n if (id === null || id === undefined) {\n throw new Error('id cannot be null');\n }\n\n const result = KeyVaultIdentifier.tryParse(id);\n if (!result.success) {\n throw new Error(`Invalid ObjectIdentifier: ${id}. Bad number of segments: ${id.pathname.split('/').length}`);\n }\n // biome-ignore lint/style/noNonNullAssertion: tryParse sets identifier when success is true, guarded by the throw above\n return result.identifier!;\n }\n\n public static parseWithCollection(id: URL, collection: string): KeyVaultIdentifier {\n const identifier = KeyVaultIdentifier.parse(id);\n if (identifier.collection.toLowerCase() !== collection.toLowerCase()) {\n throw new Error(`Invalid ObjectIdentifier: ${id}. segment [1] should be '${collection}/', found '${identifier.collection}'`);\n }\n return identifier;\n }\n\n public static tryParse(id: URL | null): { success: boolean; identifier?: KeyVaultIdentifier } {\n if (id === null) {\n return { success: false };\n }\n\n // We expect an identifier with either 3 or 4 segments: host + collection + name [+ version]\n const segments = id.pathname.split('/');\n if (segments.length !== 3 && segments.length !== 4) {\n return { success: false };\n }\n\n const identifier = new KeyVaultIdentifier();\n identifier.id = id;\n identifier.vaultUri = new URL(`${id.protocol}//${id.host}`);\n // biome-ignore lint/style/noNonNullAssertion: length check above guarantees segments[1..3] exist\n identifier.collection = segments[1]!.replace(/\\/$/, ''); // Trim '/'\n // biome-ignore lint/style/noNonNullAssertion: length check above guarantees segments[1..3] exist\n identifier.name = segments[2]!.replace(/\\/$/, ''); // Trim '/'\n // biome-ignore lint/style/noNonNullAssertion: length check above guarantees segments[3] exists when length is 4\n identifier.version = segments.length === 4 ? segments[3]!.replace(/\\/$/, '') : null; // TrimEnd '/'\n\n return { success: true, identifier };\n }\n}\n","/**\n * Port of KeyVaultSecretIdentifier from Azure SDK for .NET\n * @see https://github.com/Azure/azure-sdk-for-net/blob/3dad5181b332bf12d5298810f73347ee1bc9980b/sdk/keyvault/Azure.Security.KeyVault.Secrets/src/KeyVaultSecretIdentifier.cs\n */\n\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT License.\n\nimport { KeyVaultIdentifier } from './KeyVaultIdentifier';\n\n/**\n * Information about a KeyVault Secret parsed from a URL.\n * You can use this information when calling methods of a SecretClient.\n */\nexport class KeyVaultSecretIdentifier {\n /**\n * Gets the source URL passed to KeyVaultSecretIdentifier constructor.\n */\n public sourceId: URL;\n\n /**\n * Gets the URL of the Key Vault.\n */\n public vaultUri: URL;\n\n /**\n * Gets the name of the secret.\n */\n public name: string;\n\n /**\n * Gets the optional version of the secret.\n */\n public version: string | null;\n\n /**\n * Creates a new instance of the KeyVaultSecretIdentifier class.\n * @param id The URL to a secret or deleted secret.\n * @throws Error if id is not a valid Key Vault secret ID.\n */\n public constructor(id: URL) {\n if (id === null || id === undefined) {\n throw new Error('id cannot be null');\n }\n\n const result = KeyVaultIdentifier.tryParse(id);\n if (result.success && result.identifier) {\n this.sourceId = id;\n this.vaultUri = result.identifier.vaultUri;\n this.name = result.identifier.name;\n this.version = result.identifier.version;\n } else {\n throw new Error(`${id} is not a valid secret ID`);\n }\n }\n}\n","/**\n * Port of SecretsManager from Azure Functions Core Tools\n * @see https://github.com/Azure/azure-functions-core-tools/blob/b367a5155d7bf299c4719dc37051082ae8ddebaf/src/Cli/func/Common/SecretsManager.cs\n */\n\nimport { join } from 'node:path';\nimport { AppSettingsFile } from './AppSettingsFile';\n\nexport class SecretsManager {\n private static _lazySettings: AppSettingsFile | null = null;\n\n private static get Settings(): AppSettingsFile {\n if (!SecretsManager._lazySettings) {\n SecretsManager._lazySettings = new AppSettingsFile(SecretsManager.AppSettingsFilePath);\n }\n return SecretsManager._lazySettings;\n }\n\n public static get AppSettingsFilePath(): string {\n const secretsFile = 'local.settings.json';\n const rootPath = process.cwd();\n const secretsFilePath = join(rootPath, secretsFile);\n\n console.log(`'${secretsFile}' found in root directory (${rootPath}).`);\n return secretsFilePath;\n }\n\n public static get AppSettingsFileName(): string {\n return 'local.settings.json';\n }\n\n public getSecrets(refreshSecrets = false): Record<string, string> {\n if (refreshSecrets) {\n return new AppSettingsFile(SecretsManager.AppSettingsFilePath).getValues();\n }\n\n return SecretsManager.Settings.getValues();\n }\n\n public getConnectionStrings(): any[] {\n return SecretsManager.Settings.getConnectionStrings();\n }\n}\n","/**\n * Port of AppSettingsFile from Azure Functions Core Tools\n * @see https://github.com/Azure/azure-functions-core-tools/blob/b367a5155d7bf299c4719dc37051082ae8ddebaf/src/Cli/func/Common/AppSettingsFile.cs\n */\n\nimport { readFileSync } from 'node:fs';\n\ninterface LocalSettingsJson {\n IsEncrypted?: boolean;\n Values?: Record<string, string>;\n ConnectionStrings?: Record<string, any>;\n Host?: any;\n}\n\nexport class AppSettingsFile {\n public isEncrypted: boolean;\n public values: Record<string, string>;\n public connectionStrings: Record<string, any>;\n public host: any;\n\n constructor(private filePath: string) {\n this.values = {};\n this.connectionStrings = {};\n this.isEncrypted = true;\n\n try {\n const content = readFileSync(this.filePath, 'utf8');\n const appSettings: LocalSettingsJson = JSON.parse(content);\n\n this.isEncrypted = appSettings.IsEncrypted ?? true;\n this.values = appSettings.Values ?? {};\n this.connectionStrings = appSettings.ConnectionStrings ?? {};\n this.host = appSettings.Host ?? {};\n } catch (ex) {\n console.warn(`Failed to read app settings file at '${this.filePath}'. Ensure it is a valid JSON file.`, ex);\n this.values = {};\n this.connectionStrings = {};\n this.isEncrypted = true;\n }\n }\n\n public getValues(): Record<string, string> {\n if (this.isEncrypted) {\n throw new Error('Encrypted settings are not supported in this TypeScript port.');\n }\n return { ...this.values };\n }\n\n public getConnectionStrings(): any[] {\n return [];\n }\n}\n"]}