alpic 0.0.0-dev.added1b → 0.0.0-dev.adefca3

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 (82) hide show
  1. package/dist/__tests__/auth.e2e.test.d.ts +1 -0
  2. package/dist/__tests__/auth.e2e.test.js +142 -0
  3. package/dist/__tests__/auth.e2e.test.js.map +1 -0
  4. package/dist/__tests__/deploy-flags.e2e.test.d.ts +1 -0
  5. package/dist/__tests__/deploy-flags.e2e.test.js +87 -0
  6. package/dist/__tests__/deploy-flags.e2e.test.js.map +1 -0
  7. package/dist/__tests__/deploy.e2e.test.js +36 -53
  8. package/dist/__tests__/deploy.e2e.test.js.map +1 -1
  9. package/dist/__tests__/git.e2e.test.js +51 -13
  10. package/dist/__tests__/git.e2e.test.js.map +1 -1
  11. package/dist/__tests__/mock-server.js +60 -3
  12. package/dist/__tests__/mock-server.js.map +1 -1
  13. package/dist/__tests__/utils.d.ts +15 -1
  14. package/dist/__tests__/utils.js +71 -2
  15. package/dist/__tests__/utils.js.map +1 -1
  16. package/dist/api.d.ts +0 -1
  17. package/dist/api.js +5 -9
  18. package/dist/api.js.map +1 -1
  19. package/dist/commands/deploy.d.ts +6 -0
  20. package/dist/commands/deploy.js +41 -13
  21. package/dist/commands/deploy.js.map +1 -1
  22. package/dist/commands/git/connect.js +5 -11
  23. package/dist/commands/git/connect.js.map +1 -1
  24. package/dist/commands/git/disconnect.js +5 -9
  25. package/dist/commands/git/disconnect.js.map +1 -1
  26. package/dist/commands/git.js +1 -1
  27. package/dist/commands/git.js.map +1 -1
  28. package/dist/commands/login.d.ts +6 -0
  29. package/dist/commands/login.js +39 -0
  30. package/dist/commands/login.js.map +1 -0
  31. package/dist/commands/logout.d.ts +6 -0
  32. package/dist/commands/logout.js +20 -0
  33. package/dist/commands/logout.js.map +1 -0
  34. package/dist/commands/whoami.d.ts +6 -0
  35. package/dist/commands/whoami.js +25 -0
  36. package/dist/commands/whoami.js.map +1 -0
  37. package/dist/env.d.ts +4 -0
  38. package/dist/env.js +10 -0
  39. package/dist/env.js.map +1 -0
  40. package/dist/lib/alpic-command.js +0 -3
  41. package/dist/lib/alpic-command.js.map +1 -1
  42. package/dist/lib/auth/auth.d.ts +2 -0
  43. package/dist/lib/auth/auth.js +21 -0
  44. package/dist/lib/auth/auth.js.map +1 -0
  45. package/dist/lib/auth/oauth/client.d.ts +28 -0
  46. package/dist/lib/auth/oauth/client.js +110 -0
  47. package/dist/lib/auth/oauth/client.js.map +1 -0
  48. package/dist/lib/auth/oauth/constants.d.ts +2 -0
  49. package/dist/lib/auth/oauth/constants.js +3 -0
  50. package/dist/lib/auth/oauth/constants.js.map +1 -0
  51. package/dist/lib/auth/oauth/server/assets/alpic-mountain.png +0 -0
  52. package/dist/lib/auth/oauth/server/assets/authorize.html +195 -0
  53. package/dist/lib/auth/oauth/server/assets/callback.html +88 -0
  54. package/dist/lib/auth/oauth/server/index.d.ts +8 -0
  55. package/dist/lib/auth/oauth/server/index.js +103 -0
  56. package/dist/lib/auth/oauth/server/index.js.map +1 -0
  57. package/dist/lib/auth/whoami.d.ts +28 -0
  58. package/dist/lib/auth/whoami.js +35 -0
  59. package/dist/lib/auth/whoami.js.map +1 -0
  60. package/dist/lib/base-workflow.d.ts +10 -0
  61. package/dist/lib/base-workflow.js +21 -0
  62. package/dist/lib/base-workflow.js.map +1 -0
  63. package/dist/lib/deployment.d.ts +3 -3
  64. package/dist/lib/deployment.js +24 -8
  65. package/dist/lib/deployment.js.map +1 -1
  66. package/dist/lib/git.js +2 -3
  67. package/dist/lib/git.js.map +1 -1
  68. package/dist/lib/global-store.d.ts +28 -0
  69. package/dist/lib/global-store.js +75 -0
  70. package/dist/lib/global-store.js.map +1 -0
  71. package/dist/lib/project.d.ts +59 -61
  72. package/dist/lib/project.js +252 -254
  73. package/dist/lib/project.js.map +1 -1
  74. package/dist/lib/telemetry.js +6 -6
  75. package/dist/lib/telemetry.js.map +1 -1
  76. package/package.json +25 -18
  77. package/dist/lib/auth.d.ts +0 -1
  78. package/dist/lib/auth.js +0 -10
  79. package/dist/lib/auth.js.map +0 -1
  80. package/dist/lib/global-config.d.ts +0 -9
  81. package/dist/lib/global-config.js +0 -48
  82. package/dist/lib/global-config.js.map +0 -1
