@eighty4/c2 0.0.3-0 → 0.0.3

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
@@ -2,10 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ - ???
6
+
7
+ ## [v0.0.3] - 2025-06-26
8
+
5
9
  ### Fixed
6
10
 
7
- - TypeScript type declarations were broken by pointing to a
8
- directory instead of the export entrypoint `.d.ts` file
11
+ - TypeScript type declarations were broken because subpath imports
12
+ used internally in package were output in `.d.ts` files and
13
+ `package.json` pointed `types` to a directory instead of the
14
+ export entrypoint `.d.ts` file
9
15
 
10
16
  ## [v0.0.2] - 2025-06-07
11
17
 
@@ -16,5 +22,6 @@
16
22
  - Evaluate env() and file() expressions in user data
17
23
  - Merge multiple user data into a MIME multipart message
18
24
 
19
- [Unreleased]: https://github.com/eighty4/c2/compare/v0.0.2...HEAD
25
+ [Unreleased]: https://github.com/eighty4/c2/compare/v0.0.3...HEAD
26
+ [v0.0.3]: https://github.com/eighty4/c2/compare/v0.0.2...v0.0.3
20
27
  [v0.0.2]: https://github.com/eighty4/c2/releases/tag/v0.0.2
@@ -1,5 +1,5 @@
1
- import { evalTemplateExpressions } from '#c2/expression'
2
- import { readDirListing, readToString } from '#c2/fs'
1
+ import { evalTemplateExpressions } from './expression.ts'
2
+ import { readDirListing, readToString } from './fs.ts'
3
3
 
4
4
  export type AttachmentType = 'cloud-config' | 'x-shellscript'
5
5
 
package/lib/build.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { collectAttachments } from '#c2/attachments'
2
- import { MultipartMessage } from '#c2/http'
1
+ import { collectAttachments } from './attachments.ts'
2
+ import { MultipartMessage } from './http.ts'
3
3
 
