@shopify/cli-hydrogen 4.1.1 → 4.2.0
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/codegen-unstable.d.ts +14 -0
- package/dist/commands/hydrogen/codegen-unstable.js +64 -0
- package/dist/commands/hydrogen/dev.d.ts +5 -0
- package/dist/commands/hydrogen/dev.js +48 -6
- package/dist/commands/hydrogen/env/list.d.ts +19 -0
- package/dist/commands/hydrogen/env/list.js +96 -0
- package/dist/commands/hydrogen/env/list.test.d.ts +1 -0
- package/dist/commands/hydrogen/env/list.test.js +151 -0
- package/dist/commands/hydrogen/env/pull.d.ts +23 -0
- package/dist/commands/hydrogen/env/pull.js +68 -0
- package/dist/commands/hydrogen/env/pull.test.d.ts +1 -0
- package/dist/commands/hydrogen/env/pull.test.js +112 -0
- package/dist/commands/hydrogen/init.js +3 -1
- package/dist/commands/hydrogen/link.d.ts +24 -0
- package/dist/commands/hydrogen/link.js +102 -0
- package/dist/commands/hydrogen/link.test.d.ts +1 -0
- package/dist/commands/hydrogen/link.test.js +137 -0
- package/dist/commands/hydrogen/list.d.ts +21 -0
- package/dist/commands/hydrogen/list.js +83 -0
- package/dist/commands/hydrogen/list.test.d.ts +1 -0
- package/dist/commands/hydrogen/list.test.js +116 -0
- package/dist/commands/hydrogen/unlink.d.ts +17 -0
- package/dist/commands/hydrogen/unlink.js +29 -0
- package/dist/commands/hydrogen/unlink.test.d.ts +1 -0
- package/dist/commands/hydrogen/unlink.test.js +36 -0
- package/dist/generator-templates/routes/[robots.txt].tsx +111 -19
- package/dist/generator-templates/routes/collections/index.tsx +102 -0
- package/dist/lib/admin-session.d.ts +5 -0
- package/dist/lib/admin-session.js +16 -0
- package/dist/lib/admin-session.test.d.ts +1 -0
- package/dist/lib/admin-session.test.js +27 -0
- package/dist/lib/admin-urls.d.ts +8 -0
- package/dist/lib/admin-urls.js +18 -0
- package/dist/lib/codegen.d.ts +25 -0
- package/dist/lib/codegen.js +128 -0
- package/dist/lib/colors.d.ts +3 -0
- package/dist/lib/colors.js +4 -1
- package/dist/lib/combined-environment-variables.d.ts +8 -0
- package/dist/lib/combined-environment-variables.js +74 -0
- package/dist/lib/combined-environment-variables.test.d.ts +1 -0
- package/dist/lib/combined-environment-variables.test.js +111 -0
- package/dist/lib/flags.d.ts +2 -0
- package/dist/lib/flags.js +13 -0
- package/dist/lib/graphql/admin/link-storefront.d.ts +11 -0
- package/dist/lib/graphql/admin/link-storefront.js +11 -0
- package/dist/lib/graphql/admin/list-environments.d.ts +20 -0
- package/dist/lib/graphql/admin/list-environments.js +18 -0
- package/dist/lib/graphql/admin/list-storefronts.d.ts +17 -0
- package/dist/lib/graphql/admin/list-storefronts.js +16 -0
- package/dist/lib/graphql/admin/pull-variables.d.ts +16 -0
- package/dist/lib/graphql/admin/pull-variables.js +15 -0
- package/dist/lib/graphql.d.ts +21 -0
- package/dist/lib/graphql.js +18 -0
- package/dist/lib/graphql.test.d.ts +1 -0
- package/dist/lib/graphql.test.js +15 -0
- package/dist/lib/mini-oxygen.d.ts +4 -1
- package/dist/lib/mini-oxygen.js +7 -3
- package/dist/lib/missing-storefronts.d.ts +5 -0
- package/dist/lib/missing-storefronts.js +18 -0
- package/dist/lib/pull-environment-variables.d.ts +19 -0
- package/dist/lib/pull-environment-variables.js +67 -0
- package/dist/lib/pull-environment-variables.test.d.ts +1 -0
- package/dist/lib/pull-environment-variables.test.js +174 -0
- package/dist/lib/render-errors.d.ts +16 -0
- package/dist/lib/render-errors.js +37 -0
- package/dist/lib/shop.d.ts +7 -0
- package/dist/lib/shop.js +32 -0
- package/dist/lib/shop.test.d.ts +1 -0
- package/dist/lib/shop.test.js +78 -0
- package/dist/lib/shopify-config.d.ts +35 -0
- package/dist/lib/shopify-config.js +86 -0
- package/dist/lib/shopify-config.test.d.ts +1 -0
- package/dist/lib/shopify-config.test.js +209 -0
- package/oclif.manifest.json +1 -1
- package/package.json +7 -5
|
@@ -3,19 +3,28 @@ import {
|
|
|
3
3
|
type ErrorBoundaryComponent,
|
|
4
4
|
} from '@shopify/remix-oxygen';
|
|
5
5
|
import {useCatch, useRouteError, isRouteErrorResponse} from '@remix-run/react';
|
|
6
|
+
import type {Shop} from '@shopify/hydrogen/storefront-api-types';
|
|
7
|
+
import {parseGid} from '@shopify/hydrogen';
|
|
6
8
|
|
|
7
|
-
export const loader = ({request}: LoaderArgs) => {
|
|
9
|
+
export const loader = async ({request, context}: LoaderArgs) => {
|
|
8
10
|
const url = new URL(request.url);
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
const {shop} = await context.storefront.query<{shop: Pick<Shop, 'id'>}>(
|
|
13
|
+
SHOP_QUERY,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return new Response(
|
|
17
|
+
robotsTxtData({url: url.origin, shopId: parseGid(shop.id).id}),
|
|
18
|
+
{
|
|
19
|
+
status: 200,
|
|
20
|
+
headers: {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
22
|
+
'Content-Type': 'text/plain',
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
24
|
+
'Cache-Control': `max-age=${60 * 60 * 24}`,
|
|
25
|
+
},
|
|
17
26
|
},
|
|
18
|
-
|
|
27
|
+
);
|
|
19
28
|
};
|
|
20
29
|
|
|
21
30
|
export const ErrorBoundaryV1: ErrorBoundaryComponent = ({error}) => {
|
|
@@ -48,28 +57,111 @@ export function ErrorBoundary() {
|
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
function robotsTxtData({url}: {url
|
|
60
|
+
function robotsTxtData({url, shopId}: {shopId?: string; url?: string}) {
|
|
52
61
|
const sitemapUrl = url ? `${url}/sitemap.xml` : undefined;
|
|
53
62
|
|
|
54
63
|
return `
|
|
55
64
|
User-agent: *
|
|
56
|
-
|
|
57
|
-
Disallow: /cart
|
|
58
|
-
Disallow: /orders
|
|
59
|
-
Disallow: /checkouts/
|
|
60
|
-
Disallow: /checkout
|
|
61
|
-
Disallow: /carts
|
|
62
|
-
Disallow: /account
|
|
63
|
-
${sitemapUrl ? `Sitemap: ${sitemapUrl}` : ''}
|
|
65
|
+
${generalDisallowRules({sitemapUrl, shopId})}
|
|
64
66
|
|
|
65
67
|
# Google adsbot ignores robots.txt unless specifically named!
|
|
66
68
|
User-agent: adsbot-google
|
|
67
69
|
Disallow: /checkouts/
|
|
68
70
|
Disallow: /checkout
|
|
69
71
|
Disallow: /carts
|
|
70
|
-
Disallow: /orders
|
|
72
|
+
Disallow: /orders${
|
|
73
|
+
shopId
|
|
74
|
+
? `
|
|
75
|
+
Disallow: /${shopId}/checkouts
|
|
76
|
+
Disallow: /${shopId}/orders`
|
|
77
|
+
: ''
|
|
78
|
+
}
|
|
79
|
+
Disallow: /*?*oseid=*
|
|
80
|
+
Disallow: /*preview_theme_id*
|
|
81
|
+
Disallow: /*preview_script_id*
|
|
82
|
+
|
|
83
|
+
User-agent: Nutch
|
|
84
|
+
Disallow: /
|
|
85
|
+
|
|
86
|
+
User-agent: AhrefsBot
|
|
87
|
+
Crawl-delay: 10
|
|
88
|
+
${generalDisallowRules({sitemapUrl, shopId})}
|
|
89
|
+
|
|
90
|
+
User-agent: AhrefsSiteAudit
|
|
91
|
+
Crawl-delay: 10
|
|
92
|
+
${generalDisallowRules({sitemapUrl, shopId})}
|
|
93
|
+
|
|
94
|
+
User-agent: MJ12bot
|
|
95
|
+
Crawl-Delay: 10
|
|
71
96
|
|
|
72
97
|
User-agent: Pinterest
|
|
73
98
|
Crawl-delay: 1
|
|
74
99
|
`.trim();
|
|
75
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
*
|
|
104
|
+
* This function generates disallow rules that generally follow what Shopify's Online Store has as defaults for their robots.txt
|
|
105
|
+
*
|
|
106
|
+
*/
|
|
107
|
+
function generalDisallowRules({
|
|
108
|
+
shopId,
|
|
109
|
+
sitemapUrl,
|
|
110
|
+
}: {
|
|
111
|
+
shopId?: string;
|
|
112
|
+
sitemapUrl?: string;
|
|
113
|
+
}) {
|
|
114
|
+
return `Disallow: /admin
|
|
115
|
+
Disallow: /cart
|
|
116
|
+
Disallow: /orders
|
|
117
|
+
Disallow: /checkouts/
|
|
118
|
+
Disallow: /checkout${
|
|
119
|
+
shopId
|
|
120
|
+
? `
|
|
121
|
+
Disallow: /${shopId}/checkouts
|
|
122
|
+
Disallow: /${shopId}/orders`
|
|
123
|
+
: ''
|
|
124
|
+
}
|
|
125
|
+
Disallow: /carts
|
|
126
|
+
Disallow: /account
|
|
127
|
+
Disallow: /collections/*sort_by*
|
|
128
|
+
Disallow: /*/collections/*sort_by*
|
|
129
|
+
Disallow: /collections/*+*
|
|
130
|
+
Disallow: /collections/*%2B*
|
|
131
|
+
Disallow: /collections/*%2b*
|
|
132
|
+
Disallow: /*/collections/*+*
|
|
133
|
+
Disallow: /*/collections/*%2B*
|
|
134
|
+
Disallow: /*/collections/*%2b*
|
|
135
|
+
Disallow: */collections/*filter*&*filter*
|
|
136
|
+
Disallow: /blogs/*+*
|
|
137
|
+
Disallow: /blogs/*%2B*
|
|
138
|
+
Disallow: /blogs/*%2b*
|
|
139
|
+
Disallow: /*/blogs/*+*
|
|
140
|
+
Disallow: /*/blogs/*%2B*
|
|
141
|
+
Disallow: /*/blogs/*%2b*
|
|
142
|
+
Disallow: /*?*oseid=*
|
|
143
|
+
Disallow: /*preview_theme_id*
|
|
144
|
+
Disallow: /*preview_script_id*
|
|
145
|
+
Disallow: /policies/
|
|
146
|
+
Disallow: /*/*?*ls=*&ls=*
|
|
147
|
+
Disallow: /*/*?*ls%3D*%3Fls%3D*
|
|
148
|
+
Disallow: /*/*?*ls%3d*%3fls%3d*
|
|
149
|
+
Disallow: /search
|
|
150
|
+
Allow: /search/
|
|
151
|
+
Disallow: /search/?*
|
|
152
|
+
Disallow: /apple-app-site-association
|
|
153
|
+
Disallow: /.well-known/shopify/monorail${
|
|
154
|
+
sitemapUrl
|
|
155
|
+
? `
|
|
156
|
+
Sitemap: ${sitemapUrl}`
|
|
157
|
+
: ''
|
|
158
|
+
}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const SHOP_QUERY = `#graphql
|
|
162
|
+
query robots_shop_query {
|
|
163
|
+
shop {
|
|
164
|
+
id
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useLoaderData,
|
|
3
|
+
Link,
|
|
4
|
+
useRouteError,
|
|
5
|
+
isRouteErrorResponse,
|
|
6
|
+
useCatch,
|
|
7
|
+
} from '@remix-run/react';
|
|
8
|
+
import {
|
|
9
|
+
json,
|
|
10
|
+
type LoaderArgs,
|
|
11
|
+
type ErrorBoundaryComponent,
|
|
12
|
+
} from '@shopify/remix-oxygen';
|
|
13
|
+
import type {CollectionConnection} from '@shopify/hydrogen/storefront-api-types';
|
|
14
|
+
import {Image} from '@shopify/hydrogen';
|
|
15
|
+
|
|
16
|
+
export async function loader({context}: LoaderArgs) {
|
|
17
|
+
const {collectionConnection} = await context.storefront.query<{
|
|
18
|
+
collectionConnection: CollectionConnection;
|
|
19
|
+
}>(COLLECTIONS_QUERY, {
|
|
20
|
+
variables: {
|
|
21
|
+
country: context.storefront.i18n?.country,
|
|
22
|
+
language: context.storefront.i18n?.language,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return json({collectionConnection});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function Collections() {
|
|
30
|
+
const {collectionConnection} = useLoaderData<typeof loader>();
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
{collectionConnection.nodes.map((collection, collectionIndex) => {
|
|
35
|
+
return (
|
|
36
|
+
<Link key={collection.id} to={`/collections/${collection.handle}`}>
|
|
37
|
+
<h3>{collection.title}</h3>
|
|
38
|
+
{collection.image && (
|
|
39
|
+
<Image
|
|
40
|
+
data={collection.image}
|
|
41
|
+
loading={collectionIndex === 0 ? 'eager' : undefined}
|
|
42
|
+
/>
|
|
43
|
+
)}
|
|
44
|
+
</Link>
|
|
45
|
+
);
|
|
46
|
+
})}
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const ErrorBoundaryV1: ErrorBoundaryComponent = ({error}) => {
|
|
52
|
+
console.error(error);
|
|
53
|
+
|
|
54
|
+
return <div>There was an error.</div>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function CatchBoundary() {
|
|
58
|
+
const caught = useCatch();
|
|
59
|
+
console.error(caught);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div>
|
|
63
|
+
There was an error. Status: {caught.status}. Message:{' '}
|
|
64
|
+
{caught.data?.message}
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function ErrorBoundary() {
|
|
70
|
+
const error = useRouteError();
|
|
71
|
+
|
|
72
|
+
if (isRouteErrorResponse(error)) {
|
|
73
|
+
console.error(error.status, error.statusText, error.data);
|
|
74
|
+
return <div>Route Error</div>;
|
|
75
|
+
} else {
|
|
76
|
+
console.error((error as Error).message);
|
|
77
|
+
return <div>Thrown Error</div>;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const COLLECTIONS_QUERY = `#graphql
|
|
82
|
+
query collection_index(
|
|
83
|
+
$country: CountryCode
|
|
84
|
+
$language: LanguageCode
|
|
85
|
+
) @inContext(country: $country, language: $language)
|
|
86
|
+
{
|
|
87
|
+
collectionConnection: collections(first: 250) {
|
|
88
|
+
nodes {
|
|
89
|
+
id
|
|
90
|
+
title
|
|
91
|
+
handle
|
|
92
|
+
image {
|
|
93
|
+
id
|
|
94
|
+
url
|
|
95
|
+
altText
|
|
96
|
+
width
|
|
97
|
+
height
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
2
|
+
import { ensureAuthenticatedAdmin } from '@shopify/cli-kit/node/session';
|
|
3
|
+
|
|
4
|
+
async function getAdminSession(shop) {
|
|
5
|
+
let adminSession;
|
|
6
|
+
try {
|
|
7
|
+
adminSession = await ensureAuthenticatedAdmin(shop);
|
|
8
|
+
} catch {
|
|
9
|
+
throw new AbortError("Unable to authenticate with Shopify", void 0, [
|
|
10
|
+
`Ensure the shop that you specified is correct (you are trying to use: ${shop})`
|
|
11
|
+
]);
|
|
12
|
+
}
|
|
13
|
+
return adminSession;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { getAdminSession };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, vi, afterEach, it, expect } from 'vitest';
|
|
2
|
+
import { ensureAuthenticatedAdmin } from '@shopify/cli-kit/node/session';
|
|
3
|
+
import { AbortError } from '@shopify/cli-kit/node/error';
|
|
4
|
+
import { getAdminSession } from './admin-session.js';
|
|
5
|
+
|
|
6
|
+
describe("list", () => {
|
|
7
|
+
vi.mock("@shopify/cli-kit/node/session");
|
|
8
|
+
const ADMIN_SESSION = {
|
|
9
|
+
token: "abc123",
|
|
10
|
+
storeFqdn: "my-shop"
|
|
11
|
+
};
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
vi.resetAllMocks();
|
|
14
|
+
});
|
|
15
|
+
it("returns the admin session", async () => {
|
|
16
|
+
vi.mocked(ensureAuthenticatedAdmin).mockResolvedValue(ADMIN_SESSION);
|
|
17
|
+
const adminSession = await getAdminSession("my-shop");
|
|
18
|
+
expect(ensureAuthenticatedAdmin).toHaveBeenCalledWith("my-shop");
|
|
19
|
+
expect(adminSession).toStrictEqual(ADMIN_SESSION);
|
|
20
|
+
});
|
|
21
|
+
describe("when it fails to authenticate", () => {
|
|
22
|
+
it("throws an error", async () => {
|
|
23
|
+
vi.mocked(ensureAuthenticatedAdmin).mockRejectedValue({});
|
|
24
|
+
await expect(getAdminSession("my-shop")).rejects.toThrow(AbortError);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AdminSession } from '@shopify/cli-kit/node/session';
|
|
2
|
+
|
|
3
|
+
declare function newHydrogenStorefrontUrl(session: AdminSession): string;
|
|
4
|
+
declare function hydrogenStorefrontsUrl(session: AdminSession): string;
|
|
5
|
+
declare function hydrogenStorefrontUrl(session: AdminSession, storefrontId: string): string;
|
|
6
|
+
declare function hydrogenStorefrontSettingsUrl(session: AdminSession, storefrontId: string): string;
|
|
7
|
+
|
|
8
|
+
export { hydrogenStorefrontSettingsUrl, hydrogenStorefrontUrl, hydrogenStorefrontsUrl, newHydrogenStorefrontUrl };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function newHydrogenStorefrontUrl(session) {
|
|
2
|
+
const { storeFqdn } = session;
|
|
3
|
+
return `https://${storeFqdn}/admin/custom_storefronts/new`;
|
|
4
|
+
}
|
|
5
|
+
function hydrogenStorefrontsUrl(session) {
|
|
6
|
+
const { storeFqdn } = session;
|
|
7
|
+
return `https://${storeFqdn}/admin/custom_storefronts`;
|
|
8
|
+
}
|
|
9
|
+
function hydrogenStorefrontUrl(session, storefrontId) {
|
|
10
|
+
const { storeFqdn } = session;
|
|
11
|
+
return `https://${storeFqdn}/admin/custom_storefronts/${storefrontId}`;
|
|
12
|
+
}
|
|
13
|
+
function hydrogenStorefrontSettingsUrl(session, storefrontId) {
|
|
14
|
+
const { storeFqdn } = session;
|
|
15
|
+
return `https://${storeFqdn}/admin/custom_storefronts/${storefrontId}/settings`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { hydrogenStorefrontSettingsUrl, hydrogenStorefrontUrl, hydrogenStorefrontsUrl, newHydrogenStorefrontUrl };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as child_process from 'child_process';
|
|
2
|
+
import * as stream from 'stream';
|
|
3
|
+
export { patchGqlPluck } from '@shopify/hydrogen-codegen';
|
|
4
|
+
|
|
5
|
+
declare function normalizeCodegenError(errorMessage: string, rootDirectory?: string): {
|
|
6
|
+
message: string;
|
|
7
|
+
details: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Spawns a child process to run GraphlQL CLI Codegen.
|
|
11
|
+
* Running on a separate process splits work from this processor
|
|
12
|
+
* and also allows us to filter out logs.
|
|
13
|
+
*/
|
|
14
|
+
declare function spawnCodegenProcess({ rootDirectory, appDirectory, configFilePath, }: CodegenOptions): child_process.ChildProcessByStdio<null, null, stream.Readable>;
|
|
15
|
+
type ProjectDirs = {
|
|
16
|
+
rootDirectory: string;
|
|
17
|
+
appDirectory: string;
|
|
18
|
+
};
|
|
19
|
+
type CodegenOptions = ProjectDirs & {
|
|
20
|
+
configFilePath?: string;
|
|
21
|
+
watch?: boolean;
|
|
22
|
+
};
|
|
23
|
+
declare function generateTypes({ configFilePath, watch, ...dirs }: CodegenOptions): Promise<string[]>;
|
|
24
|
+
|
|
25
|
+
export { generateTypes, normalizeCodegenError, spawnCodegenProcess };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { loadCodegenConfig, generate } from '@graphql-codegen/cli';
|
|
2
|
+
import { patchGqlPluck, pluckConfig, preset, schema } from '@shopify/hydrogen-codegen';
|
|
3
|
+
export { patchGqlPluck } from '@shopify/hydrogen-codegen';
|
|
4
|
+
import { resolveFormatConfig, format } from './transpile-ts.js';
|
|
5
|
+
import { renderWarning, renderFatalError } from '@shopify/cli-kit/node/ui';
|
|
6
|
+
import { relativePath, joinPath } from '@shopify/cli-kit/node/path';
|
|
7
|
+
import { spawn } from 'node:child_process';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const nodePath = process.argv[1];
|
|
11
|
+
const modulePath = fileURLToPath(import.meta.url);
|
|
12
|
+
const isStandaloneProcess = nodePath === modulePath;
|
|
13
|
+
if (isStandaloneProcess) {
|
|
14
|
+
patchGqlPluck().then(
|
|
15
|
+
() => generateTypes({
|
|
16
|
+
rootDirectory: process.argv[2],
|
|
17
|
+
appDirectory: process.argv[3],
|
|
18
|
+
configFilePath: process.argv[4],
|
|
19
|
+
watch: true
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
function normalizeCodegenError(errorMessage, rootDirectory) {
|
|
24
|
+
const [first = "", ...rest] = errorMessage.replaceAll("[FAILED]", "").replace(/\s{2,}/g, "\n").replace(/\n,\n/, "\n").trim().split("\n");
|
|
25
|
+
const message = "[Codegen] " + first;
|
|
26
|
+
let details = rest.join("\n");
|
|
27
|
+
if (rootDirectory) {
|
|
28
|
+
const forwardSlashRootDir = rootDirectory.replaceAll("\\", "/") + "/";
|
|
29
|
+
details = details.replaceAll(forwardSlashRootDir, "");
|
|
30
|
+
}
|
|
31
|
+
return { message, details };
|
|
32
|
+
}
|
|
33
|
+
function spawnCodegenProcess({
|
|
34
|
+
rootDirectory,
|
|
35
|
+
appDirectory,
|
|
36
|
+
configFilePath
|
|
37
|
+
}) {
|
|
38
|
+
const child = spawn(
|
|
39
|
+
"node",
|
|
40
|
+
[
|
|
41
|
+
fileURLToPath(import.meta.url),
|
|
42
|
+
rootDirectory,
|
|
43
|
+
appDirectory,
|
|
44
|
+
configFilePath ?? ""
|
|
45
|
+
],
|
|
46
|
+
{ stdio: ["inherit", "ignore", "pipe"] }
|
|
47
|
+
);
|
|
48
|
+
child.stderr.on("data", (data) => {
|
|
49
|
+
const dataString = typeof data === "string" ? data : data?.toString?.("utf8") ?? "";
|
|
50
|
+
if (!dataString)
|
|
51
|
+
return;
|
|
52
|
+
const { message, details } = normalizeCodegenError(dataString, rootDirectory);
|
|
53
|
+
console.log("");
|
|
54
|
+
renderWarning({ headline: message, body: details });
|
|
55
|
+
});
|
|
56
|
+
child.on("close", (code) => {
|
|
57
|
+
if (code && code > 0) {
|
|
58
|
+
renderFatalError({
|
|
59
|
+
type: 0,
|
|
60
|
+
name: "CodegenError",
|
|
61
|
+
message: `Codegen process exited with code ${code}`,
|
|
62
|
+
tryMessage: "Try restarting the dev server."
|
|
63
|
+
});
|
|
64
|
+
process.exit(code);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return child;
|
|
68
|
+
}
|
|
69
|
+
async function generateTypes({
|
|
70
|
+
configFilePath,
|
|
71
|
+
watch,
|
|
72
|
+
...dirs
|
|
73
|
+
}) {
|
|
74
|
+
const { config: codegenConfig } = await loadCodegenConfig({
|
|
75
|
+
configFilePath,
|
|
76
|
+
searchPlaces: [dirs.rootDirectory]
|
|
77
|
+
}) || generateDefaultConfig(dirs);
|
|
78
|
+
await addHooksToHydrogenOptions(codegenConfig, dirs);
|
|
79
|
+
await generate(
|
|
80
|
+
{
|
|
81
|
+
...codegenConfig,
|
|
82
|
+
cwd: dirs.rootDirectory,
|
|
83
|
+
watch,
|
|
84
|
+
silent: !watch
|
|
85
|
+
},
|
|
86
|
+
true
|
|
87
|
+
);
|
|
88
|
+
return Object.keys(codegenConfig.generates);
|
|
89
|
+
}
|
|
90
|
+
function generateDefaultConfig({
|
|
91
|
+
rootDirectory,
|
|
92
|
+
appDirectory
|
|
93
|
+
}) {
|
|
94
|
+
const tsDefaultGlob = "*!(*.d).{ts,tsx}";
|
|
95
|
+
const appDirRelative = relativePath(rootDirectory, appDirectory);
|
|
96
|
+
return {
|
|
97
|
+
filepath: "virtual:codegen",
|
|
98
|
+
config: {
|
|
99
|
+
overwrite: true,
|
|
100
|
+
pluckConfig,
|
|
101
|
+
generates: {
|
|
102
|
+
["storefrontapi.generated.d.ts"]: {
|
|
103
|
+
preset,
|
|
104
|
+
schema,
|
|
105
|
+
documents: [
|
|
106
|
+
tsDefaultGlob,
|
|
107
|
+
joinPath(appDirRelative, "**", tsDefaultGlob)
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
async function addHooksToHydrogenOptions(codegenConfig, { rootDirectory }) {
|
|
115
|
+
const [, options] = Object.entries(codegenConfig.generates).find(
|
|
116
|
+
([, value]) => (Array.isArray(value) ? value[0] : value)?.schema === schema
|
|
117
|
+
) || [];
|
|
118
|
+
const hydrogenOptions = Array.isArray(options) ? options[0] : options;
|
|
119
|
+
if (hydrogenOptions) {
|
|
120
|
+
const formatConfig = await resolveFormatConfig(rootDirectory);
|
|
121
|
+
hydrogenOptions.hooks = {
|
|
122
|
+
beforeOneFileWrite: (file, content) => format(content, formatConfig, file),
|
|
123
|
+
...hydrogenOptions.hooks
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { generateTypes, normalizeCodegenError, spawnCodegenProcess };
|
package/dist/lib/colors.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import ansiColors from 'ansi-colors';
|
|
|
3
3
|
declare const colors: {
|
|
4
4
|
dim: ansiColors.StyleFunction;
|
|
5
5
|
bold: ansiColors.StyleFunction;
|
|
6
|
+
green: ansiColors.StyleFunction;
|
|
7
|
+
whiteBright: ansiColors.StyleFunction;
|
|
8
|
+
yellow: ansiColors.StyleFunction;
|
|
6
9
|
};
|
|
7
10
|
|
|
8
11
|
export { colors };
|
package/dist/lib/colors.js
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { fileExists } from '@shopify/cli-kit/node/fs';
|
|
2
|
+
import { resolvePath } from '@shopify/cli-kit/node/path';
|
|
3
|
+
import { outputInfo, outputContent, outputToken } from '@shopify/cli-kit/node/output';
|
|
4
|
+
import { readAndParseDotEnv } from '@shopify/cli-kit/node/dot-env';
|
|
5
|
+
import { colors } from './colors.js';
|
|
6
|
+
import { pullRemoteEnvironmentVariables } from './pull-environment-variables.js';
|
|
7
|
+
import { getConfig } from './shopify-config.js';
|
|
8
|
+
|
|
9
|
+
async function combinedEnvironmentVariables({
|
|
10
|
+
envBranch,
|
|
11
|
+
root,
|
|
12
|
+
shop
|
|
13
|
+
}) {
|
|
14
|
+
const remoteEnvironmentVariables = await pullRemoteEnvironmentVariables({
|
|
15
|
+
root,
|
|
16
|
+
flagShop: shop,
|
|
17
|
+
silent: true,
|
|
18
|
+
envBranch
|
|
19
|
+
});
|
|
20
|
+
const formattedRemoteVariables = remoteEnvironmentVariables?.reduce(
|
|
21
|
+
(a, v) => ({ ...a, [v.key]: v.value }),
|
|
22
|
+
{}
|
|
23
|
+
);
|
|
24
|
+
const dotEnvPath = resolvePath(root, ".env");
|
|
25
|
+
const localEnvironmentVariables = await fileExists(dotEnvPath) ? (await readAndParseDotEnv(dotEnvPath)).variables : {};
|
|
26
|
+
const remoteKeys = new Set(
|
|
27
|
+
remoteEnvironmentVariables.map((variable) => variable.key)
|
|
28
|
+
);
|
|
29
|
+
const localKeys = new Set(Object.keys(localEnvironmentVariables));
|
|
30
|
+
if ([...remoteKeys, ...localKeys].length) {
|
|
31
|
+
outputInfo(
|
|
32
|
+
`${colors.bold("Injecting environment variables into MiniOxygen...")}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
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);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
[...localKeys].forEach((keyName) => {
|
|
52
|
+
outputUsingKey(keyName, ".env");
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
...formattedRemoteVariables,
|
|
56
|
+
...localEnvironmentVariables
|
|
57
|
+
};
|
|
58
|
+
}
|
|
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
|
+
|
|
74
|
+
export { combinedEnvironmentVariables };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|