giget 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## Features
11
11
 
12
- ✔ Support popular git providers (GitHub, GitLab, and Bitbucket) out of the box.
12
+ ✔ Support popular git providers (GitHub, GitLab, Bitbucket, Sourcehut) out of the box.
13
13
 
14
14
  ✔ Built-in and custom [template registry](#template-registry).
15
15
 
@@ -21,6 +21,8 @@
21
21
 
22
22
  ✔ Support extracting with a subdir.
23
23
 
24
+ ✔ Authorization support to download private templates
25
+
24
26
  ## Usage (CLI)
25
27
 
26
28
  ```bash
@@ -39,13 +41,18 @@ npx giget@latest <template> [<dir>] [...options]
39
41
  - `--prefer-offline`: Use cache if exists otherwise try to download.
40
42
  - `--force-clean`: ⚠️ Remove any existing directory or file recusively before cloning.
41
43
  - `--shell`: ⚠️ Open a new shell with current working directory in cloned dir. (Experimental).
42
- - `--registry`: URL to a custom registry.
44
+ - `--registry`: URL to a custom registry. (Can be overriden with `GIGET_REGISTRY` environment variable).
43
45
  - `--no-registry`: Disable registry lookup and functionality.
44
46
  - `--verbose`: Show verbose debugging info.
47
+ - `--cwd`: Set current working directory to resolve dirs relative to it.
48
+ - `--auth`: Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable).
45
49
 
46
50
  ### Examples
47
51
 
48
52
  ```sh
53
+ # Clone nuxt starter from giget template registry
54
+ npx giget@latest nuxt
55
+
49
56
  # Clone the main branch of github.com/unjs/template to unjs-template directory
50
57
  npx giget@latest gh:unjs/template
51
58
 
@@ -64,8 +71,8 @@ npx giget@latest gitlab:unjs/template
64
71
  # Clone from bitbucket
65
72
  npx giget@latest bitbucket:unjs/template
66
73
 
67
- # Clone nuxt starter from giget template registry
68
- npx giget@latest nuxt
74
+ # Clone from sourcehut
75
+ npx giget@latest sourcehut:pi0/unjs-template
69
76
  ```
70
77
 
71
78
  ## Template Registry
@@ -78,11 +85,12 @@ If you want to add your template to the built-in registry, just drop a PR to add
78
85
 
79
86
  A custom registry should provide an endpoint with dynamic path `/:template.json` that returns a JSON response with keys same as [custom providers](#custom-providers).
80
87
 
81
- - `name`: (required) Name of the template.
82
- - `tar` (required) Link to the tar download link.
83
- - `defaultDir`: (optional) Default cloning directory.
84
- - `url`: (optional) Webpage of the template.
85
- - `subpath` (optional) Subpath inside the tar file.
88
+ - `name`: (required) Name of the template.
89
+ - `tar` (required) Link to the tar download link.
90
+ - `defaultDir`: (optional) Default cloning directory.
91
+ - `url`: (optional) Webpage of the template.
92
+ - `subpath`: (optional) Subpath inside the tar file.
93
+ - `headers`: (optional) Custom headers to send while downloading template.
86
94
 
87
95
  Because of the simplicity, you can even use a github repository as template registry but also you can build something more powerful by bringing your own API.
88
96
 
@@ -124,7 +132,7 @@ const { source, dir } = await downloadTemplate('github:unjs/template')
124
132
  - `source`: (string) Input source in format of `[provider]:repo[/subpath][#ref]`.
125
133
  - `dir`: (string) Destination directory to clone to. If not provided, `user-name` will be used relative to the current directory.
126
134
  - `options`: (object) Options are usually inferred from the input string. You can customize them.
127
- - `provider`: (string) Either `github`, `gitlab` or `bitbucket`. The default is `github`.
135
+ - `provider`: (string) Either `github`, `gitlab`, `bitbucket` or `sourcehut`. The default is `github`.
128
136
  - `repo`: (string) Name of repository in format of `{username}/{reponame}`.
129
137
  - `ref`: (string) Git ref (branch or commit or tag). The default value is `main`.
130
138
  - `subdirpath`: (string) subdir of the repo to clone from. The default value is none.
@@ -133,7 +141,9 @@ const { source, dir } = await downloadTemplate('github:unjs/template')
133
141
  - `offline`: (boolean) Do not attempt to download and use cached version.
134
142
  - `preferOffline`: (boolean) Use cache if exists otherwise try to download.
135
143
  - `providers`: (object) A map from provider name to custom providers. Can be used to override built-ins too.
136
- - `registry`: (string or false) Set to `false` to disable registry. Set to a URL string (without trailing slash) for custom registry.
144
+ - `registry`: (string or false) Set to `false` to disable registry. Set to a URL string (without trailing slash) for custom registry. (Can be overriden with `GIGET_REGISTRY` environment variable).
145
+ - `cwd`: (string) Current working directory to resolve dirs relative to it.
146
+ - `auth`: (string) Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable).
137
147
 
138
148
  **Return value:**
139
149
 
@@ -151,10 +161,11 @@ Using programmatic method, you can make your own custom template providers.
151
161
  ```ts
152
162
  import type { TemplateProvider } from 'giget'
153
163
 
154
- const rainbow: TemplateProvider = async (input) => {
164
+ const rainbow: TemplateProvider = async (input, { auth }) => {
155
165
  return {
156
166
  name: 'rainbow',
157
167
  version: input,
168
+ headers: { Authorization: auth },
158
169
  url: `https://rainbow.template/?variant=${input}`,
159
170
  tar: `https://rainbow.template/dl/rainbow.${input}.tar.gz`
160
171
  }
