@shopify/cli-hydrogen 4.2.1 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/commands/hydrogen/build.d.ts +1 -1
  2. package/dist/commands/hydrogen/build.js +24 -22
  3. package/dist/commands/hydrogen/check.js +1 -1
  4. package/dist/commands/hydrogen/codegen-unstable.d.ts +1 -0
  5. package/dist/commands/hydrogen/codegen-unstable.js +6 -0
  6. package/dist/commands/hydrogen/dev.d.ts +2 -1
  7. package/dist/commands/hydrogen/dev.js +85 -65
  8. package/dist/commands/hydrogen/env/list.d.ts +2 -3
  9. package/dist/commands/hydrogen/env/list.js +42 -44
  10. package/dist/commands/hydrogen/env/list.test.js +18 -24
  11. package/dist/commands/hydrogen/env/pull.d.ts +2 -3
  12. package/dist/commands/hydrogen/env/pull.js +42 -23
  13. package/dist/commands/hydrogen/env/pull.test.js +16 -4
  14. package/dist/commands/hydrogen/init.js +3 -13
  15. package/dist/commands/hydrogen/link.d.ts +0 -1
  16. package/dist/commands/hydrogen/link.js +34 -36
  17. package/dist/commands/hydrogen/link.test.js +43 -27
  18. package/dist/commands/hydrogen/list.d.ts +2 -2
  19. package/dist/commands/hydrogen/list.js +43 -39
  20. package/dist/commands/hydrogen/list.test.js +24 -32
  21. package/dist/commands/hydrogen/shortcut.js +6 -7
  22. package/dist/commands/hydrogen/shortcut.test.js +8 -9
  23. package/dist/commands/hydrogen/unlink.d.ts +0 -1
  24. package/dist/commands/hydrogen/unlink.js +5 -3
  25. package/dist/lib/admin-session.d.ts +1 -0
  26. package/dist/lib/codegen.d.ts +3 -2
  27. package/dist/lib/codegen.js +20 -7
  28. package/dist/lib/combined-environment-variables.js +19 -36
  29. package/dist/lib/combined-environment-variables.test.js +7 -7
  30. package/dist/lib/config.d.ts +3 -1
  31. package/dist/lib/config.js +67 -63
  32. package/dist/lib/flags.d.ts +1 -0
  33. package/dist/lib/flags.js +8 -3
  34. package/dist/lib/graphql/admin/link-storefront.d.ts +12 -9
  35. package/dist/lib/graphql/admin/link-storefront.js +18 -1
  36. package/dist/lib/graphql/admin/list-environments.d.ts +6 -5
  37. package/dist/lib/graphql/admin/list-environments.js +11 -1
  38. package/dist/lib/graphql/admin/list-storefronts.d.ts +13 -5
  39. package/dist/lib/graphql/admin/list-storefronts.js +18 -1
  40. package/dist/lib/graphql/admin/pull-variables.d.ts +6 -1
  41. package/dist/lib/graphql/admin/pull-variables.js +14 -1
  42. package/dist/lib/log.d.ts +2 -1
  43. package/dist/lib/log.js +8 -1
  44. package/dist/lib/mini-oxygen.js +1 -1
  45. package/dist/lib/process.d.ts +6 -0
  46. package/dist/lib/process.js +17 -0
  47. package/dist/lib/pull-environment-variables.d.ts +1 -0
  48. package/dist/lib/pull-environment-variables.js +4 -14
  49. package/dist/lib/remix-version-interop.js +1 -1
  50. package/dist/lib/shell.d.ts +5 -6
  51. package/dist/lib/shell.js +65 -17
  52. package/dist/lib/shell.test.d.ts +1 -0
  53. package/dist/lib/shell.test.js +85 -0
  54. package/dist/lib/shopify-config.d.ts +1 -1
  55. package/dist/lib/shopify-config.js +2 -2
  56. package/dist/lib/transpile-ts.js +6 -0
  57. package/oclif.manifest.json +1 -1
  58. package/package.json +9 -8
  59. package/dist/lib/colors.d.ts +0 -11
  60. package/dist/lib/colors.js +0 -11
@@ -1,32 +1,24 @@
1
1
  import { vi, describe, beforeEach, afterEach, it, expect } from 'vitest';
2
2
  import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
3
- import { ListStorefrontsQuery } from '../../lib/graphql/admin/list-storefronts.js';
4
- import { getAdminSession } from '../../lib/admin-session.js';
5
- import { adminRequest } from '../../lib/graphql.js';
3
+ import { getStorefrontsWithDeployment } from '../../lib/graphql/admin/list-storefronts.js';
6
4
  import { listStorefronts, formatDeployment } from './list.js';
