@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.
- package/dist/commands/hydrogen/build.d.ts +1 -1
- package/dist/commands/hydrogen/build.js +24 -22
- package/dist/commands/hydrogen/check.js +1 -1
- package/dist/commands/hydrogen/codegen-unstable.d.ts +1 -0
- package/dist/commands/hydrogen/codegen-unstable.js +6 -0
- package/dist/commands/hydrogen/dev.d.ts +2 -1
- package/dist/commands/hydrogen/dev.js +85 -65
- package/dist/commands/hydrogen/env/list.d.ts +2 -3
- package/dist/commands/hydrogen/env/list.js +42 -44
- package/dist/commands/hydrogen/env/list.test.js +18 -24
- package/dist/commands/hydrogen/env/pull.d.ts +2 -3
- package/dist/commands/hydrogen/env/pull.js +42 -23
- package/dist/commands/hydrogen/env/pull.test.js +16 -4
- package/dist/commands/hydrogen/init.js +3 -13
- package/dist/commands/hydrogen/link.d.ts +0 -1
- package/dist/commands/hydrogen/link.js +34 -36
- package/dist/commands/hydrogen/link.test.js +43 -27
- package/dist/commands/hydrogen/list.d.ts +2 -2
- package/dist/commands/hydrogen/list.js +43 -39
- package/dist/commands/hydrogen/list.test.js +24 -32
- package/dist/commands/hydrogen/shortcut.js +6 -7
- package/dist/commands/hydrogen/shortcut.test.js +8 -9
- package/dist/commands/hydrogen/unlink.d.ts +0 -1
- package/dist/commands/hydrogen/unlink.js +5 -3
- package/dist/lib/admin-session.d.ts +1 -0
- package/dist/lib/codegen.d.ts +3 -2
- package/dist/lib/codegen.js +20 -7
- package/dist/lib/combined-environment-variables.js +19 -36
- package/dist/lib/combined-environment-variables.test.js +7 -7
- package/dist/lib/config.d.ts +3 -1
- package/dist/lib/config.js +67 -63
- package/dist/lib/flags.d.ts +1 -0
- package/dist/lib/flags.js +8 -3
- package/dist/lib/graphql/admin/link-storefront.d.ts +12 -9
- package/dist/lib/graphql/admin/link-storefront.js +18 -1
- package/dist/lib/graphql/admin/list-environments.d.ts +6 -5
- package/dist/lib/graphql/admin/list-environments.js +11 -1
- package/dist/lib/graphql/admin/list-storefronts.d.ts +13 -5
- package/dist/lib/graphql/admin/list-storefronts.js +18 -1
- package/dist/lib/graphql/admin/pull-variables.d.ts +6 -1
- package/dist/lib/graphql/admin/pull-variables.js +14 -1
- package/dist/lib/log.d.ts +2 -1
- package/dist/lib/log.js +8 -1
- package/dist/lib/mini-oxygen.js +1 -1
- package/dist/lib/process.d.ts +6 -0
- package/dist/lib/process.js +17 -0
- package/dist/lib/pull-environment-variables.d.ts +1 -0
- package/dist/lib/pull-environment-variables.js +4 -14
- package/dist/lib/remix-version-interop.js +1 -1
- package/dist/lib/shell.d.ts +5 -6
- package/dist/lib/shell.js +65 -17
- package/dist/lib/shell.test.d.ts +1 -0
- package/dist/lib/shell.test.js +85 -0
- package/dist/lib/shopify-config.d.ts +1 -1
- package/dist/lib/shopify-config.js +2 -2
- package/dist/lib/transpile-ts.js +6 -0
- package/oclif.manifest.json +1 -1
- package/package.json +9 -8
- package/dist/lib/colors.d.ts +0 -11
- 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 {
|
|
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
|
-
|
|
9
|
-
vi.mock("../../lib/graphql.js", async () => {
|
|
10
|
-
|
|
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: () =>
|
|
11
|
+
getHydrogenShop: () => SHOP_NAME
|
|
20
12
|
}));
|
|
21
13
|
describe("list", () => {
|
|
22
14
|
const ADMIN_SESSION = {
|
|
23
15
|
token: "abc123",
|
|
24
|
-
storeFqdn:
|
|
16
|
+
storeFqdn: SHOP_NAME
|
|
25
17
|
};
|
|
26
18
|
beforeEach(async () => {
|
|
27
|
-
vi.mocked(
|
|
28
|
-
|
|
29
|
-
|
|
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(
|
|
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(
|
|
46
|
-
|
|
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
|
-
/
|
|
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
|
-
"
|
|
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("
|
|
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,
|
|
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 (
|
|
40
|
+
if (await shellWriteAlias("zsh", ALIAS_NAME, BASH_ZSH_COMMAND)) {
|
|
42
41
|
shells.push("zsh");
|
|
43
42
|
}
|
|
44
|
-
if (
|
|
43
|
+
if (await shellWriteAlias("bash", ALIAS_NAME, BASH_ZSH_COMMAND)) {
|
|
45
44
|
shells.push("bash");
|
|
46
45
|
}
|
|
47
|
-
if (
|
|
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 {
|
|
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
|
-
|
|
17
|
-
|
|
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(
|
|
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(
|
|
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 {
|
|
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
|
-
|
|
26
|
+
renderSuccess({
|
|
27
|
+
body: ["You are no longer linked to", { bold: storefrontTitle }]
|
|
28
|
+
});
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export { Unlink as default, unlinkStorefront };
|
package/dist/lib/codegen.d.ts
CHANGED
|
@@ -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,
|
|
24
|
+
declare function generateTypes({ watch, configFilePath, forceSfapiVersion, ...dirs }: CodegenOptions): Promise<string[]>;
|
|
24
25
|
|
|
25
26
|
export { generateTypes, normalizeCodegenError, spawnCodegenProcess };
|
package/dist/lib/codegen.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
/
|
|
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(/
|
|
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
|
-
/
|
|
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(/
|
|
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
|
-
/
|
|
101
|
+
expect(outputMock.info()).not.toMatch(
|
|
102
|
+
/PUBLIC_API_TOKEN\s+from Oxygen/
|
|
103
103
|
);
|
|
104
104
|
expect(outputMock.info()).toMatch(
|
|
105
|
-
/
|
|
105
|
+
/PUBLIC_API_TOKEN\s+from local \.env/
|
|
106
106
|
);
|
|
107
107
|
});
|
|
108
108
|
});
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -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;
|
package/dist/lib/config.js
CHANGED
|
@@ -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 (!
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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));
|
package/dist/lib/flags.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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,
|
|
14
|
+
export { LinkStorefrontQuery, getStorefronts };
|