@@ -175,19 +186,20 @@ const themes = registryProvider('https://raw.githubusercontent.com/unjs/giget/ma
175
186
  const { source, dir } = await downloadRepo('themes:test', { providers: { themes } })
176
187
  ```
177
188
 
178
- ## 💻 Development
179
-
180
- - Clone this repository
181
- - Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
182
- - Install dependencies using `pnpm install`
183
- - Run interactive tests using `pnpm dev`
184
-
185
189
  ## Related projects
186
190
 
191
+ Giget wouldn't be possible without inspering from former projects. In comparation giget does not depend on any local command which increases stability and performance, supports custom template providers, auth and many more features out of the box.
192
+
187
193
  - https://github.com/samsonjs/gitter
188
194
  - https://github.com/tiged/tiged
189
195
  - https://github.com/Rich-Harris/degit
190
196
 
197
+ ## 💻 Development
198
+
199
+ - Clone this repository
200
+ - Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable` (use `npm i -g corepack` for Node.js < 16.10)
201
+ - Install dependencies using `pnpm install`
202
+ - Run interactive tests using `pnpm dev`
191
203
 
192
204
  ## License
193
205
 
@@ -196,14 +208,12 @@ Made with 💛
196
208
  Published under [MIT License](./LICENSE).
197
209
 
198
210
  <!-- Badges -->
211
+
199
212
  [npm-version-src]: https://img.shields.io/npm/v/giget?style=flat-square
200
213
  [npm-version-href]: https://npmjs.com/package/giget
201
-
202
214
  [npm-downloads-src]: https://img.shields.io/npm/dm/giget?style=flat-square
203
215
  [npm-downloads-href]: https://npmjs.com/package/giget
204
-
205
216
  [github-actions-src]: https://img.shields.io/github/workflow/status/unjs/giget/ci/main?style=flat-square
206
217
  [github-actions-href]: https://github.com/unjs/giget/actions?query=workflow%3Aci
207
-
208
218
  [codecov-src]: https://img.shields.io/codecov/c/gh/unjs/giget/main?style=flat-square
209
219
  [codecov-href]: https://codecov.io/gh/unjs/giget
package/dist/cli.cjs CHANGED
@@ -4,14 +4,16 @@
4
4
  const node_path = require('node:path');
5
5
  const mri = require('mri');
6
6
  const colorette = require('colorette');
7
- const giget = require('./shared/giget.774476cb.cjs');
7
+ const giget = require('./shared/giget.3522139c.cjs');
8
8
  require('node:fs/promises');
9
9
  require('node:os');
10
10
  require('node:fs');
11
11
  require('tar');
12
12
  require('pathe');
13
- require('node:stream/promises');
13
+ require('defu');
14
+ require('node:stream');
14
15
  require('node:child_process');
16
+ require('node:util');
15
17
  require('node-fetch-native');
16
18
 
17
19
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
@@ -21,12 +23,12 @@ const mri__default = /*#__PURE__*/_interopDefaultLegacy(mri);
21
23
  async function main() {
22
24
  const args = mri__default(process.argv.slice(2), {
23
25
  boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "verbose"],
24
- string: ["registry"]
26
+ string: ["registry", "cwd", "auth"]
25
27
  });
26
28
  const input = args._[0];
27
29
  const dir = args._[1];
28
30
  if (!input || args.help || args.h) {
29
- console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose]");
31
+ console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose] [--cwd] [--auth]");
30
32
  process.exit(1);