@@ -1,12 +1,11 @@
1
1
  import * as p from "@clack/prompts";
2
- import { Args, Command } from "@oclif/core";
2
+ import { Args } from "@oclif/core";
3
3
  import chalk from "chalk";
4
4
  import { api } from "../../api.js";
5
5
  import { AlpicCommand } from "../../lib/alpic-command.js";
6
- import { ensureApiKey } from "../../lib/auth.js";
6
+ import { isAuthenticated } from "../../lib/auth/auth.js";
7
7
  import { config } from "../../lib/config.js";
8
- import { isGitRepository, listGithubRemotes } from "../../lib/git.js";
9
- import { resolveDeployDir } from "../../lib/project.js";
8
+ import { resolveDeployDir } from "../../lib/deployment.js";
10
9
  export default class GitDisconnect extends AlpicCommand {
11
10
  static description = "Disconnect a linked Alpic project from its git remote source";
12
11
  static examples = ["<%= config.bin %> git disconnect", "<%= config.bin %> git disconnect ./my-app"];
@@ -19,21 +18,19 @@ export default class GitDisconnect extends AlpicCommand {
19
18
  async run() {
20
19
  const { args } = await this.parse(GitDisconnect);
21
20
  p.intro("Disconnecting git repository from Alpic");
22
- if (!ensureApiKey()) {
23
- this.exit(1);
21
+ if (!(await isAuthenticated())) {
22
+ p.cancel("Not authenticated. Run `alpic login` or set ALPIC_API_KEY. Get an API key from Team settings in the Alpic dashboard.");
24
23
  return;
25
24
  }
26
25
  const deployDir = resolveDeployDir(args.directory);
27
26
  const linkedConfig = config.load(deployDir);
28
27
  if (!linkedConfig) {
29
28
  p.cancel("This directory is not linked to an Alpic project. Link it first using `alpic deploy`.");
30
- this.exit(1);
31
29
  return;
32
30
  }
33
31
  const project = await api.projects.get.v1({ projectId: linkedConfig.projectId });
34
32
  if (!project.sourceRepository) {
35
33
  p.cancel(`Project "${project.name}" is not connected to any repository.`);
36
- this.exit(1);
37
34
  return;
38
35
  }
39
36
  const confirm = await p.confirm({
@@ -42,7 +39,6 @@ export default class GitDisconnect extends AlpicCommand {
42
39
  });
43
40
  if (p.isCancel(confirm) || !confirm) {
44
41
  p.cancel("Git disconnect cancelled");
45
- this.exit(1);
46
42
  return;
47
43
  }
48
44
  await api.projects.update.v1({
@@ -1 +1 @@
1
- {"version":3,"file":"disconnect.js","sourceRoot":"","sources":["../../../src/commands/git/disconnect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"disconnect.js","sourceRoot":"","sources":["../../../src/commands/git/disconnect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,YAAY;IACrD,MAAM,CAAU,WAAW,GAAG,8DAA8D,CAAC;IAE7F,MAAM,CAAU,QAAQ,GAAG,CAAC,kCAAkC,EAAE,2CAA2C,CAAC,CAAC;IAE7G,MAAM,CAAU,IAAI,GAAG;QACrB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;YACrB,WAAW,EAAE,sDAAsD;YACnE,QAAQ,EAAE,KAAK;SAChB,CAAC;KACH,CAAC;IAEF,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACjD,CAAC,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAEnD,IAAI,CAAC,CAAC,MAAM,eAAe,EAAE,CAAC,EAAE,CAAC;YAC/B,CAAC,CAAC,MAAM,CACN,sHAAsH,CACvH,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,CAAC,CAAC,MAAM,CAAC,uFAAuF,CAAC,CAAC;YAClG,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC9B,CAAC,CAAC,MAAM,CAAC,YAAY,OAAO,CAAC,IAAI,uCAAuC,CAAC,CAAC;YAC1E,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC;YAC9B,OAAO,EAAE,uCAAuC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG;YAChI,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;QACH,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,CAAC,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,SAAS,EAAE,YAAY,CAAC,SAAS;YACjC,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAC;QAEH,CAAC,CAAC,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9G,CAAC"}
@@ -4,7 +4,7 @@ export default class Git extends Command {
4
4
  static description = "Manage git repository connection for a linked Alpic project";
5
5
  static examples = ["<%= config.bin %> git connect", "<%= config.bin %> git disconnect"];
6
6
  async run() {
7
- const { args } = await this.parse(Git);
7
+ await this.parse(Git);
8
8
  this.log(chalk.bold("Usage:"));
9
9
  this.log(" alpic git connect [directory]");
10
10
  this.log(" alpic git disconnect [directory]");
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/commands/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACtC,MAAM,CAAU,WAAW,GAAG,6DAA6D,CAAC;IAE5F,MAAM,CAAU,QAAQ,GAAG,CAAC,+BAA+B,EAAE,kCAAkC,CAAC,CAAC;IAEjG,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEvC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;QAClF,IAAI,CAAC,GAAG,CAAC,8EAA8E,CAAC,CAAC;IAC3F,CAAC"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/commands/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,OAAO,OAAO,GAAI,SAAQ,OAAO;IACtC,MAAM,CAAU,WAAW,GAAG,6DAA6D,CAAC;IAE5F,MAAM,CAAU,QAAQ,GAAG,CAAC,+BAA+B,EAAE,kCAAkC,CAAC,CAAC;IAEjG,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAC/C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;QAClF,IAAI,CAAC,GAAG,CAAC,8EAA8E,CAAC,CAAC;IAC3F,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { AlpicCommand } from "../lib/alpic-command.js";
2
+ export declare class Login extends AlpicCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,39 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ import open from "open";
4
+ import { AlpicCommand } from "../lib/alpic-command.js";
5
+ import { oAuthClient } from "../lib/auth/oauth/client.js";
6
+ import { getLoginPageUrl, listenToOAuthCallback } from "../lib/auth/oauth/server/index.js";
7
+ import { getWhoamiInfo } from "../lib/auth/whoami.js";
8
+ import { globalStore } from "../lib/global-store.js";
9
+ export class Login extends AlpicCommand {
10
+ static description = "Log in to Alpic (opens browser, stores tokens)";
11
+ static examples = ["<%= config.bin %> login"];
12
+ async run() {
13
+ await this.parse(Login);
14
+ p.intro("Log in to Alpic");
15
+ const token = await oAuthClient.getValidAccessToken();
16
+ if (token) {
17
+ p.outro("Already logged in.");
18
+ return;
19
+ }
20
+ const { authorizeUrl, state, nonce, codeVerifier } = await oAuthClient.prepareOAuthConfig();
21
+ p.log.message("Opening browser to log in…");
22
+ await open(getLoginPageUrl());
23
+ const storedToken = await listenToOAuthCallback({
24
+ state,
25
+ nonce,
26
+ codeVerifier,
27
+ authorizeUrl: authorizeUrl.toString(),
28
+ });
29
+ globalStore.saveCredentials(storedToken);
30
+ const info = await getWhoamiInfo();
31
+ if (!info) {
32
+ p.cancel("Failed to get user information.");
33
+ return;
34
+ }
35
+ const msg = `Authenticated as ${chalk.green(info.name)} (${chalk.cyan(info.email)})`;
36
+ p.outro(msg);
37
+ }
38
+ }
39
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,OAAO,KAAM,SAAQ,YAAY;IACrC,MAAM,CAAU,WAAW,GAAG,gDAAgD,CAAC;IAE/E,MAAM,CAAU,QAAQ,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAEvD,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAExB,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAE3B,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,mBAAmB,EAAE,CAAC;QACtD,IAAI,KAAK,EAAE,CAAC;YACV,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,WAAW,CAAC,kBAAkB,EAAE,CAAC;QAE5F,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;QAE9B,MAAM,WAAW,GAAG,MAAM,qBAAqB,CAAC;YAC9C,KAAK;YACL,KAAK;YACL,YAAY;YACZ,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE;SACtC,CAAC,CAAC;QAEH,WAAW,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QAEzC,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;QAEnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,CAAC,CAAC,MAAM,CAAC,iCAAiC,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,oBAAoB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACrF,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACf,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { AlpicCommand } from "../lib/alpic-command.js";
2
+ export declare class Logout extends AlpicCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,20 @@
1
+ import * as p from "@clack/prompts";
2
+ import { AlpicCommand } from "../lib/alpic-command.js";
3
+ import { globalStore } from "../lib/global-store.js";
4
+ export class Logout extends AlpicCommand {
5
+ static description = "Log out from Alpic (removes stored OAuth credentials)";
6
+ static examples = ["<%= config.bin %> logout"];
7
+ async run() {
8
+ await this.parse(Logout);
9
+ p.intro("Log out from Alpic");
10
+ const hasCredentials = globalStore.getCredentials() !== null;
11
+ if (!hasCredentials) {
12
+ p.outro("You are not logged in.");
13
+ return;
14
+ }
15
+ globalStore.clearCredentials();
16
+ p.log.success("✅ User authentication cleared.");
17
+ p.outro("You are logged out.");
18
+ }
19
+ }
20
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,MAAM,OAAO,MAAO,SAAQ,YAAY;IACtC,MAAM,CAAU,WAAW,GAAG,uDAAuD,CAAC;IAEtF,MAAM,CAAU,QAAQ,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAExD,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAEzB,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE9B,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,EAAE,KAAK,IAAI,CAAC;QAE7D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAClC,OAAO;QACT,CAAC;QAED,WAAW,CAAC,gBAAgB,EAAE,CAAC;QAE/B,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;QAEhD,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACjC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { AlpicCommand } from "../lib/alpic-command.js";
2
+ export declare class Whoami extends AlpicCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,25 @@
1
+ import * as p from "@clack/prompts";
2
+ import chalk from "chalk";
3
+ import { AlpicCommand } from "../lib/alpic-command.js";
4
+ import { getWhoamiInfo } from "../lib/auth/whoami.js";
5
+ export class Whoami extends AlpicCommand {
6
+ static description = "Show the current Alpic identity (API key or logged-in user)";
7
+ static examples = ["<%= config.bin %> whoami"];
8
+ async run() {
9
+ await this.parse(Whoami);
10
+ p.intro("Reading authentication status…");
11
+ const info = await getWhoamiInfo();
12
+ if (!info) {
13
+ p.cancel("Not logged in. Run `alpic login` or set ALPIC_API_KEY.");
14
+ return;
15
+ }
16
+ if (info.method === "api_key") {
17
+ const msg = `Authenticated via API key — Team: ${chalk.green(info.team?.name ?? "unknown")}`;
18
+ p.outro(msg);
19
+ return;
20
+ }
21
+ const msg = `Authenticated as ${chalk.green(info.name)} (${chalk.cyan(info.email)})`;
22
+ p.outro(msg);
23
+ }
24
+ }
25
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,OAAO,MAAO,SAAQ,YAAY;IACtC,MAAM,CAAU,WAAW,GAAG,6DAA6D,CAAC;IAE5F,MAAM,CAAU,QAAQ,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAExD,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAEzB,CAAC,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAE1C,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;QAEnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,CAAC,CAAC,MAAM,CAAC,wDAAwD,CAAC,CAAC;YACnE,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,qCAAqC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,SAAS,CAAC,EAAE,CAAC;YAC7F,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,oBAAoB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACrF,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACf,CAAC"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare const env: Readonly<{
2
+ ALPIC_API_BASE_URL: string;
3
+ ALPIC_COGNITO_CLIENT_ID: string;
4
+ }>;
package/dist/env.js ADDED
@@ -0,0 +1,10 @@
1
+ import { createEnv } from "@t3-oss/env-core";
2
+ import { z } from "zod";
3
+ export const env = createEnv({
4
+ server: {
5
+ ALPIC_API_BASE_URL: z.string().default("https://api.alpic.ai"),
6
+ ALPIC_COGNITO_CLIENT_ID: z.string().default("1023dpimab488tfv4sh4bdk2r"),
7
+ },
8
+ runtimeEnv: process.env,
9
+ });
10
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC;IAC3B,MAAM,EAAE;QACN,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC;QAC9D,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,2BAA2B,CAAC;KACzE;IACD,UAAU,EAAE,OAAO,CAAC,GAAG;CACxB,CAAC,CAAC"}
@@ -5,16 +5,13 @@ export class AlpicCommand extends Command {
5
5
  async catch(error) {
6
6
  if (error instanceof ORPCError) {
7
7
  p.cancel(`An error occurred while connecting to Alpic: ${error.message}`);
8
- this.exit(1);
9
8
  return;
10
9
  }
11
10
  if (error instanceof Error) {
12
11
  p.cancel(error.message);
13
- this.exit(1);
14
12
  return;
15
13
  }
16
14
  p.cancel(String(error));
17
- this.exit(1);
18
15
  }
19
16
  }
20
17
  //# sourceMappingURL=alpic-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpic-command.js","sourceRoot":"","sources":["../../src/lib/alpic-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,OAAgB,YAAa,SAAQ,OAAO;IACvC,KAAK,CAAC,KAAK,CAAC,KAAc;QACjC,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;YAC/B,CAAC,CAAC,MAAM,CAAC,gDAAgD,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACb,OAAO;QACT,CAAC;QACD,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACf,CAAC;CACF"}
1
+ {"version":3,"file":"alpic-command.js","sourceRoot":"","sources":["../../src/lib/alpic-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,OAAgB,YAAa,SAAQ,OAAO;IACvC,KAAK,CAAC,KAAK,CAAC,KAAc;QACjC,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;YAC/B,CAAC,CAAC,MAAM,CAAC,gDAAgD,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1E,OAAO;QACT,CAAC;QACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxB,OAAO;QACT,CAAC;QACD,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export declare function getApiToken(): Promise<string | undefined>;
2
+ export declare function isAuthenticated(): Promise<boolean>;
@@ -0,0 +1,21 @@
1
+ import { oAuthClient } from "./oauth/client.js";
2
+ export async function getApiToken() {
3
+ const token = process.env.ALPIC_API_KEY ?? (await oAuthClient.getValidAccessToken())?.access_token;
4
+ return token;
5
+ }
6
+ export async function isAuthenticated() {
7
+ const isAuthenticatedViaApiKey = hasApiKey();
8
+ if (isAuthenticatedViaApiKey)
9
+ return true;
10
+ const isAuthenticatedViaOAuth = await hasValidAccessToken();
11
+ if (isAuthenticatedViaOAuth)
12
+ return true;
13
+ return false;
14
+ }
15
+ function hasApiKey() {
16
+ return process.env.ALPIC_API_KEY !== undefined;
17
+ }
18
+ async function hasValidAccessToken() {
19
+ return (await oAuthClient.getValidAccessToken()) !== null;
20
+ }
21
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/lib/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,MAAM,WAAW,CAAC,mBAAmB,EAAE,CAAC,EAAE,YAAY,CAAC;IAEnG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,wBAAwB,GAAG,SAAS,EAAE,CAAC;IAC7C,IAAI,wBAAwB;QAAE,OAAO,IAAI,CAAC;IAC1C,MAAM,uBAAuB,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAC5D,IAAI,uBAAuB;QAAE,OAAO,IAAI,CAAC;IAEzC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,SAAS,CAAC;AACjD,CAAC;AAED,KAAK,UAAU,mBAAmB;IAChC,OAAO,CAAC,MAAM,WAAW,CAAC,mBAAmB,EAAE,CAAC,KAAK,IAAI,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,28 @@
1
+ import * as openid from "openid-client";
2
+ import { type Credentials } from "../../global-store.js";
3
+ export declare class OAuthClient {
4
+ private config;
5
+ initialize: Promise<void>;
6
+ constructor();
7
+ getValidAccessToken(): Promise<Credentials | null>;
8
+ fetchUserInfo(credentials: Credentials): Promise<openid.UserInfoResponse>;
9
+ refreshAccessToken(credentials: Credentials): Promise<Credentials>;
10
+ prepareOAuthConfig(): Promise<{
11
+ authorizeUrl: URL;
12
+ state: string;
13
+ nonce: string;
14
+ codeVerifier: string;
15
+ }>;
16
+ exchangeAuthorizationCode({ url, codeVerifier, state, nonce, }: {
17
+ url: URL;
18
+ codeVerifier: string;
19
+ state: string;
20
+ nonce: string;
21
+ }): Promise<openid.TokenEndpointResponse & openid.TokenEndpointResponseHelpers>;
22
+ getExpiresAt(expires_in: number): number;
23
+ private loadConfig;
24
+ private fetchOAuthProtectedResourceConfig;
25
+ private getConfig;
26
+ private isAccessTokenExpired;
27
+ }
28
+ export declare const oAuthClient: OAuthClient;
@@ -0,0 +1,110 @@
1
+ import * as openid from "openid-client";
2
+ import { env } from "../../../env.js";
3
+ import { globalStore } from "../../global-store.js";
4
+ import { LOOPBACK_HOST, LOOPBACK_PORT } from "./constants.js";
5
+ const SCOPES = ["openid", "email", "profile"];
6
+ export class OAuthClient {
7
+ config = null;
8
+ initialize;
9
+ constructor() {
10
+ this.initialize = this.loadConfig();
11
+ }
12
+ async getValidAccessToken() {
13
+ await this.initialize;
14
+ const stored = globalStore.getCredentials();
15
+ if (!stored) {
16
+ return null;
17
+ }
18
+ if (this.isAccessTokenExpired(stored)) {
19
+ try {
20
+ return await this.refreshAccessToken(stored);
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ return stored;
27
+ }
28
+ async fetchUserInfo(credentials) {
29
+ return openid.fetchUserInfo(await this.getConfig(), credentials.access_token, credentials.sub);
30
+ }
31
+ async refreshAccessToken(credentials) {
32
+ if (!credentials.refresh_token) {
33
+ throw new Error("No refresh token available");
34
+ }
35
+ const response = await openid.refreshTokenGrant(await this.getConfig(), credentials.refresh_token);
36
+ const refreshed = {
37
+ access_token: response.access_token,
38
+ refresh_token: response.refresh_token ?? credentials.refresh_token,
39
+ expires_at: this.getExpiresAt(response.expires_in ?? 0),
40
+ sub: credentials.sub,
41
+ };
42
+ globalStore.saveCredentials(refreshed);
43
+ return refreshed;
44
+ }
45
+ async prepareOAuthConfig() {
46
+ await this.initialize;
47
+ if (!this.config) {
48
+ throw new Error("Config not loaded");
49
+ }
50
+ const codeVerifier = openid.randomPKCECodeVerifier();
51
+ const codeChallenge = await openid.calculatePKCECodeChallenge(codeVerifier);
52
+ const state = openid.randomState();
53
+ const nonce = openid.randomNonce();
54
+ const callbackUrl = new URL(`http://${LOOPBACK_HOST}:${LOOPBACK_PORT}/callback`);
55
+ const authorizeUrl = openid.buildAuthorizationUrl(this.config, {
56
+ redirect_uri: callbackUrl.toString(),
57
+ scope: SCOPES.join(" "),
58
+ code_challenge: codeChallenge,
59
+ code_challenge_method: "S256",
60
+ state,
61
+ nonce,
62
+ });
63
+ return { authorizeUrl, state, nonce, codeVerifier };
64
+ }
65
+ async exchangeAuthorizationCode({ url, codeVerifier, state, nonce, }) {
66
+ return await openid.authorizationCodeGrant(await this.getConfig(), url, {
67
+ pkceCodeVerifier: codeVerifier,
68
+ expectedState: state,
69
+ expectedNonce: nonce,
70
+ });
71
+ }
72
+ getExpiresAt(expires_in) {
73
+ return expires_in !== undefined ? Math.floor(Date.now() / 1000) + expires_in : Date.now() / 1000 + 3600;
74
+ }
75
+ async loadConfig() {
76
+ const protectedResourceConfig = await this.fetchOAuthProtectedResourceConfig();
77
+ const issuer = protectedResourceConfig.authorization_servers[0];
78
+ if (!issuer) {
79
+ throw new Error("No authorization server in OAuth protected resource config");
80
+ }
81
+ const issuerUrl = new URL(issuer);
82
+ try {
83
+ this.config = await openid.discovery(issuerUrl, env.ALPIC_COGNITO_CLIENT_ID);
84
+ }
85
+ catch {
86
+ throw new Error("Failed to discover OAuth config");
87
+ }
88
+ }
89
+ async fetchOAuthProtectedResourceConfig() {
90
+ const baseUrl = env.ALPIC_API_BASE_URL;
91
+ const response = await fetch(`${baseUrl}/.well-known/oauth-protected-resource`);
92
+ if (!response.ok) {
93
+ throw new Error(`Failed to load service config from ${baseUrl} (${response.status} ${response.statusText})`);
94
+ }
95
+ return (await response.json());
96
+ }
97
+ async getConfig() {
98
+ await this.initialize;
99
+ if (!this.config) {
100
+ throw new Error("Config not loaded");
101
+ }
102
+ return this.config;
103
+ }
104
+ isAccessTokenExpired(credentials) {
105
+ const EXPIRATION_WINDOW_IN_SECONDS = 300;
106
+ return Date.now() / 1000 + EXPIRATION_WINDOW_IN_SECONDS >= credentials.expires_at;
107
+ }
108
+ }
109
+ export const oAuthClient = new OAuthClient();
110
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../src/lib/auth/oauth/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const LOOPBACK_HOST = "127.0.0.1";
2
+ export declare const LOOPBACK_PORT = 38472;
@@ -0,0 +1,3 @@
1
+ export const LOOPBACK_HOST = "127.0.0.1";
2
+ export const LOOPBACK_PORT = 38472;
3
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/lib/auth/oauth/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC"}
@@ -0,0 +1,195 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Sign in to Alpic</title>
7
+ <link
8
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Mozilla+Text:wght@200..700&display=swap"
9
+ rel="stylesheet"
10
+ />
11
+ <style>
12
+ *,
13
+ *::before,
14
+ *::after {
15
+ margin: 0;
16
+ padding: 0;
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ :root {
21
+ --midnight: #051413;
22
+ }
23
+
24
+ body {
25
+ font-family: "Inter", system-ui, sans-serif;
26
+ background-color: var(--midnight);
27
+ min-height: 100vh;
28
+ display: flex;
29
+ background-image: url("/assets/alpic-mountain.png");
30
+ background-repeat: no-repeat;
31
+ background-position: right bottom;
32
+ background-size: auto;
33
+ padding: 64px;
34
+ }
35
+
36
+ .card {
37
+ background: #fff;
38
+ border-radius: 2px;
39
+ padding: 48px;
40
+ width: 50%;
41
+ min-height: calc(100vh - 128px);
42
+ display: flex;
43
+ flex-direction: column;
44
+ align-items: center;
45
+ justify-content: center;
46
+ }
47
+
48
+ h1 {
49
+ font-family: "Mozilla Text", system-ui, sans-serif;
50
+ font-weight: 400;
51
+ font-size: 48px;
52
+ color: var(--midnight);
53
+ margin-bottom: 8px;
54
+ }
55
+
56
+ .subtitle {
57
+ font-size: 20px;
58
+ color: var(--midnight);
59
+ margin-bottom: 32px;
60
+ }
61
+
62
+ .buttons {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 12px;
66
+ }
67
+
68
+ .btn {
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+ gap: 8px;
73
+ height: 48px;
74
+ width: 256px;
75
+ padding: 0 16px;
76
+ border-radius: 2px;
77
+ border: 1px solid var(--midnight);
78
+ font-family: "Inter", system-ui, sans-serif;
79
+ font-size: 16px;
80
+ font-weight: 500;
81
+ cursor: pointer;
82
+ transition: background 0.15s;
83
+ }
84
+
85
+ .btn:focus-visible {
86
+ outline: none;
87
+ box-shadow: 0 0 0 2px var(--midnight);
88
+ }
89
+
90
+ .btn svg {
91
+ width: 20px;
92
+ height: 20px;
93
+ flex-shrink: 0;
94
+ }
95
+
96
+ .btn-github {
97
+ background: var(--midnight);
98
+ color: #fff;
99
+ }
100
+ .btn-github svg {
101
+ fill: #fff;
102
+ }
103
+ .btn-github:hover {
104
+ background: rgba(5, 20, 19, 0.9);
105
+ }
106
+
107
+ .btn-google {
108
+ background: #fff;
109
+ color: var(--midnight);
110
+ }
111
+ .btn-google svg {
112
+ fill: var(--midnight);
113
+ }
114
+ .btn-google:hover {
115
+ background: rgba(5, 20, 19, 0.1);
116
+ }
117
+
118
+ .btn-loading {
119
+ opacity: 0.7;
120
+ pointer-events: none;
121
+ cursor: default;
122
+ transition: opacity 0.2s;
123
+ }
124
+ .spinner {
125
+ width: 20px;
126
+ height: 20px;
127
+ animation: spin 0.8s linear infinite;
128
+ }
129
+ @keyframes spin {
130
+ to {
131
+ transform: rotate(360deg);
132
+ }
133
+ }
134
+
135
+ @media (max-width: 768px) {
136
+ body {
137
+ padding: 16px;
138
+ }
139
+ .card {
140
+ width: 100%;
141
+ height: auto;
142
+ padding: 24px;
143
+ }
144
+ h1 {
145
+ font-size: 36px;
146
+ }
147
+ .subtitle {
148
+ font-size: 18px;
149
+ }
150
+ }
151
+ </style>
152
+ </head>
153
+ <body>
154
+ <div class="card">
155
+ <h1>Welcome to Alpic</h1>
156
+ <p class="subtitle">Sign in to use Alpic CLI</p>
157
+ <div class="buttons">
158
+ <button class="btn btn-github" onclick="login('Github', this)" type="button">
159
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
160
+ <title>GitHub</title>
161
+ <path
162
+ d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
163
+ />
164
+ </svg>
165
+ Sign in with GitHub
166
+ </button>
167
+ <button class="btn btn-google" onclick="login('google', this)" type="button">
168
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
169
+ <title>Google</title>
170
+ <path
171
+ d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.8 4.133-1.147 1.147-2.933 2.4-6.04 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
172
+ />
173
+ </svg>
174
+ Sign in with Google
175
+ </button>
176
+ </div>
177
+ </div>
178
+ <script>
179
+ var loaderSvg =
180
+ '<svg class="spinner" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4"/><path d="m16.2 7.8 2.9-2.9"/><path d="M18 12h4"/><path d="m16.2 16.2 2.9 2.9"/><path d="M12 18v4"/><path d="m4.9 19.1 2.9-2.9"/><path d="M2 12h4"/><path d="m4.9 4.9 2.9 2.9"/></svg>';
181
+ // biome-ignore lint/correctness/noUnusedVariables: The function is used within the buttons onclick handlers
182
+ function login(provider, btn) {
183
+ const icon = btn.querySelector("svg");
184
+ const wrap = document.createElement("div");
185
+ wrap.innerHTML = loaderSvg;
186
+ icon.replaceWith(wrap.firstChild);
187
+ btn.classList.add("btn-loading");
188
+ btn.disabled = true;
189
+ const url = new URL("%AUTH_BASE_URL%");
190
+ url.searchParams.set("identity_provider", provider);
191
+ window.location.href = url.toString();
192
+ }
193
+ </script>
194
+ </body>
195
+ </html>