4
4
  export type BuildUserDataOpts = {
5
5
  attachmentBoundary?: string
package/lib/c2.api.ts CHANGED
@@ -1 +1 @@
1
- export { type BuildUserDataOpts, buildUserData } from '#c2/build'
1
+ export { type BuildUserDataOpts, buildUserData } from './build.ts'
package/lib/c2.bin.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { buildUserData } from '#c2/build'
4
- import { parseArgs, type ParsedArgs } from '#c2/cli'
5
- import { doesDirExist } from '#c2/fs'
6
- import { startUserDataHttp } from '#c2/http'
3
+ import { buildUserData } from './build.ts'
4
+ import { parseArgs, type ParsedArgs } from './cli.ts'
5
+ import { doesDirExist } from './fs.ts'
6
+ import { startUserDataHttp } from './http.ts'
7
7
 
8
8
  let args: ParsedArgs | undefined
9
9
  try {
package/lib/expression.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import MagicString from 'magic-string'
2
- import { readToString } from '#c2/fs'
2
+ import { readToString } from './fs.ts'
3
3
 
4
4
  type TemplateExpression = {
5
5
  index: number
package/lib/http.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto'
2
2
  import { createServer, type ServerResponse } from 'node:http'
3
- import { type Attachment, collectAttachments } from '#c2/attachments'
3
+ import { type Attachment, collectAttachments } from './attachments.ts'
4
4
 
5
5
  export function startUserDataHttp(port: number, userDataDir: string) {
6
6
  const server = createServer((req, res) => {
@@ -1,5 +1,5 @@
1
- import { evalTemplateExpressions } from '#c2/expression';
2
- import { readDirListing, readToString } from '#c2/fs';
1
+ import { evalTemplateExpressions } from "./expression.js";
2
+ import { readDirListing, readToString } from "./fs.js";
3
3
  export async function collectAttachments(dir) {
4
4
  const filenames = await readDirListing(dir);
5
5
  const attachments = await Promise.all(filenames.map(async (filename) => {
package/lib_js/build.js CHANGED
@@ -1,5 +1,5 @@
1
- import { collectAttachments } from '#c2/attachments';
2
- import { MultipartMessage } from '#c2/http';
1
+ import { collectAttachments } from "./attachments.js";
2
+ import { MultipartMessage } from "./http.js";
3
3
  export async function buildUserData(userDataDir, opts) {
4
4
  const attachments = await collectAttachments(userDataDir);
5
5
  switch (attachments.length) {
package/lib_js/c2.api.js CHANGED
@@ -1 +1 @@
1
- export { buildUserData } from '#c2/build';
1
+ export { buildUserData } from "./build.js";
package/lib_js/c2.bin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { buildUserData } from '#c2/build';
3
- import { parseArgs } from '#c2/cli';
4
- import { doesDirExist } from '#c2/fs';
5
- import { startUserDataHttp } from '#c2/http';
2
+ import { buildUserData } from "./build.js";
3
+ import { parseArgs } from "./cli.js";
4
+ import { doesDirExist } from "./fs.js";
5
+ import { startUserDataHttp } from "./http.js";
6
6
  let args;
7
7
  try {
8
8
  args = parseArgs();
@@ -1,5 +1,5 @@
1
1
  import MagicString from 'magic-string';
2
- import { readToString } from '#c2/fs';
2
+ import { readToString } from "./fs.js";
3
3
  export async function evalTemplateExpressions(content) {
4
4
  const regex = new RegExp(/\${{\s*(.*)\s*}}/g);
5
5
  let match;
package/lib_js/http.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { createServer } from 'node:http';
3
- import { collectAttachments } from '#c2/attachments';
3
+ import { collectAttachments } from "./attachments.js";
4
4
  export function startUserDataHttp(port, userDataDir) {
5
5
  const server = createServer((req, res) => {
6
6
  console.log(req.method, req.url);
@@ -1,2 +1,2 @@
1
- export { type BuildUserDataOpts, buildUserData } from '#c2/build';
1
+ export { type BuildUserDataOpts, buildUserData } from './build.ts';
2
2
  //# sourceMappingURL=c2.api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"c2.api.d.ts","sourceRoot":"","sources":["../lib/c2.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"c2.api.d.ts","sourceRoot":"","sources":["../lib/c2.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA"}
@@ -1,4 +1,4 @@
1
- import { type Attachment } from '#c2/attachments';
1
+ import { type Attachment } from './attachments.ts';
2
2
  export declare function startUserDataHttp(port: number, userDataDir: string): void;
3
3
  export declare class MultipartMessage {
4
4
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../lib/http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,iBAAiB,CAAA;AAErE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAoBlE;AAiBD,qBAAa,gBAAgB;;IACzB,MAAM,CAAC,cAAc,IAAI,MAAM;gBAQ3B,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,EAC9B,QAAQ,GAAE,MAA0C;IAMxD,IAAI,WAAW,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAE5C;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMpC;IAED,MAAM,IAAI,MAAM;IAShB,YAAY,IAAI,MAAM;CASzB;AAED,qBAAa,mBAAmB;;gBAGhB,UAAU,EAAE,UAAU;IAIlC,MAAM,IAAI,MAAM;CASnB"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../lib/http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,kBAAkB,CAAA;AAEtE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAoBlE;AAiBD,qBAAa,gBAAgB;;IACzB,MAAM,CAAC,cAAc,IAAI,MAAM;gBAQ3B,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,EAC9B,QAAQ,GAAE,MAA0C;IAMxD,IAAI,WAAW,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAE5C;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMpC;IAED,MAAM,IAAI,MAAM;IAShB,YAAY,IAAI,MAAM;CASzB;AAED,qBAAa,mBAAmB;;gBAGhB,UAAU,EAAE,UAAU;IAIlC,MAAM,IAAI,MAAM;CASnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eighty4/c2",
3
- "version": "0.0.3-0",
3
+ "version": "0.0.3",
4
4
  "author": "Adam McKee <adam.be.g84d@gmail.com>",
5
5
  "repository": "https://github.com/eighty4/c2",
6
6
  "homepage": "https://github.com/eighty4/c2",
@@ -22,17 +22,11 @@
22
22
  "bin": {
23
23
  "c2": "./lib_js/c2.bin.js"
24
24
  },
25
- "types": "./lib_types/c2.api.d.ts",
26
25
  "exports": {
27
26
  ".": {
28
27
  "bun": "./lib/c2.api.ts",
29
- "node": "./lib_js/c2.api.js"
30
- }
31
- },
32
- "imports": {
33
- "#c2/*": {
34
- "bun": "./lib/*.ts",
35
- "node": "./lib_js/*.js"
28
+ "node": "./lib_js/c2.api.js",
29
+ "types": "./lib_types/c2.api.d.ts"
36
30
  }
37
31
  },
38
32
  "scripts": {
@@ -53,6 +47,7 @@
53
47
  },
54
48
  "files": [
55
49
  "lib/*",
50
+ "!lib/*.spec.ts",
56
51
  "lib_js/*",
57
52
  "lib_types/*",
58
53
  "CHANGELOG.md"
@@ -1,111 +0,0 @@
1
- import { afterEach, beforeEach, expect, test } from 'bun:test'
2
- import { join } from 'node:path'
3
- import { collectAttachments } from '#c2/attachments'
4
- import { makeFile, makeTempDir, removeDir } from '#c2/fs.testing'
5
-
6
- let tmpDir: string
7
-
8
- beforeEach(async () => (tmpDir = await makeTempDir()))
9
-
10
- afterEach(async () => await removeDir(tmpDir))
11
-
12
- test('collect throws error for unknown filetype', async () => {
13
- await makeFile('init-cloud', 'whoopie', tmpDir)
14
- await expect(() => collectAttachments(tmpDir)).toThrow(
15
- 'init-cloud is an unsupported file type',
16
- )
17
- })
18
-
19
- test('collect cloud config yml', async () => {
20
- await makeFile('init-cloud.yml', '#cloud-config\nwhoopie', tmpDir)
21
- expect(await collectAttachments(tmpDir)).toStrictEqual([
22
- {
23
- path: join(tmpDir, 'init-cloud.yml'),
24
- content: '#cloud-config\nwhoopie',
25
- filename: 'init-cloud.yml',
26
- source: '#cloud-config\nwhoopie',
27
- type: 'cloud-config',
28
- },
29
- ])
30
- })
31
-
32
- test('collect cloud config yaml', async () => {
33
- await makeFile('init-cloud.yaml', '#cloud-config\nwhoopie', tmpDir)
34
- expect(await collectAttachments(tmpDir)).toStrictEqual([
35
- {
36
- path: join(tmpDir, 'init-cloud.yaml'),
37
- content: '#cloud-config\nwhoopie',
38
- filename: 'init-cloud.yaml',
39
- source: '#cloud-config\nwhoopie',
40
- type: 'cloud-config',
41
- },
42
- ])
43
- })
44
-
45
- test('collect throws error when yml does not have #cloud-config comment', async () => {
46
- await makeFile('init-cloud.yml', 'whoopie', tmpDir)
47
- await expect(() => collectAttachments(tmpDir)).toThrow(
48
- 'YAML cloud config must start with a #cloud-config comment',
49
- )
50
- })
51
-
52
- test('collect throws error when yaml does not have #cloud-config comment', async () => {
53
- await makeFile('init-cloud.yaml', 'whoopie', tmpDir)
54
- await expect(() => collectAttachments(tmpDir)).toThrow(
55
- 'YAML cloud config must start with a #cloud-config comment',
56
- )
57
- })
58
-
59
- test('collect shell script', async () => {
60
- await makeFile('init-cloud.sh', 'whoopie', tmpDir)
61
- expect(await collectAttachments(tmpDir)).toStrictEqual([
62
- {
63
- path: join(tmpDir, 'init-cloud.sh'),
64
- content: 'whoopie',
65
- filename: 'init-cloud.sh',
66
- source: 'whoopie',
67
- type: 'x-shellscript',
68
- },
69
- ])
70
- })
71
-
72
- test('evals template expressions', async () => {
73
- const resourceTmpDir = await makeTempDir()
74
- await makeFile('whoopie', 'whoopie', resourceTmpDir)
75
- await makeFile(
76
- 'init-cloud.sh',
77
- `\${{ file('${resourceTmpDir}/whoopie') }}`,
78
- tmpDir,
79
- )
80
- expect(await collectAttachments(tmpDir)).toStrictEqual([
81
- {
82
- path: tmpDir + '/init-cloud.sh',
83
- content: 'whoopie',
84
- filename: 'init-cloud.sh',
85
- source: `\${{ file('${resourceTmpDir}/whoopie') }}`,
86
- type: 'x-shellscript',
87
- },
88
- ])
89
- await removeDir(resourceTmpDir)
90
- })
91
-
92
- test('sorts attachments by filename', async () => {
93
- await makeFile('01-init-cloud.sh', 'whoopie', tmpDir)
94
- await makeFile('02-init-cloud.sh', 'whoopie', tmpDir)
95
- expect(await collectAttachments(tmpDir)).toStrictEqual([
96
- {
97
- path: join(tmpDir, '01-init-cloud.sh'),
98
- content: 'whoopie',
99
- filename: '01-init-cloud.sh',
100
- source: 'whoopie',
101
- type: 'x-shellscript',
102
- },
103
- {
104
- path: join(tmpDir, '02-init-cloud.sh'),
105
- content: 'whoopie',
106
- filename: '02-init-cloud.sh',
107
- source: 'whoopie',
108
- type: 'x-shellscript',
109
- },
110
- ])
111
- })
package/lib/build.spec.ts DELETED
@@ -1,90 +0,0 @@
1
- import { afterEach, beforeEach, expect, test } from 'bun:test'
2
- import { buildUserData } from '#c2/build'
3
- import { makeFile, makeTempDir, removeDir } from '#c2/fs.testing'
4
-
5
- let tmpDir: string
6
-
7
- beforeEach(async () => {
8
- tmpDir = await makeTempDir()
9
- })
10
-
11
- afterEach(async () => removeDir(tmpDir))
12
-
13
- test('build user data of single file', async () => {
14
- const initCloudYml = '#cloud-config\nwhoopie'
15
- await makeFile('init-cloud.yml', initCloudYml, tmpDir)
16
- expect(await buildUserData(tmpDir)).toStrictEqual(initCloudYml)
17
- })
18
-
19
- test('build user data of single file with template expression', async () => {
20
- const whoopie = await makeTempDir()
21
- await makeFile('whoopie', 'whoopie', whoopie)
22
- await makeFile(
23
- 'init-cloud.yml',
24
- `#cloud-config\n\${{ file('${whoopie}/whoopie')}}`,
25
- tmpDir,
26
- )
27
- expect(await buildUserData(tmpDir)).toStrictEqual('#cloud-config\nwhoopie')
28
- await removeDir(whoopie)
29
- })
30
-
31
- test('build user data multipart message', async () => {
32
- await makeFile('1-init-cloud.yml', '#cloud-config\nwhoopie', tmpDir)
33
- await makeFile('2-init-cloud.sh', 'cushion', tmpDir)
34
- const boundary = Bun.randomUUIDv7()
35
- expect(
36
- await buildUserData(tmpDir, { attachmentBoundary: boundary }),
37
- ).toStrictEqual(
38
- `Content-Type: multipart/mixed; boundary=${boundary}\r
39
- MIME-Version: 1.0\r
40
- Number-Attachments: 2\r
41
- --${boundary}\r
42
- Content-Type: text/cloud-config; charset="us-ascii"\r
43
- Content-Transfer-Encoding: 7bit\r
44
- Content-Disposition: attachment; filename="1-init-cloud.yml"\r
45
- \r
46
- #cloud-config
47
- whoopie\r
48
- --${boundary}\r
49
- Content-Type: text/x-shellscript; charset="us-ascii"\r
50
- Content-Transfer-Encoding: 7bit\r
51
- Content-Disposition: attachment; filename="2-init-cloud.sh"\r
52
- \r
53
- cushion\r
54
- --${boundary}\r
55
- `,
56
- )
57
- })
58
-
59
- test('build user data multipart with template expression', async () => {
60
- const whoopie = await makeTempDir()
61
- await makeFile('whoopie', 'whoopie', whoopie)
62
- await makeFile(
63
- '1-init-cloud.yml',
64
- `#cloud-config\n\${{ file('${whoopie}/whoopie')}}`,
65
- tmpDir,
66
- )
67
- await makeFile('2-init-cloud.sh', 'cushion', tmpDir)
68
- const boundary = Bun.randomUUIDv7()
69
- expect(
70
- await buildUserData(tmpDir, { attachmentBoundary: boundary }),
71
- ).toStrictEqual(
72
- `Content-Type: multipart/mixed; boundary=${boundary}\r
73
- MIME-Version: 1.0\r
74
- Number-Attachments: 2\r
75
- --${boundary}\r
76
- Content-Type: text/cloud-config; charset="us-ascii"\r
77
- Content-Transfer-Encoding: 7bit\r
78
- Content-Disposition: attachment; filename="1-init-cloud.yml"\r
79
- \r
80
- #cloud-config\nwhoopie\r
81
- --${boundary}\r
82
- Content-Type: text/x-shellscript; charset="us-ascii"\r
83
- Content-Transfer-Encoding: 7bit\r
84
- Content-Disposition: attachment; filename="2-init-cloud.sh"\r
85
- \r
86
- cushion\r
87
- --${boundary}\r
88
- `,
89
- )
90
- })
package/lib/cli.spec.ts DELETED
@@ -1,116 +0,0 @@
1
- import { expect, test } from 'bun:test'
2
- import { parseArgs } from '#c2/cli'
3
-
4
- test('parseArgs with ts entrypoint', () => {
5
- expect(
6
- parseArgs([
7
- '/Users/who/.bun/bin/bun',
8
- '/Users/who/user-data/lib/c2.bin.ts',
9
- 'user_data_dir',
10
- ]),
11
- ).toStrictEqual({
12
- base64: false,
13
- userDataDir: 'user_data_dir',
14
- })
15
- })
16
-
17
- test('parseArgs with executable entrypoint', () => {
18
- expect(
19
- parseArgs([
20
- '/Users/who/.nvm/versions/node/v23.7.0/bin/node',
21
- '/Users/who/.nvm/versions/node/v23.7.0/bin/c2',
22
- 'user_data_dir',
23
- ]),
24
- ).toStrictEqual({
25
- base64: false,
26
- userDataDir: 'user_data_dir',
27
- })
28
- })
29
-
30
- test('parseArgs with js entrypoint', () => {
31
- expect(
32
- parseArgs([
33
- '/Users/who/.nvm/versions/node/v23.7.0/bin/node',
34
- '/Users/who/user-data/lib_js/c2.bin.js',
35
- 'user_data_dir',
36
- ]),
37
- ).toStrictEqual({
38
- base64: false,
39
- userDataDir: 'user_data_dir',
40
- })
41
- })
42
-
43
- test('parseArgs with unexepected argv', () => {
44
- expect(() => parseArgs(['tippity', 'doo', 'da'])).toThrow(
45
- 'unexpected program installation\nplease report at https://github.com/eighty4/c2/issues/new and include:\n\n[\n \"tippity\",\n \"doo\",\n \"da\"\n]',
46
- )
47
- })
48
-
49
- test('parseArgs errors without USER_DATA_DIR', () => {
50
- expect(() =>
51
- parseArgs([
52
- '/Users/who/.bun/bin/bun',
53
- '/Users/who/user-data/lib/c2.bin.ts',
54
- ]),
55
- ).toThrow()
56
- })
57
-
58
- test('parseArgs errors with extra USER_DATA_DIR', () => {
59
- expect(() =>
60
- parseArgs([
61
- '/Users/who/.bun/bin/bun',
62
- '/Users/who/user-data/lib/c2.bin.ts',
63
- 'user_data_dir',
64
- 'some_other_arg',
65
- ]),
66
- ).toThrow()
67
- })
68
-
69
- test('parseArgs with --base64', () => {
70
- expect(
71
- parseArgs([
72
- '/Users/who/.bun/bin/bun',
73
- '/Users/who/user-data/lib/c2.bin.ts',
74
- '--base64',
75
- 'user_data_dir',
76
- ]),
77
- ).toStrictEqual({
78
- base64: true,
79
- userDataDir: 'user_data_dir',
80
- })
81
- })
82
-
83
- test('parseArgs with --http PORT', () => {
84
- expect(
85
- parseArgs([
86
- '/Users/who/.bun/bin/bun',
87
- '/Users/who/user-data/lib/c2.bin.ts',
88
- '--http',
89
- '6666',
90
- 'user_data_dir',
91
- ]),
92
- ).toStrictEqual({ httpPort: 6666, userDataDir: 'user_data_dir' })
93
- })
94
-
95
- test('parseArgs with --http bunk', () => {
96
- expect(() =>
97
- parseArgs([
98
- '/Users/who/.bun/bin/bun',
99
- '/Users/who/user-data/lib/c2.bin.ts',
100
- '--http',
101
- 'bunk',
102
- 'user_data_dir',
103
- ]),
104
- ).toThrow('--http bunk is not a valid http port')
105
- })
106
-
107
- test('parseArgs with --http without PORT', () => {
108
- expect(() =>
109
- parseArgs([
110
- '/Users/who/.bun/bin/bun',
111
- '/Users/who/user-data/lib/c2.bin.ts',
112
- 'user_data_dir',
113
- '--http',
114
- ]),
115
- ).toThrow('--http did not include a PORT')
116
- })
@@ -1,82 +0,0 @@
1
- import { afterAll, afterEach, beforeEach, expect, test } from 'bun:test'
2
- import { join } from 'node:path'
3
- import { evalTemplateExpressions } from './expression.ts'
4
- import { makeFile, makeTempDir, removeDir } from './fs.testing.ts'
5
-
6
- let files: Array<string> = []
7
- let tmpDir: string
8
-
9
- beforeEach(async () => (tmpDir = await makeTempDir()))
10
-
11
- afterEach(async () => await removeDir(tmpDir))
12
-
13
- afterAll(async () => {
14
- for (const p of files) {
15
- await Bun.file(p).delete()
16
- }
17
- })
18
-
19
- test('env() found', async () => {
20
- const envVar = 'C2_TEST_' + Bun.randomUUIDv7().substring(0, 8).toUpperCase()
21
- Bun.env[envVar] = Bun.randomUUIDv7()
22
- expect(await evalTemplateExpressions(`\${{ env('${envVar}') }}`)).toBe(
23
- Bun.env[envVar],
24
- )
25
- delete Bun.env[envVar]
26
- })
27
-
28
- test('env() not found', async () => {
29
- const envVar = 'C2_TEST_' + Bun.randomUUIDv7().substring(0, 8).toUpperCase()
30
- expect(() => evalTemplateExpressions(` \${{ env('${envVar}') }}`)).toThrow(
31
- `env var \`${envVar}\` does not exist`,
32
- )
33
- })
34
-
35
- test('env() name not valid', async () => {
36
- ;['2_NOT_VALID', 'NOT=VALID', 'NOT@VALID'].forEach(envVar =>
37
- expect(() =>
38
- evalTemplateExpressions(`\${{ env('${envVar}') }}`),
39
- ).toThrow(`env var \`${envVar}\` is not a valid name`),
40
- )
41
- })
42
-
43
- test('file() not found', async () => {
44
- const path = join(await makeTempDir(), 'whoopie')
45
- expect(() => evalTemplateExpressions(`\${{ file('${path}') }}`)).toThrow(
46
- `ENOENT: no such file or directory, open '${path}'`,
47
- )
48
- })
49
-
50
- test('file() absolute', async () => {
51
- const content = Bun.randomUUIDv7()
52
- const path = await makeFile('.user-data', content, tmpDir)
53
- expect(await evalTemplateExpressions(`\${{ file('${path}') }}`)).toBe(
54
- content,
55
- )
56
- })
57
-
58
- test('file() home', async () => {
59
- const content = Bun.randomUUIDv7()
60
- const filename = `.user-data.${Bun.randomUUIDv7()}`
61
- const path = join(Bun.env.HOME!, filename)
62
- await makeFile(path, content)
63
- files.push(path)
64
- expect(await evalTemplateExpressions(`\${{ file('~/${filename}') }}`)).toBe(
65
- content,
66
- )
67
- })
68
-
69
- test('file() relative', async () => {
70
- const content = Bun.randomUUIDv7()
71
- const filename = `.user-data.${Bun.randomUUIDv7()}`
72
- await makeFile(filename, content, tmpDir)
73
- const prevPwd = process.cwd()
74
- process.chdir(tmpDir)
75
- try {
76
- expect(
77
- await evalTemplateExpressions(`\${{ file('${filename}') }}`),
78
- ).toBe(content)
79
- } finally {
80
- process.chdir(prevPwd)
81
- }
82
- })
package/lib/http.spec.ts DELETED
@@ -1,57 +0,0 @@
1
- import { beforeEach, expect, test } from 'bun:test'
2
- import { MultipartMessage, MultipartAttachment } from '#c2/http'
3
-
4
- let message: MultipartMessage
5
-
6
- beforeEach(() => {
7
- message = new MultipartMessage(
8
- [
9
- {
10
- path: 'upgrades',
11
- content: '#cloud-config\nupgrades',
12
- filename: 'upgrades.yml',
13
- source: '#cloud-config\nupgrades',
14
- type: 'cloud-config',
15
- },
16
- {
17
- path: 'security',
18
- content: 'security',
19
- filename: 'security.sh',
20
- source: 'security',
21
- type: 'x-shellscript',
22
- },
23
- ],
24
- 'BOUNDARY',
25
- )
26
- })
27
-
28
- test('multipart message creates cloud-init payload', () => {
29
- expect(message.toHTTP()).toStrictEqual(
30
- `Content-Type: multipart/mixed; boundary=BOUNDARY\r
31
- MIME-Version: 1.0\r
32
- Number-Attachments: 2\r
33
- --BOUNDARY\r
34
- Content-Type: text/cloud-config; charset="us-ascii"\r
35
- Content-Transfer-Encoding: 7bit\r
36
- Content-Disposition: attachment; filename="upgrades.yml"\r
37
- \r
38
- #cloud-config
39
- upgrades\r
40
- --BOUNDARY\r
41
- Content-Type: text/x-shellscript; charset="us-ascii"\r
42
- Content-Transfer-Encoding: 7bit\r
43
- Content-Disposition: attachment; filename="security.sh"\r
44
- \r
45
- security\r
46
- --BOUNDARY\r
47
- `,
48
- )
49
- })
50
-
51
- test('multipart message creates HTTP headers', () => {
52
- expect(message.headers).toStrictEqual({
53
- 'Content-Type': 'multipart/mixed; boundary=BOUNDARY',
54
- 'MIME-Version': '1.0',
55
- 'Number-Attachments': '2',
56
- })
57
- })