31
33
  }
32
34
  if (args.verbose) {
@@ -37,7 +39,9 @@ async function main() {
37
39
  force: args.force,
38
40
  forceClean: args["force-clean"],
39
41
  offline: args.offline,
40
- registry: args.registry
42
+ registry: args.registry,
43
+ cwd: args.cwd,
44
+ auth: args.auth
41
45
  });
42
46
  console.log(`\u2728 Successfully cloned ${colorette.cyan(r.name || r.url)} to ${colorette.cyan(node_path.relative(process.cwd(), r.dir))}
43
47
  `);
package/dist/cli.mjs CHANGED
@@ -2,25 +2,27 @@
2
2
  import { relative } from 'node:path';
3
3
  import mri from 'mri';
4
4
  import { cyan } from 'colorette';
5
- import { d as downloadTemplate, s as startShell } from './shared/giget.1430f5a2.mjs';
5
+ import { d as downloadTemplate, s as startShell } from './shared/giget.dd19862e.mjs';
6
6
  import 'node:fs/promises';
7
7
  import 'node:os';
8
8
  import 'node:fs';
9
9
  import 'tar';
10
10
  import 'pathe';
11
- import 'node:stream/promises';
11
+ import 'defu';
12
+ import 'node:stream';
12
13
  import 'node:child_process';
14
+ import 'node:util';
13
15
  import 'node-fetch-native';
14
16
 
15
17
  async function main() {
16
18
  const args = mri(process.argv.slice(2), {
17
19
  boolean: ["help", "force", "force-clean", "offline", "prefer-offline", "shell", "verbose"],
18
- string: ["registry"]
20
+ string: ["registry", "cwd", "auth"]
19
21
  });
20
22
  const input = args._[0];
21
23
  const dir = args._[1];
22
24
  if (!input || args.help || args.h) {
23
- console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose]");
25
+ console.error("Usage: npx getgit@latest <input> [<dir>] [--force] [--force-clean] [--offline] [--prefer-offline] [--shell] [--registry] [--no-registry] [--verbose] [--cwd] [--auth]");
24
26
  process.exit(1);
25
27
  }
26
28
  if (args.verbose) {
@@ -31,7 +33,9 @@ async function main() {
31
33
  force: args.force,
32
34
  forceClean: args["force-clean"],
33
35
  offline: args.offline,
34
- registry: args.registry
36
+ registry: args.registry,
37
+ cwd: args.cwd,
38
+ auth: args.auth
35
39
  });
36
40
  console.log(`\u2728 Successfully cloned ${cyan(r.name || r.url)} to ${cyan(relative(process.cwd(), r.dir))}
37
41
  `);
package/dist/index.cjs CHANGED
@@ -2,14 +2,16 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const giget = require('./shared/giget.774476cb.cjs');
5
+ const giget = require('./shared/giget.3522139c.cjs');
6
6
  require('node:fs/promises');
7
7
  require('node:os');
8
8
  require('node:fs');
9
9
  require('tar');
10
10
  require('pathe');
11
- require('node:stream/promises');
11
+ require('defu');
12
+ require('node:stream');
12
13
  require('node:child_process');
14
+ require('node:util');
13
15
  require('node-fetch-native');
14
16
 