7
5
 
8
- vi.mock("../../lib/admin-session.js");
9
- vi.mock("../../lib/graphql.js", async () => {
10
- const original = await vi.importActual(
11
- "../../lib/graphql.js"
12
- );
13
- return {
14
- ...original,
15
- adminRequest: vi.fn()
16
- };
6
+ const SHOP_NAME = "my-shop";
7
+ vi.mock("../../lib/graphql/admin/list-storefronts.js", async () => {
8
+ return { getStorefrontsWithDeployment: vi.fn() };
17
9
  });
18
10
  vi.mock("../../lib/shop.js", () => ({
19
- getHydrogenShop: () => "my-shop"
11
+ getHydrogenShop: () => SHOP_NAME
20
12
  }));
21
13
  describe("list", () => {
22
14
  const ADMIN_SESSION = {
23
15
  token: "abc123",
24
- storeFqdn: "my-shop"
16
+ storeFqdn: SHOP_NAME
25
17
  };
26
18
  beforeEach(async () => {
27
- vi.mocked(getAdminSession).mockResolvedValue(ADMIN_SESSION);
28
- vi.mocked(adminRequest).mockResolvedValue({
29
- hydrogenStorefronts: []
19
+ vi.mocked(getStorefrontsWithDeployment).mockResolvedValue({
20
+ adminSession: ADMIN_SESSION,
21
+ storefronts: []
30
22
  });
31
23
  });
32
24
  afterEach(() => {
@@ -35,23 +27,23 @@ describe("list", () => {
35
27
  });
36
28
  it("makes a GraphQL call to fetch the storefronts", async () => {
37
29
  await listStorefronts({});
38
- expect(adminRequest).toHaveBeenCalledWith(
39
- ListStorefrontsQuery,
40
- ADMIN_SESSION
41
- );
30
+ expect(getStorefrontsWithDeployment).toHaveBeenCalledWith(SHOP_NAME);
42
31
  });
43
32
  describe("and there are storefronts", () => {
44
33
  beforeEach(() => {
45
- vi.mocked(adminRequest).mockResolvedValue({
46
- hydrogenStorefronts: [
34
+ vi.mocked(getStorefrontsWithDeployment).mockResolvedValue({
35
+ adminSession: ADMIN_SESSION,
36
+ storefronts: [
47
37
  {
48
38
  id: "gid://shopify/HydrogenStorefront/1",
39
+ parsedId: "1",
49
40
  title: "Hydrogen",
50
41
  productionUrl: "https://example.com",
51
42
  currentProductionDeployment: null
52
43
  },
53
44
  {
54
45
  id: "gid://shopify/HydrogenStorefront/2",
46
+ parsedId: "2",
55
47
  title: "Demo Store",
56
48
  productionUrl: "https://demo.example.com",
57
49
  currentProductionDeployment: {
@@ -67,14 +59,13 @@ describe("list", () => {
67
59
  const outputMock = mockAndCaptureOutput();
68
60
  await listStorefronts({});
69
61
  expect(outputMock.info()).toMatch(
70
- /Found 2 Hydrogen storefronts on my-shop/g
71
- );
72
- expect(outputMock.info()).toMatch(
73
- /1 Hydrogen https:\/\/example.com/g
74
- );
75
- expect(outputMock.info()).toMatch(
76
- /2 Demo Store https:\/\/demo.example.com March 22, 2023, Update README.md/g
62
+ /Showing 2 Hydrogen storefronts for the store my-shop/g
77
63
  );
64
+ expect(outputMock.info()).toMatch(/Hydrogen \(id: 1\)/g);
65
+ expect(outputMock.info()).toMatch(/https:\/\/example.com/g);
66
+ expect(outputMock.info()).toMatch(/Demo Store \(id: 2\)/g);
67
+ expect(outputMock.info()).toMatch(/https:\/\/demo.example.com/g);
68
+ expect(outputMock.info()).toMatch(/3\/22\/2023, Update README.md/g);
78
69
  });
79
70
  });
80
71
  describe("and there are no storefronts", () => {
@@ -100,17 +91,18 @@ describe("formatDeployment", () => {
100
91
  commitMessage: "Update README.md\n\nThis is a description of why the change was made."
101
92
  };
102
93
  expect(formatDeployment(deployment)).toStrictEqual(
103
- "March 22, 2023, Update README.md"
94
+ "3/22/2023, Update README.md"
104
95
  );
105
96
  });
106
97
  describe("when there is no commit message", () => {
107
98
  it("only returns the date", () => {
108
99
  const deployment = {
109
100
  id: "gid://shopify/HydrogenStorefrontDeployment/1",
101
+ parsedId: "1",
110
102
  createdAt,
111
103
  commitMessage: null
112
104
  };
113
- expect(formatDeployment(deployment)).toStrictEqual("March 22, 2023");
105
+ expect(formatDeployment(deployment)).toStrictEqual("3/22/2023");
114
106
  });
115
107
  });
116
108
  });
@@ -1,8 +1,7 @@
1
1
  import Command from '@shopify/cli-kit/node/base-command';
2
2
  import { renderSuccess, renderFatalError } from '@shopify/cli-kit/node/ui';
3
- import { isWindows, isGitBash, supportsShell, hasAlias, shellWriteFile, homeFileExists, shellRunScript } from '../../lib/shell.js';
3
+ import { ALIAS_NAME, isWindows, isGitBash, shellWriteAlias, shellRunScript } from '../../lib/shell.js';
4
4
 
5
- const ALIAS_NAME = "h2";
6
5
  class Shortcut extends Command {
7
6
  static description = `Creates a global \`${ALIAS_NAME}\` shortcut for the Hydrogen CLI`;
8
7
  async run() {
@@ -38,13 +37,13 @@ end
38
37
  `;
39
38
  async function createShortcutsForUnix() {
40
39
  const shells = [];
41
- if (supportsShell("zsh") && (hasAlias(ALIAS_NAME, "~/.zshrc") || shellWriteFile("~/.zshrc", BASH_ZSH_COMMAND, true))) {
40
+ if (await shellWriteAlias("zsh", ALIAS_NAME, BASH_ZSH_COMMAND)) {
42
41
  shells.push("zsh");
43
42
  }
44
- if (supportsShell("bash") && (hasAlias(ALIAS_NAME, "~/.bashrc") || shellWriteFile("~/.bashrc", BASH_ZSH_COMMAND, true))) {
43
+ if (await shellWriteAlias("bash", ALIAS_NAME, BASH_ZSH_COMMAND)) {
45
44
  shells.push("bash");
46
45
  }
47
- if (supportsShell("fish") && await homeFileExists("~/.config/fish/functions") && shellWriteFile(`~/.config/fish/functions/${ALIAS_NAME}.fish`, FISH_FUNCTION)) {
46
+ if (await shellWriteAlias("fish", ALIAS_NAME, FISH_FUNCTION)) {
48
47
  shells.push("fish");
49
48
  }
50
49
  return shells;
@@ -62,10 +61,10 @@ if (!$profileContent -or $profileContent -NotLike '*Invoke-Local-H2*') {
62
61
  `;
63
62
  async function createShortcutsForWindows() {
64
63
  const shells = [];
65
- if (shellRunScript(PS_APPEND_PROFILE_COMMAND, "powershell.exe")) {
64
+ if (await shellRunScript(PS_APPEND_PROFILE_COMMAND, "powershell.exe")) {
66
65
  shells.push("PowerShell");
67
66
  }
68
- if (shellRunScript(PS_APPEND_PROFILE_COMMAND, "pwsh.exe")) {
67
+ if (await shellRunScript(PS_APPEND_PROFILE_COMMAND, "pwsh.exe")) {
69
68
  shells.push("PowerShell 7+");
70
69
  }
71
70
  return shells;
@@ -1,7 +1,7 @@
1
1
  import { describe, beforeEach, vi, afterEach, expect, it } from 'vitest';
2
2
  import { runCreateShortcut } from './shortcut.js';
3
3
  import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
4
- import { supportsShell, isWindows, isGitBash } from '../../lib/shell.js';
4
+ import { shellWriteAlias, isWindows, isGitBash } from '../../lib/shell.js';
5
5
  import { execSync, exec } from 'child_process';
6
6
 
7
7
  describe("shortcut", () => {
@@ -10,18 +10,17 @@ describe("shortcut", () => {
10
10
  vi.resetAllMocks();
11
11
  vi.mock("child_process");
12
12
  vi.mock("../../lib/shell.js", async () => {
13
+ const original = await vi.importActual("../../lib/shell.js");
13
14
  return {
15
+ ...original,
14
16
  isWindows: vi.fn(),
15
17
  isGitBash: vi.fn(),
16
- supportsShell: vi.fn(),
17
- shellWriteFile: () => true,
18
- shellRunScript: () => true,
19
- hasAlias: () => false,
20
- homeFileExists: () => Promise.resolve(true)
18
+ shellWriteAlias: vi.fn(),
19
+ shellRunScript: async () => true
21
20
  };
22
21
  });
23
- vi.mocked(supportsShell).mockImplementation(
24
- (shell) => !isWindows() || shell === "bash"
22
+ vi.mocked(shellWriteAlias).mockImplementation(
23
+ async (shell) => !isWindows() || shell === "bash"
25
24
  );
26
25
  });
27
26
  afterEach(() => {
@@ -50,7 +49,7 @@ describe("shortcut", () => {
50
49
  });
51
50
  it("warns when not finding shells", async () => {
52
51
  vi.mocked(isWindows).mockReturnValue(false);
53
- vi.mocked(supportsShell).mockReturnValue(false);
52
+ vi.mocked(shellWriteAlias).mockResolvedValue(false);
54
53
  await runCreateShortcut();
55
54
  expect(outputMock.info()).toBeFalsy();
56
55
  expect(outputMock.error()).toBeTruthy();
@@ -3,7 +3,6 @@ import Command from '@shopify/cli-kit/node/base-command';
3
3
 
4
4
  declare class Unlink extends Command {
5
5
  static description: string;
6
- static hidden: boolean;
7
6
  static flags: {
8
7
  path: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
9
8
  };
@@ -1,11 +1,11 @@
1
1
  import Command from '@shopify/cli-kit/node/base-command';
2
- import { outputWarn, outputSuccess } from '@shopify/cli-kit/node/output';
2
+ import { renderSuccess } from '@shopify/cli-kit/node/ui';
3
+ import { outputWarn } from '@shopify/cli-kit/node/output';
3
4
  import { commonFlags } from '../../lib/flags.js';
4
5
  import { getConfig, unsetStorefront } from '../../lib/shopify-config.js';
5
6
 
6
7
  class Unlink extends Command {
7
8
  static description = "Unlink a local project from a Hydrogen storefront.";
8
- static hidden = true;
9
9
  static flags = {
10
10
  path: commonFlags.path
11
11
  };
@@ -23,7 +23,9 @@ async function unlinkStorefront({ path }) {
23
23
  }
24
24
  const storefrontTitle = configStorefront.title;
25
25
  await unsetStorefront(actualPath);
26
- outputSuccess(`You are no longer linked to ${storefrontTitle}`);
26
+ renderSuccess({
27
+ body: ["You are no longer linked to", { bold: storefrontTitle }]
28
+ });
27
29
  }
28
30
 
29
31
  export { Unlink as default, unlinkStorefront };
@@ -1,4 +1,5 @@
1
1
  import { AdminSession } from '@shopify/cli-kit/node/session';
2
+ export { AdminSession } from '@shopify/cli-kit/node/session';
2
3
 
3
4
  declare function getAdminSession(shop: string): Promise<AdminSession>;
4
5
 
@@ -17,9 +17,10 @@ type ProjectDirs = {
17
17
  appDirectory: string;
18
18
  };
19
19
  type CodegenOptions = ProjectDirs & {
20
- configFilePath?: string;
21
20
  watch?: boolean;
21
+ configFilePath?: string;
22
+ forceSfapiVersion?: string;
22
23
  };
23
- declare function generateTypes({ configFilePath, watch, ...dirs }: CodegenOptions): Promise<string[]>;
24
+ declare function generateTypes({ watch, configFilePath, forceSfapiVersion, ...dirs }: CodegenOptions): Promise<string[]>;
24
25
 
25
26
  export { generateTypes, normalizeCodegenError, spawnCodegenProcess };
@@ -67,14 +67,15 @@ function spawnCodegenProcess({
67
67
  return child;
68
68
  }
69
69
  async function generateTypes({
70
- configFilePath,
71
70
  watch,
71
+ configFilePath,
72
+ forceSfapiVersion,
72
73
  ...dirs
73
74
  }) {
74
75
  const { config: codegenConfig } = await loadCodegenConfig({
75
76
  configFilePath,
76
77
  searchPlaces: [dirs.rootDirectory]
77
- }) || generateDefaultConfig(dirs);
78
+ }) || generateDefaultConfig(dirs, forceSfapiVersion);
78
79
  await addHooksToHydrogenOptions(codegenConfig, dirs);
79
80
  await generate(
80
81
  {
@@ -87,10 +88,7 @@ async function generateTypes({
87
88
  );
88
89
  return Object.keys(codegenConfig.generates);
89
90
  }
90
- function generateDefaultConfig({
91
- rootDirectory,
92
- appDirectory
93
- }) {
91
+ function generateDefaultConfig({ rootDirectory, appDirectory }, forceSfapiVersion) {
94
92
  const tsDefaultGlob = "*!(*.d).{ts,tsx}";
95
93
  const appDirRelative = relativePath(rootDirectory, appDirectory);
96
94
  return {
@@ -105,7 +103,22 @@ function generateDefaultConfig({
105
103
  documents: [
106
104
  tsDefaultGlob,
107
105
  joinPath(appDirRelative, "**", tsDefaultGlob)
108
- ]
106
+ ],
107
+ ...!!forceSfapiVersion && {
108
+ presetConfig: { importTypes: false },
109
+ schema: {
110
+ [`https://hydrogen-preview.myshopify.com/api/${forceSfapiVersion.split(":")[0]}/graphql.json`]: {
111
+ headers: {
112
+ "content-type": "application/json",
113
+ "X-Shopify-Storefront-Access-Token": forceSfapiVersion.split(":")[1] ?? "3b580e70970c4528da70c98e097c2fa0"
114
+ }
115
+ }
116
+ },
117
+ config: {
118
+ defaultScalarType: "string",
119
+ scalars: { JSON: "unknown" }
120
+ }
121
+ }
109
122
  }
110
123
  }
111
124
  }
@@ -1,10 +1,10 @@
1
1
  import { fileExists } from '@shopify/cli-kit/node/fs';
2
2
  import { resolvePath } from '@shopify/cli-kit/node/path';
3
- import { outputInfo, outputContent, outputToken } from '@shopify/cli-kit/node/output';
3
+ import { linesToColumns } from '@shopify/cli-kit/common/string';
4
+ import { outputInfo } from '@shopify/cli-kit/node/output';
4
5
  import { readAndParseDotEnv } from '@shopify/cli-kit/node/dot-env';
5
- import { colors } from './colors.js';
6
+ import colors from '@shopify/cli-kit/node/colors';
6
7
  import { pullRemoteEnvironmentVariables } from './pull-environment-variables.js';
7
- import { getConfig } from './shopify-config.js';
8
8
 
9
9
  async function combinedEnvironmentVariables({
10
10
  envBranch,
@@ -28,47 +28,30 @@ async function combinedEnvironmentVariables({
28
28
  );
29
29
  const localKeys = new Set(Object.keys(localEnvironmentVariables));
30
30
  if ([...remoteKeys, ...localKeys].length) {
31
- outputInfo(
32
- `${colors.bold("Injecting environment variables into MiniOxygen...")}`
33
- );
31
+ outputInfo("\nEnvironment variables injected into MiniOxygen:\n");
34
32
  }
35
- let storefrontTitle = "";
36
- if (remoteEnvironmentVariables.length) {
37
- const { storefront } = await getConfig(root);
38
- if (storefront) {
39
- storefrontTitle = storefront.title;
40
- }
41
- }
42
- remoteEnvironmentVariables.forEach(({ key, isSecret }) => {
43
- if (localKeys.has(key)) {
44
- outputIgnoringKey(key, `overwritten via ${colors.yellow(".env")}`);
45
- } else if (isSecret) {
46
- outputIgnoringKey(key, "value is marked as secret");
47
- } else {
48
- outputUsingKey(key, storefrontTitle);
33
+ let rows = [];
34
+ remoteEnvironmentVariables.filter(({ isSecret }) => !isSecret).forEach(({ key }) => {
35
+ if (!localKeys.has(key)) {
36
+ rows.push([key, "from Oxygen"]);
49
37
  }
50
38
  });
51
- [...localKeys].forEach((keyName) => {
52
- outputUsingKey(keyName, ".env");
39
+ localKeys.forEach((key) => {
40
+ rows.push([key, "from local .env"]);
41
+ });
42
+ remoteEnvironmentVariables.filter(({ isSecret }) => isSecret).forEach(({ key }) => {
43
+ if (!localKeys.has(key)) {
44
+ rows.push([
45
+ colors.dim(key),
46
+ colors.dim(`from Oxygen (Marked as secret)`)
47
+ ]);
48
+ }
53
49
  });
50
+ outputInfo(linesToColumns(rows));
54
51
  return {
55
52
  ...formattedRemoteVariables,
56
53
  ...localEnvironmentVariables
57
54
  };
58
55
  }
59
- function outputUsingKey(keyName, source) {
60
- outputInfo(
61
- outputContent` Using ${outputToken.green(
62
- keyName
63
- )} from ${outputToken.yellow(source)}`.value
64
- );
65
- }
66
- function outputIgnoringKey(keyName, reason) {
67
- outputInfo(
68
- outputContent`${colors.dim(
69
- ` Ignoring ${colors.green(keyName)} (${reason})`
70
- )}`.value
71
- );
72
- }
73
56
 
74
57
  export { combinedEnvironmentVariables };
@@ -49,7 +49,7 @@ describe("combinedEnvironmentVariables()", () => {
49
49
  const outputMock = mockAndCaptureOutput();
50
50
  await combinedEnvironmentVariables({ root: tmpDir, shop: "my-shop" });
51
51
  expect(outputMock.info()).toMatch(
52
- /Injecting environment variables into MiniOxygen/
52
+ /Environment variables injected into MiniOxygen:/
53
53
  );
54
54
  });
55
55
  });
@@ -57,7 +57,7 @@ describe("combinedEnvironmentVariables()", () => {
57
57
  await inTemporaryDirectory(async (tmpDir) => {
58
58
  const outputMock = mockAndCaptureOutput();
59
59
  await combinedEnvironmentVariables({ root: tmpDir, shop: "my-shop" });
60
- expect(outputMock.info()).toMatch(/Using PUBLIC_API_TOKEN from Hydrogen/);
60
+ expect(outputMock.info()).toMatch(/PUBLIC_API_TOKEN\s+from Oxygen/);
61
61
  });
62
62
  });
63
63
  describe("when one of the variables is a secret", () => {
@@ -76,7 +76,7 @@ describe("combinedEnvironmentVariables()", () => {
76
76
  const outputMock = mockAndCaptureOutput();
77
77
  await combinedEnvironmentVariables({ root: tmpDir, shop: "my-shop" });
78
78
  expect(outputMock.info()).toMatch(
79
- /Ignoring PUBLIC_API_TOKEN \(value is marked as secret\)/
79
+ /PUBLIC_API_TOKEN\s+from Oxygen \(Marked as secret\)/
80
80
  );
81
81
  });
82
82
  });
@@ -88,7 +88,7 @@ describe("combinedEnvironmentVariables()", () => {
88
88
  await writeFile(filePath, "LOCAL_TOKEN=1");
89
89
  const outputMock = mockAndCaptureOutput();
90
90
  await combinedEnvironmentVariables({ root: tmpDir });
91
- expect(outputMock.info()).toMatch(/Using LOCAL_TOKEN from \.env/);
91
+ expect(outputMock.info()).toMatch(/LOCAL_TOKEN\s+from local \.env/);
92
92
  });
93
93
  });
94
94
  describe("and they overwrite remote variables", () => {
@@ -98,11 +98,11 @@ describe("combinedEnvironmentVariables()", () => {
98
98
  await writeFile(filePath, "PUBLIC_API_TOKEN=abc");
99
99
  const outputMock = mockAndCaptureOutput();
100
100
  await combinedEnvironmentVariables({ root: tmpDir, shop: "my-shop" });
101
- expect(outputMock.info()).toMatch(
102
- /Ignoring PUBLIC_API_TOKEN \(overwritten via \.env\)/
101
+ expect(outputMock.info()).not.toMatch(
102
+ /PUBLIC_API_TOKEN\s+from Oxygen/
103
103
  );
104
104
  expect(outputMock.info()).toMatch(
105
- /Using PUBLIC_API_TOKEN from \.env/
105
+ /PUBLIC_API_TOKEN\s+from local \.env/
106
106
  );
107
107
  });
108
108
  });
@@ -1,5 +1,7 @@
1
1
  import { ServerMode } from '@remix-run/dev/dist/config/serverModes.js';
2
+ export { ServerMode } from '@remix-run/dev/dist/config/serverModes.js';
2
3
  import { RemixConfig } from '@remix-run/dev/dist/config.js';
4
+ export { RemixConfig } from '@remix-run/dev/dist/config.js';
3
5
 
4
6
  declare function getProjectPaths(appPath?: string, entry?: string): {
5
7
  root: string;
@@ -8,7 +10,7 @@ declare function getProjectPaths(appPath?: string, entry?: string): {
8
10
  buildPathWorkerFile: string;
9
11
  publicPath: string;
10
12
  };
11
- declare function getRemixConfig(root: string, mode?: ServerMode): Promise<RemixConfig & {
13
+ declare function getRemixConfig(root: string, skipOxygenChecks?: boolean, mode?: ServerMode): Promise<RemixConfig & {
12
14
  serverConditions?: string[] | undefined;
13
15
  serverMainFields?: string[] | undefined;
14
16
  serverDependenciesToBundle?: string | undefined;
@@ -23,72 +23,76 @@ function getProjectPaths(appPath, entry) {
23
23
  publicPath
24
24
  };
25
25
  }
26
- async function getRemixConfig(root, mode = process.env.NODE_ENV) {
26
+ async function getRemixConfig(root, skipOxygenChecks = false, mode = process.env.NODE_ENV) {
27
27
  const { readConfig } = await import('@remix-run/dev/dist/config.js');
28
28
  const config = await readConfig(root, mode);
29
- if (!config.serverEntryPoint) {
30
- throwConfigError(
31
- "Could not find a server entry point.",
32
- "Please add a server option to your remix.config.js pointing to an Oxygen worker entry file."
33
- );
34
- } else {
35
- assertEntryFileExists(config.rootDirectory, config.serverEntryPoint);
36
- }
37
- if (config.serverPlatform !== "neutral") {
38
- throwConfigError(
39
- 'The serverPlatform in remix.config.js must be "neutral".'
40
- );
41
- }
42
- if (config.serverModuleFormat !== "esm") {
43
- throwConfigError(
44
- 'The serverModuleFormat in remix.config.js must be "esm".'
45
- );
46
- }
47
- if (config.serverDependenciesToBundle !== "all") {
48
- throwConfigError(
49
- 'The serverDependenciesToBundle in remix.config.js must be "all".'
50
- );
51
- }
52
- if (!config.serverConditions?.includes("worker")) {
53
- throwConfigError(
54
- 'The serverConditions in remix.config.js must include "worker".'
55
- );
56
- }
57
- if (process.env.NODE_ENV === "development" && !config.serverConditions?.includes("development")) {
58
- outputWarn(
59
- "Add `process.env.NODE_ENV` value to serverConditions in remix.config.js to enable debugging features in development."
60
- );
61
- }
62
- if (!config.serverMainFields || !oxygenServerMainFields.every((v, i) => config.serverMainFields?.[i] === v)) {
63
- throwConfigError(
64
- `The serverMainFields in remix.config.js must be ${JSON.stringify(
65
- oxygenServerMainFields
66
- )}.`
67
- );
68
- }
69
- const cdnUrl = process.env.HYDROGEN_ASSET_BASE_URL;
70
- if (cdnUrl && !config.publicPath.startsWith(cdnUrl)) {
71
- throwConfigError(
72
- "The publicPath in remix.config.js must be prepended with the value of `process.env.HYDROGEN_ASSET_BASE_URL`."
73
- );
74
- }
75
- const expectedServerBuildPath = path.join(
76
- BUILD_DIR,
77
- WORKER_SUBDIR,
78
- "index.js"
79
- );
80
- if (config.serverBuildPath !== path.resolve(root, expectedServerBuildPath)) {
81
- throwConfigError(
82
- `The serverBuildPath in remix.config.js must be "${expectedServerBuildPath}".`
83
- );
84
- }
85
- const expectedAssetsBuildDirectory = path.join(BUILD_DIR, CLIENT_SUBDIR);
86
- if (!config.assetsBuildDirectory.startsWith(
87
- path.resolve(root, expectedAssetsBuildDirectory)
88
- )) {
89
- throwConfigError(
90
- `The assetsBuildDirectory in remix.config.js must be in "${expectedAssetsBuildDirectory}".`
29
+ if (!skipOxygenChecks) {
30
+ if (!config.serverEntryPoint) {
31
+ throwConfigError(
32
+ "Could not find a server entry point.",
33
+ "Please add a server option to your remix.config.js pointing to an Oxygen worker entry file."
34
+ );
35
+ } else {
36
+ assertEntryFileExists(config.rootDirectory, config.serverEntryPoint);
37
+ }
38
+ if (config.serverPlatform !== "neutral") {
39
+ throwConfigError(
40
+ 'The serverPlatform in remix.config.js must be "neutral".'
41
+ );
42
+ }
43
+ if (config.serverModuleFormat !== "esm") {
44
+ throwConfigError(
45
+ 'The serverModuleFormat in remix.config.js must be "esm".'
46
+ );
47
+ }
48
+ if (config.serverDependenciesToBundle !== "all") {
49
+ throwConfigError(
50
+ 'The serverDependenciesToBundle in remix.config.js must be "all".'
51
+ );
52
+ }
53
+ if (!config.serverConditions?.includes("worker")) {
54
+ throwConfigError(
55
+ 'The serverConditions in remix.config.js must include "worker".'
56
+ );
57
+ }
58
+ if (process.env.NODE_ENV === "development" && !config.serverConditions?.includes("development")) {
59
+ outputWarn(
60
+ "Add `process.env.NODE_ENV` value to serverConditions in remix.config.js to enable debugging features in development."
61
+ );
62
+ }
63
+ if (!config.serverMainFields || !oxygenServerMainFields.every(
64
+ (v, i) => config.serverMainFields?.[i] === v
65
+ )) {
66
+ throwConfigError(
67
+ `The serverMainFields in remix.config.js must be ${JSON.stringify(
68
+ oxygenServerMainFields
69
+ )}.`
70
+ );
71
+ }
72
+ const cdnUrl = process.env.HYDROGEN_ASSET_BASE_URL;
73
+ if (cdnUrl && !config.publicPath.startsWith(cdnUrl)) {
74
+ throwConfigError(
75
+ "The publicPath in remix.config.js must be prepended with the value of `process.env.HYDROGEN_ASSET_BASE_URL`."
76
+ );
77
+ }
78
+ const expectedServerBuildPath = path.join(
79
+ BUILD_DIR,
80
+ WORKER_SUBDIR,
81
+ "index.js"
91
82
  );
83
+ if (config.serverBuildPath !== path.resolve(root, expectedServerBuildPath)) {
84
+ throwConfigError(
85
+ `The serverBuildPath in remix.config.js must be "${expectedServerBuildPath}".`
86
+ );
87
+ }
88
+ const expectedAssetsBuildDirectory = path.join(BUILD_DIR, CLIENT_SUBDIR);
89
+ if (!config.assetsBuildDirectory.startsWith(
90
+ path.resolve(root, expectedAssetsBuildDirectory)
91
+ )) {
92
+ throwConfigError(
93
+ `The assetsBuildDirectory in remix.config.js must be in "${expectedAssetsBuildDirectory}".`
94
+ );
95
+ }
92
96
  }
93
97
  if (process.env.LOCAL_DEV) {
94
98
  const packagesPath = fileURLToPath(new URL("../../..", import.meta.url));
@@ -6,6 +6,7 @@ declare const commonFlags: {
6
6
  force: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
7
7
  shop: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
8
8
  "env-branch": _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
9
+ sourcemap: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
9
10
  };
10
11
  declare function flagsToCamelObject(obj: Record<string, any>): any;
11
12
  /**
package/dist/lib/flags.js CHANGED
@@ -2,7 +2,7 @@ import { Flags } from '@oclif/core';
2
2
  import { camelize } from '@shopify/cli-kit/common/string';
3
3
  import { renderInfo } from '@shopify/cli-kit/node/ui';
4
4
  import { normalizeStoreFqdn } from '@shopify/cli-kit/node/context/fqdn';
5
- import { colors } from './colors.js';
5
+ import colors from '@shopify/cli-kit/node/colors';
6
6
 
7
7
  const commonFlags = {
8
8
  path: Flags.string({
@@ -28,8 +28,13 @@ const commonFlags = {
28
28
  ["env-branch"]: Flags.string({
29
29
  description: "Specify an environment's branch name when using remote environment variables.",
30
30
  env: "SHOPIFY_HYDROGEN_ENVIRONMENT_BRANCH",
31
- char: "e",
32
- hidden: true
31
+ char: "e"
32
+ }),
33
+ sourcemap: Flags.boolean({
34
+ description: "Generate sourcemaps for the build.",
35
+ env: "SHOPIFY_HYDROGEN_FLAG_SOURCEMAP",
36
+ default: true,
37
+ allowNo: true
33
38
  })
34
39
  };
35
40
  function flagsToCamelObject(obj) {
@@ -1,11 +1,14 @@
1
+ import { AdminSession } from '@shopify/cli-kit/node/session';
2
+
1
3
  declare const LinkStorefrontQuery = "#graphql\n query LinkStorefront {\n hydrogenStorefronts {\n id\n title\n productionUrl\n }\n }\n";
2
- interface HydrogenStorefront {
3
- id: string;
4
- title: string;
5
- productionUrl: string;
6
- }
7
- interface LinkStorefrontSchema {
8
- hydrogenStorefronts: HydrogenStorefront[];
9
- }
4
+ declare function getStorefronts(shop: string): Promise<{
5
+ adminSession: AdminSession;
6
+ storefronts: {
7
+ parsedId: string;
8
+ id: string;
9
+ title: string;
10
+ productionUrl: string;
11
+ }[];
12
+ }>;
10
13
 
11
- export { LinkStorefrontQuery, LinkStorefrontSchema };
14
+ export { LinkStorefrontQuery, getStorefronts };