@bubltec/mycota-config 0.0.1-next.10

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Genome
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ import { loadSsmConfig, pushSsmConfig, cloneSsmNamespace, deleteSsmNamespace } from './ssm-config.js';
3
+ const USAGE = `Usage:
4
+ mycota-config load --namespace <ns> --env <env> [--region <region>]
5
+ mycota-config push --namespace <ns> --env <env> --key <key> --value <value>
6
+ mycota-config clone --namespace <ns> --source <env> --target <env>
7
+ mycota-config delete --namespace <ns> --env <env>
8
+
9
+ 'load' prints dotenv-format KEY=VALUE lines to stdout — pipe/redirect it
10
+ (e.g. \`mycota-config load --namespace myapp --env dev > .env\`) rather than
11
+ reading it off the terminal, since it contains real secret values.`;
12
+ function parseArgs(argv) {
13
+ const args = {};
14
+ for (let i = 0; i < argv.length; i += 2) {
15
+ const key = argv[i]?.replace(/^--/, '');
16
+ const value = argv[i + 1];
17
+ if (key && value !== undefined)
18
+ args[key] = value;
19
+ }
20
+ return args;
21
+ }
22
+ function requireArg(args, name) {
23
+ const value = args[name];
24
+ if (!value) {
25
+ console.error(`Missing required --${name}\n\n${USAGE}`);
26
+ process.exit(1);
27
+ }
28
+ return value;
29
+ }
30
+ async function main() {
31
+ const [command, ...rest] = process.argv.slice(2);
32
+ const args = parseArgs(rest);
33
+ switch (command) {
34
+ case 'load': {
35
+ const config = await loadSsmConfig({
36
+ namespace: requireArg(args, 'namespace'),
37
+ env: requireArg(args, 'env'),
38
+ region: args.region,
39
+ });
40
+ for (const [key, value] of Object.entries(config)) {
41
+ console.log(`${key.toUpperCase().replace(/-/g, '_')}=${value}`);
42
+ }
43
+ break;
44
+ }
45
+ case 'push': {
46
+ const written = await pushSsmConfig({ namespace: requireArg(args, 'namespace'), env: requireArg(args, 'env') }, { [requireArg(args, 'key')]: requireArg(args, 'value') });
47
+ console.error(written.length ? `Wrote: ${written.join(', ')}` : 'Nothing written (empty value).');
48
+ break;
49
+ }
50
+ case 'clone': {
51
+ const written = await cloneSsmNamespace({
52
+ namespace: requireArg(args, 'namespace'),
53
+ sourceEnv: requireArg(args, 'source'),
54
+ targetEnv: requireArg(args, 'target'),
55
+ });
56
+ console.error(`Cloned ${written.length} parameter(s):\n${written.join('\n')}`);
57
+ break;
58
+ }
59
+ case 'delete': {
60
+ const deleted = await deleteSsmNamespace({
61
+ namespace: requireArg(args, 'namespace'),
62
+ env: requireArg(args, 'env'),
63
+ });
64
+ console.error(`Deleted ${deleted.length} parameter(s):\n${deleted.join('\n')}`);
65
+ break;
66
+ }
67
+ default:
68
+ console.error(USAGE);
69
+ process.exit(1);
70
+ }
71
+ }
72
+ main().catch((err) => {
73
+ console.error(err);
74
+ process.exitCode = 1;
75
+ });
76
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { loadSsmConfig, pushSsmConfig, cloneSsmNamespace, deleteSsmNamespace, type SsmConfigOptions, type CloneSsmNamespaceOptions, type DeleteSsmNamespaceOptions, } from './ssm-config.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { loadSsmConfig, pushSsmConfig, cloneSsmNamespace, deleteSsmNamespace, } from './ssm-config.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,GAInB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,53 @@
1
+ export interface SsmConfigOptions {
2
+ /** Top-level SSM prefix, e.g. 'btfp'. */
3
+ namespace: string;
4
+ /** Any string — 'dev', 'prod', 'pr-123', a branch name. Not a fixed enum, so ephemeral stacks need no code changes. */
5
+ env: string;
6
+ region?: string;
7
+ /** Also merge in /{namespace}/shared/*, env-specific wins on key collision. Default true. */
8
+ includeShared?: boolean;
9
+ }
10
+ /**
11
+ * Loads config for one namespace/env, merging /{namespace}/shared/* first
12
+ * and then /{namespace}/{env}/* on top (env wins on collision). Returns {}
13
+ * for an environment that hasn't been provisioned yet — never throws for
14
+ * that case — so a brand-new ephemeral stack still boots (degraded/
15
+ * placeholder) instead of crashing.
16
+ */
17
+ export declare function loadSsmConfig(options: SsmConfigOptions): Promise<Record<string, string>>;
18
+ /**
19
+ * Writes each non-empty value to /{namespace}/{env}/{key} as a SecureString.
20
+ * Empty/undefined values are skipped (mirrors "don't push a placeholder").
21
+ * Returns the parameter names actually written.
22
+ */
23
+ export declare function pushSsmConfig(options: SsmConfigOptions, values: Record<string, string | undefined>): Promise<string[]>;
24
+ export interface CloneSsmNamespaceOptions {
25
+ namespace: string;
26
+ sourceEnv: string;
27
+ targetEnv: string;
28
+ region?: string;
29
+ }
30
+ /**
31
+ * The ephemeral-stack bootstrap primitive: copies every parameter from
32
+ * /{namespace}/{sourceEnv}/* to /{namespace}/{targetEnv}/* — e.g. spin up
33
+ * "pr-123" pre-populated from "dev"'s values. Idempotent (Overwrite: true).
34
+ */
35
+ export declare function cloneSsmNamespace(options: CloneSsmNamespaceOptions): Promise<string[]>;
36
+ export interface DeleteSsmNamespaceOptions {
37
+ namespace: string;
38
+ env: string;
39
+ region?: string;
40
+ }
41
+ /**
42
+ * The ephemeral-stack teardown primitive: deletes every parameter under
43
+ * /{namespace}/{env}/* — call when a PR closes / a preview stack is
44
+ * destroyed, so its secrets don't linger indefinitely.
45
+ *
46
+ * Confirmed empirically: SSM's GetParametersByPath can lag a few seconds
47
+ * behind a delete — a loadSsmConfig call immediately after this resolves
48
+ * can still show the just-deleted values before catching up. Don't chain
49
+ * "delete, then immediately verify empty" in a script without a short wait;
50
+ * a teardown pipeline that deletes and moves on (the normal case) is fine.
51
+ */
52
+ export declare function deleteSsmNamespace(options: DeleteSsmNamespaceOptions): Promise<string[]>;
53
+ //# sourceMappingURL=ssm-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssm-config.d.ts","sourceRoot":"","sources":["../src/ssm-config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,uHAAuH;IACvH,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAmDD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAY9F;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACzC,OAAO,CAAC,MAAM,EAAE,CAAC,CAanB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAqB5F;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAc9F"}
@@ -0,0 +1,119 @@
1
+ import { GetParametersByPathCommand, PutParameterCommand, DeleteParametersCommand, SSMClient, } from '@aws-sdk/client-ssm';
2
+ /** SSM's DeleteParameters caps at 10 names per call. */
3
+ const DELETE_BATCH_SIZE = 10;
4
+ function resolveRegion(region) {
5
+ return region ?? process.env.AWS_REGION ?? 'us-east-1';
6
+ }
7
+ function leafName(parameterName) {
8
+ return parameterName.split('/').pop() ?? parameterName;
9
+ }
10
+ function toLeafMap(params) {
11
+ return Object.fromEntries(params.map((p) => [leafName(p.name), p.value]));
12
+ }
13
+ /**
14
+ * Lists every parameter under `path`, decrypted. Returns [] for a path with
15
+ * no parameters at all — GetParametersByPath never throws for an empty
16
+ * result, unlike GetParameter for a single missing name — which is exactly
17
+ * what makes an unprovisioned/ephemeral environment degrade gracefully
18
+ * instead of failing to boot.
19
+ */
20
+ async function listParametersUnderPath(client, path) {
21
+ const results = [];
22
+ let nextToken;
23
+ do {
24
+ const response = await client.send(new GetParametersByPathCommand({
25
+ Path: path,
26
+ Recursive: true,
27
+ WithDecryption: true,
28
+ NextToken: nextToken,
29
+ }));
30
+ for (const param of response.Parameters ?? []) {
31
+ if (param.Name && param.Value !== undefined) {
32
+ results.push({ name: param.Name, value: param.Value });
33
+ }
34
+ }
35
+ nextToken = response.NextToken;
36
+ } while (nextToken);
37
+ return results;
38
+ }
39
+ /**
40
+ * Loads config for one namespace/env, merging /{namespace}/shared/* first
41
+ * and then /{namespace}/{env}/* on top (env wins on collision). Returns {}
42
+ * for an environment that hasn't been provisioned yet — never throws for
43
+ * that case — so a brand-new ephemeral stack still boots (degraded/
44
+ * placeholder) instead of crashing.
45
+ */
46
+ export async function loadSsmConfig(options) {
47
+ const client = new SSMClient({ region: resolveRegion(options.region) });
48
+ const merged = {};
49
+ if (options.includeShared ?? true) {
50
+ Object.assign(merged, toLeafMap(await listParametersUnderPath(client, `/${options.namespace}/shared/`)));
51
+ }
52
+ Object.assign(merged, toLeafMap(await listParametersUnderPath(client, `/${options.namespace}/${options.env}/`)));
53
+ return merged;
54
+ }
55
+ /**
56
+ * Writes each non-empty value to /{namespace}/{env}/{key} as a SecureString.
57
+ * Empty/undefined values are skipped (mirrors "don't push a placeholder").
58
+ * Returns the parameter names actually written.
59
+ */
60
+ export async function pushSsmConfig(options, values) {
61
+ const client = new SSMClient({ region: resolveRegion(options.region) });
62
+ const written = [];
63
+ for (const [key, value] of Object.entries(values)) {
64
+ if (!value)
65
+ continue;
66
+ const name = `/${options.namespace}/${options.env}/${key}`;
67
+ await client.send(new PutParameterCommand({ Name: name, Value: value, Type: 'SecureString', Overwrite: true }));
68
+ written.push(name);
69
+ }
70
+ return written;
71
+ }
72
+ /**
73
+ * The ephemeral-stack bootstrap primitive: copies every parameter from
74
+ * /{namespace}/{sourceEnv}/* to /{namespace}/{targetEnv}/* — e.g. spin up
75
+ * "pr-123" pre-populated from "dev"'s values. Idempotent (Overwrite: true).
76
+ */
77
+ export async function cloneSsmNamespace(options) {
78
+ const client = new SSMClient({ region: resolveRegion(options.region) });
79
+ const sourceParams = await listParametersUnderPath(client, `/${options.namespace}/${options.sourceEnv}/`);
80
+ const written = [];
81
+ for (const param of sourceParams) {
82
+ const targetName = `/${options.namespace}/${options.targetEnv}/${leafName(param.name)}`;
83
+ await client.send(new PutParameterCommand({
84
+ Name: targetName,
85
+ Value: param.value,
86
+ Type: 'SecureString',
87
+ Overwrite: true,
88
+ }));
89
+ written.push(targetName);
90
+ }
91
+ return written;
92
+ }
93
+ /**
94
+ * The ephemeral-stack teardown primitive: deletes every parameter under
95
+ * /{namespace}/{env}/* — call when a PR closes / a preview stack is
96
+ * destroyed, so its secrets don't linger indefinitely.
97
+ *
98
+ * Confirmed empirically: SSM's GetParametersByPath can lag a few seconds
99
+ * behind a delete — a loadSsmConfig call immediately after this resolves
100
+ * can still show the just-deleted values before catching up. Don't chain
101
+ * "delete, then immediately verify empty" in a script without a short wait;
102
+ * a teardown pipeline that deletes and moves on (the normal case) is fine.
103
+ */
104
+ export async function deleteSsmNamespace(options) {
105
+ const client = new SSMClient({ region: resolveRegion(options.region) });
106
+ const path = `/${options.namespace}/${options.env}/`;
107
+ const params = await listParametersUnderPath(client, path);
108
+ if (params.length === 0)
109
+ return [];
110
+ const names = params.map((p) => p.name);
111
+ const deleted = [];
112
+ for (let i = 0; i < names.length; i += DELETE_BATCH_SIZE) {
113
+ const batch = names.slice(i, i + DELETE_BATCH_SIZE);
114
+ await client.send(new DeleteParametersCommand({ Names: batch }));
115
+ deleted.push(...batch);
116
+ }
117
+ return deleted;
118
+ }
119
+ //# sourceMappingURL=ssm-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssm-config.js","sourceRoot":"","sources":["../src/ssm-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ssm-config.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssm-config.spec.d.ts","sourceRoot":"","sources":["../src/ssm-config.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,107 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { mockClient } from 'aws-sdk-client-mock';
3
+ import { SSMClient, GetParametersByPathCommand, PutParameterCommand, DeleteParametersCommand, } from '@aws-sdk/client-ssm';
4
+ import { loadSsmConfig, pushSsmConfig, cloneSsmNamespace, deleteSsmNamespace } from './ssm-config.js';
5
+ const ssmMock = mockClient(SSMClient);
6
+ beforeEach(() => {
7
+ ssmMock.reset();
8
+ });
9
+ describe('loadSsmConfig', () => {
10
+ it('merges shared params first, then env-specific overrides on collision', async () => {
11
+ ssmMock
12
+ .on(GetParametersByPathCommand, { Path: '/myapp/shared/', Recursive: true })
13
+ .resolves({
14
+ Parameters: [
15
+ { Name: '/myapp/shared/brave-search-api-key', Value: 'shared-brave-key' },
16
+ { Name: '/myapp/shared/jwt-secret', Value: 'shared-jwt' },
17
+ ],
18
+ })
19
+ .on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
20
+ .resolves({
21
+ Parameters: [{ Name: '/myapp/dev/jwt-secret', Value: 'dev-jwt' }],
22
+ });
23
+ const result = await loadSsmConfig({ namespace: 'myapp', env: 'dev' });
24
+ expect(result).toEqual({
25
+ 'brave-search-api-key': 'shared-brave-key',
26
+ 'jwt-secret': 'dev-jwt', // env-specific wins over shared
27
+ });
28
+ });
29
+ it('returns {} for an unprovisioned/ephemeral environment instead of throwing', async () => {
30
+ ssmMock.on(GetParametersByPathCommand).resolves({ Parameters: [] });
31
+ const result = await loadSsmConfig({ namespace: 'myapp', env: 'pr-999', includeShared: false });
32
+ expect(result).toEqual({});
33
+ });
34
+ it('skips the shared lookup when includeShared is false', async () => {
35
+ ssmMock
36
+ .on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
37
+ .resolves({ Parameters: [{ Name: '/myapp/dev/jwt-secret', Value: 'dev-jwt' }] });
38
+ const result = await loadSsmConfig({ namespace: 'myapp', env: 'dev', includeShared: false });
39
+ expect(result).toEqual({ 'jwt-secret': 'dev-jwt' });
40
+ expect(ssmMock.commandCalls(GetParametersByPathCommand, { Path: '/myapp/shared/' })).toHaveLength(0);
41
+ });
42
+ it('follows NextToken pagination', async () => {
43
+ ssmMock
44
+ .on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
45
+ .resolvesOnce({
46
+ Parameters: [{ Name: '/myapp/dev/key-a', Value: 'a' }],
47
+ NextToken: 'page-2',
48
+ })
49
+ .resolves({
50
+ Parameters: [{ Name: '/myapp/dev/key-b', Value: 'b' }],
51
+ });
52
+ const result = await loadSsmConfig({ namespace: 'myapp', env: 'dev', includeShared: false });
53
+ expect(result).toEqual({ 'key-a': 'a', 'key-b': 'b' });
54
+ });
55
+ });
56
+ describe('pushSsmConfig', () => {
57
+ it('writes each non-empty value as a SecureString under the env path', async () => {
58
+ ssmMock.on(PutParameterCommand).resolves({});
59
+ const written = await pushSsmConfig({ namespace: 'myapp', env: 'dev' }, { 'jwt-secret': 'real-value', 'unset-key': undefined, 'empty-key': '' });
60
+ expect(written).toEqual(['/myapp/dev/jwt-secret']);
61
+ expect(ssmMock.commandCalls(PutParameterCommand)).toHaveLength(1);
62
+ expect(ssmMock.commandCalls(PutParameterCommand)[0]?.args[0].input).toMatchObject({
63
+ Name: '/myapp/dev/jwt-secret',
64
+ Value: 'real-value',
65
+ Type: 'SecureString',
66
+ Overwrite: true,
67
+ });
68
+ });
69
+ });
70
+ describe('cloneSsmNamespace', () => {
71
+ it('copies every source-env parameter to the target env', async () => {
72
+ ssmMock
73
+ .on(GetParametersByPathCommand, { Path: '/myapp/dev/', Recursive: true })
74
+ .resolves({
75
+ Parameters: [
76
+ { Name: '/myapp/dev/jwt-secret', Value: 'dev-jwt' },
77
+ { Name: '/myapp/dev/basic-auth-user', Value: 'admin' },
78
+ ],
79
+ });
80
+ ssmMock.on(PutParameterCommand).resolves({});
81
+ const written = await cloneSsmNamespace({ namespace: 'myapp', sourceEnv: 'dev', targetEnv: 'pr-123' });
82
+ expect(written.sort()).toEqual(['/myapp/pr-123/jwt-secret', '/myapp/pr-123/basic-auth-user'].sort());
83
+ expect(ssmMock.commandCalls(PutParameterCommand)).toHaveLength(2);
84
+ });
85
+ });
86
+ describe('deleteSsmNamespace', () => {
87
+ it('returns [] without calling DeleteParameters when nothing exists', async () => {
88
+ ssmMock.on(GetParametersByPathCommand).resolves({ Parameters: [] });
89
+ const deleted = await deleteSsmNamespace({ namespace: 'myapp', env: 'pr-123' });
90
+ expect(deleted).toEqual([]);
91
+ expect(ssmMock.commandCalls(DeleteParametersCommand)).toHaveLength(0);
92
+ });
93
+ it('batches deletes at 10 names per call', async () => {
94
+ const names = Array.from({ length: 23 }, (_, i) => `/myapp/pr-123/key-${i}`);
95
+ ssmMock
96
+ .on(GetParametersByPathCommand, { Path: '/myapp/pr-123/', Recursive: true })
97
+ .resolves({ Parameters: names.map((name) => ({ Name: name, Value: 'v' })) });
98
+ ssmMock.on(DeleteParametersCommand).resolves({});
99
+ const deleted = await deleteSsmNamespace({ namespace: 'myapp', env: 'pr-123' });
100
+ expect(deleted).toHaveLength(23);
101
+ const calls = ssmMock.commandCalls(DeleteParametersCommand);
102
+ expect(calls).toHaveLength(3); // 10 + 10 + 3
103
+ expect(calls[0]?.args[0].input.Names).toHaveLength(10);
104
+ expect(calls[2]?.args[0].input.Names).toHaveLength(3);
105
+ });
106
+ });
107
+ //# sourceMappingURL=ssm-config.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssm-config.spec.js","sourceRoot":"","sources":["../src/ssm-config.spec.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@bubltec/mycota-config",
3
+ "version": "0.0.1-next.10",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "bin": {
14
+ "mycota-config": "./dist/cli.js"
15
+ },
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@aws-sdk/client-ssm": "^3.716.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.10.0",
27
+ "aws-sdk-client-mock": "^4.1.0",
28
+ "typescript": "^5.8.0",
29
+ "vitest": "^2.1.0"
30
+ },
31
+ "scripts": {
32
+ "build": "tsc -b",
33
+ "typecheck": "tsc -b --noEmit",
34
+ "lint": "oxlint -c ../../.oxlintrc.json src",
35
+ "test": "vitest run"
36
+ }
37
+ }