15
17
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  interface GitInfo {
2
- provider: 'github' | 'gitlab' | 'bitbucket';
2
+ provider: 'github' | 'gitlab' | 'bitbucket' | 'sourcehut';
3
3
  repo: string;
4
4
  subdir: string;
5
5
  ref: string;
@@ -11,11 +11,14 @@ interface TemplateInfo {
11
11
  subdir?: string;
12
12
  url?: string;
13
13
  defaultDir?: string;
14
+ headers?: Record<string, string>;
14
15
  source?: never;
15
16
  dir?: never;
16
17
  [key: string]: any;
17
18
  }
18
- declare type TemplateProvider = (input: string) => TemplateInfo | Promise<TemplateInfo> | null;
19
+ declare type TemplateProvider = (input: string, options: {
20
+ auth?: string;
21
+ }) => TemplateInfo | Promise<TemplateInfo> | null;
19
22
 
20
23
  interface DownloadTemplateOptions {
21
24
  provider?: string;
@@ -26,20 +29,17 @@ interface DownloadTemplateOptions {
26
29
  providers?: Record<string, TemplateProvider>;
27
30
  dir?: string;
28
31
  registry?: false | string;
32
+ cwd?: string;
33
+ auth?: string;
29
34
  }
30
- declare function downloadTemplate(input: string, opts?: DownloadTemplateOptions): Promise<{
31
- source: string;
35
+ declare type DownloadTemplateResult = Omit<TemplateInfo, 'dir' | 'source'> & {
32
36
  dir: string;
33
- name: string;
34
- tar: string;
35
- version?: string;
36
- subdir?: string;
37
- url?: string;
38
- defaultDir?: string;
39
- }>;
37
+ source: string;
38
+ };
39
+ declare function downloadTemplate(input: string, opts?: DownloadTemplateOptions): Promise<DownloadTemplateResult>;
40
40
 
41
41
  declare const registryProvider: (registryEndpoint?: string) => TemplateProvider;
42
42
 
43
43
  declare function startShell(cwd: string): void;
44
44
 
45
- export { DownloadTemplateOptions, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, registryProvider, startShell };
45
+ export { DownloadTemplateOptions, DownloadTemplateResult, GitInfo, TemplateInfo, TemplateProvider, downloadTemplate, registryProvider, startShell };
package/dist/index.mjs CHANGED
@@ -1,9 +1,11 @@
1
- export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.1430f5a2.mjs';
1
+ export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.dd19862e.mjs';
2
2
  import 'node:fs/promises';
3
3
  import 'node:os';
4
4
  import 'node:fs';
5
5
  import 'tar';
6
6
  import 'pathe';
7
- import 'node:stream/promises';
7
+ import 'defu';
8
+ import 'node:stream';
8
9
  import 'node:child_process';
10
+ import 'node:util';
9
11
  import 'node-fetch-native';
@@ -5,29 +5,31 @@ const node_os = require('node:os');
5
5
  const node_fs = require('node:fs');
6
6
  const tar = require('tar');
7
7
  const pathe = require('pathe');
8
- const promises$1 = require('node:stream/promises');
8
+ const defu = require('defu');
9
+ const node_stream = require('node:stream');
9
10
  const node_child_process = require('node:child_process');
11
+ const node_util = require('node:util');
10
12
  const fetch = require('node-fetch-native');
11
13
 
12
14
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
13
15
 
14
16
  const fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
15
17
 
16
- async function download(url, filePath) {
18
+ async function download(url, filePath, opts = {}) {
17
19
  const infoPath = filePath + ".json";
18
20
  const info = JSON.parse(await promises.readFile(infoPath, "utf8").catch(() => "{}"));
19
- const headRes = await fetch.fetch(url, { method: "HEAD" }).catch(() => null);
21
+ const headRes = await fetch.fetch(url, { method: "HEAD", headers: opts.headers }).catch(() => null);
20
22
  const etag = headRes?.headers.get("etag");
21
23
  if (info.etag === etag && node_fs.existsSync(filePath)) {
22
24
  return;
23
25
  }
24
26
  info.etag = etag;
25
- const res = await fetch.fetch(url);
27
+ const res = await fetch.fetch(url, { headers: opts.headers });
26
28
  if (res.status >= 400) {
27
29
  throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
28
30
  }
29
31
  const stream = node_fs.createWriteStream(filePath);
30
- await promises$1.pipeline(res.body, stream);
32
+ await node_util.promisify(node_stream.pipeline)(res.body, stream);
31
33
  await promises.writeFile(infoPath, JSON.stringify(info), "utf8");
32
34
  }
33
35
  const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
@@ -64,41 +66,56 @@ function startShell(cwd) {
64
66
  });
65
67
  }
66
68
 
67
- const github = (input) => {
69
+ const github = (input, opts) => {
68
70
  const parsed = parseGitURI(input);
69
71
  return {
70
72
  name: parsed.repo.replace("/", "-"),
71
73
  version: parsed.ref,
72
74
  subdir: parsed.subdir,
75
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
73
76
  url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
74
77
  tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
75
78
  };
76
79
  };
77
- const gitlab = (input) => {
80
+ const gitlab = (input, opts) => {
78
81
  const parsed = parseGitURI(input);
79
82
  return {
80
83
  name: parsed.repo.replace("/", "-"),
81
84
  version: parsed.ref,
82
85
  subdir: parsed.subdir,
86
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
83
87
  url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
84
88
  tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
85
89
  };
86
90
  };
87
- const bitbucket = (input) => {
91
+ const bitbucket = (input, opts) => {
88
92
  const parsed = parseGitURI(input);
89
93
  return {
90
94
  name: parsed.repo.replace("/", "-"),
91
95
  version: parsed.ref,
92
96
  subdir: parsed.subdir,
97
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
93
98
  url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
94
99
  tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
95
100
  };
96
101
  };
102
+ const sourcehut = (input, opts) => {
103
+ const parsed = parseGitURI(input);
104
+ return {
105
+ name: parsed.repo.replace("/", "-"),
106
+ version: parsed.ref,
107
+ subdir: parsed.subdir,
108
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
109
+ url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`,
110
+ tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz`
111
+ };
112
+ };
97
113
  const providers = {
98
114
  github,
99
115
  gh: github,
100
116
  gitlab,
101
- bitbucket
117
+ bitbucket,
118
+ sourcehut
102
119
  };
103
120
 
104
121
  const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
@@ -121,6 +138,10 @@ const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
121
138
 
122
139
  const sourceProtoRe = /^([\w-.]+):/;
123
140
  async function downloadTemplate(input, opts = {}) {
141
+ opts = defu.defu({
142
+ registry: process.env.GIGET_REGISTRY,
143
+ auth: process.env.GIGET_AUTH
144
+ }, opts);
124
145
  const registry = opts.registry !== false ? registryProvider(opts.registry) : null;
125
146
  let providerName = opts.provider || (registryProvider ? "registry" : "github");
126
147
  let source = input;
@@ -133,12 +154,13 @@ async function downloadTemplate(input, opts = {}) {
133
154
  if (!provider) {
134
155
  throw new Error(`Unsupported provider: ${providerName}`);
135
156
  }
136
- const template = await Promise.resolve().then(() => provider(source)).catch((err) => {
157
+ const template = await Promise.resolve().then(() => provider(source, { auth: opts.auth })).catch((err) => {
137
158
  throw new Error(`Failed to download template from ${providerName}: ${err.message}`);
138
159
  });
139
160
  template.name = (template.name || "template").replace(/[^a-z0-9-]/gi, "-");
140
161
  template.defaultDir = (template.defaultDir || template.name).replace(/[^a-z0-9-]/gi, "-");
141
- const extractPath = pathe.resolve(opts.dir || template.defaultDir);
162
+ const cwd = pathe.resolve(opts.cwd || ".");
163
+ const extractPath = pathe.resolve(cwd, opts.dir || template.defaultDir);
142
164
  if (opts.forceClean) {
143
165
  await promises.rm(extractPath, { recursive: true, force: true });
144
166
  }
@@ -154,7 +176,7 @@ async function downloadTemplate(input, opts = {}) {
154
176
  if (!opts.offline) {
155
177
  await promises.mkdir(pathe.dirname(tarPath), { recursive: true });
156
178
  const s2 = Date.now();
157
- await download(template.tar, tarPath).catch((err) => {
179
+ await download(template.tar, tarPath, { headers: template.headers }).catch((err) => {
158
180
  if (!node_fs.existsSync(tarPath)) {
159
181
  throw err;
160
182
  }
@@ -174,7 +196,7 @@ async function downloadTemplate(input, opts = {}) {
174
196
  onentry(entry) {
175
197
  entry.path = entry.path.split("/").splice(1).join("/");
176
198
  if (subdir) {
177
- if (entry.path.startsWith(subdir)) {
199
+ if (entry.path.startsWith(subdir + "/")) {
178
200
  entry.path = entry.path.substring(subdir.length);
179
201
  } else {
180
202
  entry.path = "";
@@ -3,25 +3,27 @@ import { homedir } from 'node:os';
3
3
  import { existsSync, createWriteStream, readdirSync } from 'node:fs';
4
4
  import { extract } from 'tar';
5
5
  import { resolve, relative, dirname } from 'pathe';
6
- import { pipeline } from 'node:stream/promises';
6
+ import { defu } from 'defu';
7
+ import { pipeline } from 'node:stream';
7
8
  import { spawnSync } from 'node:child_process';
9
+ import { promisify } from 'node:util';
8
10
  import fetch$1, { fetch } from 'node-fetch-native';
9
11
 
10
- async function download(url, filePath) {
12
+ async function download(url, filePath, opts = {}) {
11
13
  const infoPath = filePath + ".json";
12
14
  const info = JSON.parse(await readFile(infoPath, "utf8").catch(() => "{}"));
13
- const headRes = await fetch(url, { method: "HEAD" }).catch(() => null);
15
+ const headRes = await fetch(url, { method: "HEAD", headers: opts.headers }).catch(() => null);
14
16
  const etag = headRes?.headers.get("etag");
15
17
  if (info.etag === etag && existsSync(filePath)) {
16
18
  return;
17
19
  }
18
20
  info.etag = etag;
19
- const res = await fetch(url);
21
+ const res = await fetch(url, { headers: opts.headers });
20
22
  if (res.status >= 400) {
21
23
  throw new Error(`Failed to download ${url}: ${res.status} ${res.statusText}`);
22
24
  }
23
25
  const stream = createWriteStream(filePath);
24
- await pipeline(res.body, stream);
26
+ await promisify(pipeline)(res.body, stream);
25
27
  await writeFile(infoPath, JSON.stringify(info), "utf8");
26
28
  }
27
29
  const inputRegex = /^(?<repo>[\w.-]+\/[\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\w.-]+)?/;
@@ -58,41 +60,56 @@ function startShell(cwd) {
58
60
  });
59
61
  }
60
62
 
61
- const github = (input) => {
63
+ const github = (input, opts) => {
62
64
  const parsed = parseGitURI(input);
63
65
  return {
64
66
  name: parsed.repo.replace("/", "-"),
65
67
  version: parsed.ref,
66
68
  subdir: parsed.subdir,
69
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
67
70
  url: `https://github.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
68
71
  tar: `https://github.com/${parsed.repo}/archive/${parsed.ref}.tar.gz`
69
72
  };
70
73
  };
71
- const gitlab = (input) => {
74
+ const gitlab = (input, opts) => {
72
75
  const parsed = parseGitURI(input);
73
76
  return {
74
77
  name: parsed.repo.replace("/", "-"),
75
78
  version: parsed.ref,
76
79
  subdir: parsed.subdir,
80
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
77
81
  url: `https://gitlab.com/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`,
78
82
  tar: `https://gitlab.com/${parsed.repo}/-/archive/${parsed.ref}.tar.gz`
79
83
  };
80
84
  };
81
- const bitbucket = (input) => {
85
+ const bitbucket = (input, opts) => {
82
86
  const parsed = parseGitURI(input);
83
87
  return {
84
88
  name: parsed.repo.replace("/", "-"),
85
89
  version: parsed.ref,
86
90
  subdir: parsed.subdir,
91
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
87
92
  url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`,
88
93
  tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz`
89
94
  };
90
95
  };
96
+ const sourcehut = (input, opts) => {
97
+ const parsed = parseGitURI(input);
98
+ return {
99
+ name: parsed.repo.replace("/", "-"),
100
+ version: parsed.ref,
101
+ subdir: parsed.subdir,
102
+ headers: { Authorization: opts.auth ? `Bearer ${opts.auth}` : void 0 },
103
+ url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`,
104
+ tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz`
105
+ };
106
+ };
91
107
  const providers = {
92
108
  github,
93
109
  gh: github,
94
110
  gitlab,
95
- bitbucket
111
+ bitbucket,
112
+ sourcehut
96
113
  };
97
114
 
98
115
  const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates";
@@ -115,6 +132,10 @@ const registryProvider = (registryEndpoint = DEFAULT_REGISTRY) => {
115
132
 
116
133
  const sourceProtoRe = /^([\w-.]+):/;
117
134
  async function downloadTemplate(input, opts = {}) {
135
+ opts = defu({
136
+ registry: process.env.GIGET_REGISTRY,
137
+ auth: process.env.GIGET_AUTH
138
+ }, opts);
118
139
  const registry = opts.registry !== false ? registryProvider(opts.registry) : null;
119
140
  let providerName = opts.provider || (registryProvider ? "registry" : "github");
120
141
  let source = input;
@@ -127,12 +148,13 @@ async function downloadTemplate(input, opts = {}) {
127
148
  if (!provider) {
128
149
  throw new Error(`Unsupported provider: ${providerName}`);
129
150
  }
130
- const template = await Promise.resolve().then(() => provider(source)).catch((err) => {
151
+ const template = await Promise.resolve().then(() => provider(source, { auth: opts.auth })).catch((err) => {
131
152
  throw new Error(`Failed to download template from ${providerName}: ${err.message}`);
132
153
  });
133
154
  template.name = (template.name || "template").replace(/[^a-z0-9-]/gi, "-");
134
155
  template.defaultDir = (template.defaultDir || template.name).replace(/[^a-z0-9-]/gi, "-");
135
- const extractPath = resolve(opts.dir || template.defaultDir);
156
+ const cwd = resolve(opts.cwd || ".");
157
+ const extractPath = resolve(cwd, opts.dir || template.defaultDir);
136
158
  if (opts.forceClean) {
137
159
  await rm(extractPath, { recursive: true, force: true });
138
160
  }
@@ -148,7 +170,7 @@ async function downloadTemplate(input, opts = {}) {
148
170
  if (!opts.offline) {
149
171
  await mkdir(dirname(tarPath), { recursive: true });
150
172
  const s2 = Date.now();
151
- await download(template.tar, tarPath).catch((err) => {
173
+ await download(template.tar, tarPath, { headers: template.headers }).catch((err) => {
152
174
  if (!existsSync(tarPath)) {
153
175
  throw err;
154
176
  }
@@ -168,7 +190,7 @@ async function downloadTemplate(input, opts = {}) {
168
190
  onentry(entry) {
169
191
  entry.path = entry.path.split("/").splice(1).join("/");
170
192
  if (subdir) {
171
- if (entry.path.startsWith(subdir)) {
193
+ if (entry.path.startsWith(subdir + "/")) {
172
194
  entry.path = entry.path.substring(subdir.length);
173
195
  } else {
174
196
  entry.path = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "giget",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Download templates and git repositories with pleasure!",
5
5
  "repository": "unjs/giget",
6
6
  "license": "MIT",
@@ -23,24 +23,25 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "colorette": "^2.0.19",
26
+ "defu": "^6.1.0",
26
27
  "mri": "^1.2.0",
27
28
  "node-fetch-native": "^0.1.4",
28
- "pathe": "^0.3.7",
29
+ "pathe": "^0.3.8",
29
30
  "tar": "^6.1.11"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@nuxtjs/eslint-config-typescript": "^11.0.0",
33
34
  "@types/node": "^18.7.16",
34
35
  "@types/tar": "^6.1.2",
35
- "@vitest/coverage-c8": "^0.23.2",
36
- "eslint": "^8.23.0",
37
- "jiti": "^1.15.0",
36
+ "@vitest/coverage-c8": "^0.23.4",
37
+ "eslint": "^8.23.1",
38
+ "jiti": "^1.16.0",
38
39
  "standard-version": "^9.5.0",
39
40
  "typescript": "^4.8.3",
40
- "unbuild": "^0.8.10",
41
- "vitest": "^0.23.2"
41
+ "unbuild": "^0.8.11",
42
+ "vitest": "^0.23.4"
42
43
  },
43
- "packageManager": "pnpm@7.11.0",
44
+ "packageManager": "pnpm@7.12.0",
44
45
  "scripts": {
45
46
  "build": "unbuild",
46
47
  "dev": "vitest dev",