@shopify/cli-kit 4.3.0 → 4.5.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/cli/api/graphql/bulk-operations/generated/bulk-operation-cancel.d.ts +28 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-cancel.js +74 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-cancel.js.map +1 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-run-mutation.d.ts +28 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-run-mutation.js +92 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-run-mutation.js.map +1 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-run-query.d.ts +26 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-run-query.js +72 -0
- package/dist/cli/api/graphql/bulk-operations/generated/bulk-operation-run-query.js.map +1 -0
- package/dist/cli/api/graphql/bulk-operations/generated/get-bulk-operation-by-id.d.ts +19 -0
- package/dist/cli/api/graphql/bulk-operations/generated/get-bulk-operation-by-id.js +49 -0
- package/dist/cli/api/graphql/bulk-operations/generated/get-bulk-operation-by-id.js.map +1 -0
- package/dist/cli/api/graphql/bulk-operations/generated/list-bulk-operations.d.ts +22 -0
- package/dist/cli/api/graphql/bulk-operations/generated/list-bulk-operations.js +78 -0
- package/dist/cli/api/graphql/bulk-operations/generated/list-bulk-operations.js.map +1 -0
- package/dist/cli/api/graphql/bulk-operations/generated/staged-uploads-create.d.ts +22 -0
- package/dist/cli/api/graphql/bulk-operations/generated/staged-uploads-create.js +82 -0
- package/dist/cli/api/graphql/bulk-operations/generated/staged-uploads-create.js.map +1 -0
- package/dist/private/node/api/headers.js +1 -1
- package/dist/private/node/api/headers.js.map +1 -1
- package/dist/private/node/ui/components/Alert.test.js +5 -5
- package/dist/private/node/ui/components/Alert.test.js.map +1 -1
- package/dist/private/node/ui/components/Banner.js +9 -1
- package/dist/private/node/ui/components/Banner.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/api/admin.d.ts +2 -1
- package/dist/public/node/api/admin.js +4 -3
- package/dist/public/node/api/admin.js.map +1 -1
- package/dist/public/node/api/bulk-operations/cancel.d.ts +15 -0
- package/dist/public/node/api/bulk-operations/cancel.js +20 -0
- package/dist/public/node/api/bulk-operations/cancel.js.map +1 -0
- package/dist/public/node/api/bulk-operations/constants.d.ts +5 -0
- package/dist/public/node/api/bulk-operations/constants.js +6 -0
- package/dist/public/node/api/bulk-operations/constants.js.map +1 -0
- package/dist/public/node/api/bulk-operations/download-bulk-operation-results.d.ts +17 -0
- package/dist/public/node/api/bulk-operations/download-bulk-operation-results.js +48 -0
- package/dist/public/node/api/bulk-operations/download-bulk-operation-results.js.map +1 -0
- package/dist/public/node/api/bulk-operations/fetch.d.ts +31 -0
- package/dist/public/node/api/bulk-operations/fetch.js +42 -0
- package/dist/public/node/api/bulk-operations/fetch.js.map +1 -0
- package/dist/public/node/api/bulk-operations/format-bulk-operation-status.d.ts +45 -0
- package/dist/public/node/api/bulk-operations/format-bulk-operation-status.js +91 -0
- package/dist/public/node/api/bulk-operations/format-bulk-operation-status.js.map +1 -0
- package/dist/public/node/api/bulk-operations/helpers.d.ts +51 -0
- package/dist/public/node/api/bulk-operations/helpers.js +110 -0
- package/dist/public/node/api/bulk-operations/helpers.js.map +1 -0
- package/dist/public/node/api/bulk-operations/query.d.ts +22 -0
- package/dist/public/node/api/bulk-operations/query.js +40 -0
- package/dist/public/node/api/bulk-operations/query.js.map +1 -0
- package/dist/public/node/api/bulk-operations/run-mutation.d.ts +16 -0
- package/dist/public/node/api/bulk-operations/run-mutation.js +27 -0
- package/dist/public/node/api/bulk-operations/run-mutation.js.map +1 -0
- package/dist/public/node/api/bulk-operations/run-query.d.ts +15 -0
- package/dist/public/node/api/bulk-operations/run-query.js +19 -0
- package/dist/public/node/api/bulk-operations/run-query.js.map +1 -0
- package/dist/public/node/api/bulk-operations/stage-file.d.ts +13 -0
- package/dist/public/node/api/bulk-operations/stage-file.js +89 -0
- package/dist/public/node/api/bulk-operations/stage-file.js.map +1 -0
- package/dist/public/node/api/bulk-operations/watch-bulk-operation.d.ts +26 -0
- package/dist/public/node/api/bulk-operations/watch-bulk-operation.js +131 -0
- package/dist/public/node/api/bulk-operations/watch-bulk-operation.js.map +1 -0
- package/dist/public/node/api/bulk-operations.d.ts +18 -0
- package/dist/public/node/api/bulk-operations.js +19 -0
- package/dist/public/node/api/bulk-operations.js.map +1 -0
- package/dist/public/node/constants.d.ts +1 -0
- package/dist/public/node/constants.js +2 -0
- package/dist/public/node/constants.js.map +1 -0
- package/dist/public/node/context/fqdn.js +45 -4
- package/dist/public/node/context/fqdn.js.map +1 -1
- package/dist/public/node/graphiql/session.d.ts +50 -0
- package/dist/public/node/graphiql/session.js +92 -0
- package/dist/public/node/graphiql/session.js.map +1 -0
- package/dist/public/node/graphiql/templates/graphiql.js +1 -4
- package/dist/public/node/graphiql/templates/graphiql.js.map +1 -1
- package/dist/public/node/store-auth-session.d.ts +113 -0
- package/dist/public/node/store-auth-session.js +257 -0
- package/dist/public/node/store-auth-session.js.map +1 -0
- package/dist/public/node/ui.d.ts +2 -6
- package/dist/public/node/ui.js +2 -6
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphiql.js","sourceRoot":"","sources":["../../../../../src/public/node/graphiql/templates/graphiql.tsx"],"names":[],"mappings":"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","sourcesContent":["import {platformAndArch} from '../../os.js'\nimport {MUTATIONS_BLOCKED_MESSAGE} from '../server.js'\nimport React from 'react'\nimport {renderToStaticMarkup} from 'react-dom/server'\nimport {AppProvider, Badge, Banner, BlockStack, Box, Grid, InlineStack, Link, Select, Text} from '@shopify/polaris'\nimport {AlertCircleIcon, DisabledIcon, LinkIcon} from '@shopify/polaris-icons'\n\nconst controlKey = platformAndArch().platform === 'darwin' ? 'MAC_COMMAND_KEY' : 'Ctrl'\n\nconst graphiqlIntroMessage = `\n# Welcome to GraphiQL for the Shopify Admin API! If you've used\n# GraphiQL before, you can jump to the next tab.\n#\n# GraphiQL is an in-browser tool for writing, validating, and\n# testing GraphQL queries.\n#\n# Type queries into this side of the screen, and you will see intelligent\n# typeaheads aware of the current GraphQL type schema and live syntax and\n# validation errors highlighted within the text.\n#\n# GraphQL queries typically start with a \"{\" character. Lines that start\n# with a # are ignored.\n#\n# Keyboard shortcuts:\n#\n# Prettify query: Shift-${controlKey}-P (or press the prettify button)\n#\n# Merge fragments: Shift-${controlKey}-M (or press the merge button)\n#\n# Run Query: ${controlKey}-Enter (or press the play button)\n#\n# Auto Complete: ${controlKey}-Space (or just start typing)\n#\n`\n\nexport const defaultQuery = `query shopInfo {\n shop {\n name\n url\n myshopifyDomain\n plan {\n displayName\n partnerDevelopment\n shopifyPlus\n }\n }\n}\n`.replace(/\\n/g, '\\\\n')\n\ninterface GraphiQLTemplateOptions {\n apiVersion: string\n apiVersions: string[]\n appName?: string\n appUrl?: string\n key: string\n storeFqdn: string\n protectMutations?: boolean\n}\n\nexport function graphiqlTemplate({\n apiVersion,\n apiVersions,\n appName,\n appUrl,\n key,\n storeFqdn,\n protectMutations = false,\n}: GraphiQLTemplateOptions): string {\n const hasAppContext = Boolean(appName && appUrl)\n const unauthorizedLabel = hasAppContext ? 'App uninstalled' : 'Auth invalid'\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>GraphiQL</title>\n <link rel=\"shortcut icon\" href=\"{{url}}/graphiql/favicon.ico\" type=\"image/x-icon\" />\n <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@shopify/polaris@12.10.0/build/esm/styles.css\" />\n <style>\n body {\n height: 100%;\n margin: 0;\n width: 100%;\n overflow: hidden;\n }\n .Polaris-Page--fullWidth {\n width: 100%;\n }\n #top-bar {\n border-bottom: 1px solid var(--p-color-border);\n }\n #top-bar #top-error-bar {\n display: none;\n }\n #top-error-bar .Polaris-FullscreenBar__BackAction {\n /* hide default back button in FullscreenBar component */\n display: none;\n }\n #top-error-bar button {\n /* hide X to dismiss banner */\n display: none;\n }\n #top-bar .top-bar-section {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n }\n #top-bar .Polaris-Grid-Cell:nth-child(2) {\n justify-self: right;\n }\n #top-bar #scopes-note {\n display: inline-flex;\n align-items: center;\n height: 100%;\n }\n #top-bar .status-badge-option {\n gap: 8px;\n display: none;\n }\n #top-bar #status-badge-running {\n display: flex;\n }\n #graphiql {\n height: 100vh;\n display: flex;\n flex-direction: column;\n }\n #graphiql-explorer {\n flex-grow: 1;\n overflow: auto;\n }\n #top-bar #outbound-links a {\n line-height: 0;\n }\n #top-bar #outbound-links a:hover .Polaris-Text--root {\n text-decoration: underline;\n }\n #top-bar #outbound-links a span.Polaris-Text--root {\n max-width: max(12vw, 150px);\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n }\n .with-shrunk-icon .Polaris-Icon {\n height: 1rem;\n width: 1rem;\n margin: 0.125rem;\n }\n @media only screen and (max-width: 1550px) {\n .top-bar-section-title {\n display: none;\n }\n }\n @media only screen and (max-width: 1150px) {\n #top-bar #outbound-links a span.Polaris-Text--root {\n max-width: max(12vw, 140px);\n }\n }\n @media only screen and (max-width: 1080px) {\n #top-bar .Polaris-Grid-Cell:nth-child(2) {\n justify-self: left;\n }\n }\n @media only screen and (max-width: 650px) {\n #top-bar #outbound-links a span.Polaris-Text--root {\n max-width: 17vw;\n }\n }\n </style>\n\n <script\n src=\"https://cdn.jsdelivr.net/npm/react@17/umd/react.development.js\"\n integrity=\"sha512-Vf2xGDzpqUOEIKO+X2rgTLWPY+65++WPwCHkX2nFMu9IcstumPsf/uKKRd5prX3wOu8Q0GBylRpsDB26R6ExOg==\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n src=\"https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.development.js\"\n integrity=\"sha512-Wr9OKCTtq1anK0hq5bY3X/AvDI5EflDSAh0mE9gma+4hl+kXdTJPKZ3TwLMBcrgUeoY0s3dq9JjhCQc7vddtFg==\"\n crossorigin=\"anonymous\"\n ></script>\n <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/graphiql@3.0.4/graphiql.min.css\" />\n </head>\n <body>\n <div id=\"graphiql\">\n ${renderToStaticMarkup(\n <AppProvider i18n={{}}>\n <div id=\"top-bar\">\n <Box background=\"bg-surface\" padding=\"400\">\n <BlockStack gap=\"300\">\n <Grid columns={{xs: 3, sm: 3, md: 3}}>\n <Grid.Cell columnSpan={{xs: 3, sm: 3, md: 3, lg: 7, xl: 7}}>\n <InlineStack gap=\"400\">\n <div id=\"status-badge\" className=\"top-bar-section\">\n <div className=\"status-badge-option\" id=\"status-badge-running\">\n <span className=\"top-bar-section-title\">Status: </span>\n <Badge tone=\"success\" progress=\"complete\">\n Running\n </Badge>\n </div>\n <div className=\"status-badge-option with-shrunk-icon\" id=\"status-badge-unauthorized\">\n <span className=\"top-bar-section-title\">Status: </span>\n <Badge tone=\"attention\" icon={AlertCircleIcon}>\n {unauthorizedLabel}\n </Badge>\n </div>\n <div className=\"status-badge-option with-shrunk-icon\" id=\"status-badge-disconnected\">\n <span className=\"top-bar-section-title\">Status: </span>\n <Badge tone=\"critical\" icon={DisabledIcon}>\n Disconnected\n </Badge>\n </div>\n </div>\n <div id=\"version-select\" className=\"top-bar-section\">\n <span className=\"top-bar-section-title\">API version: </span>\n <Select\n label=\"API version\"\n labelHidden\n options={apiVersions}\n value={apiVersion}\n onChange={() => {}}\n />\n </div>\n {linkPills({storeFqdn, appName, appUrl})}\n </InlineStack>\n </Grid.Cell>\n <Grid.Cell columnSpan={{xs: 3, sm: 3, md: 3, lg: 5, xl: 5}}>\n <div id=\"scopes-note\" className=\"top-bar-section\">\n <Text as=\"span\" tone=\"subdued\">\n {scopesNoteText({hasAppContext, protectMutations})}\n </Text>\n </div>\n </Grid.Cell>\n </Grid>\n <div id=\"top-error-bar\">\n <Banner tone=\"critical\" onDismiss={() => {}} icon={DisabledIcon}>\n <p>\n The server has been stopped. Restart <code>dev</code> from the CLI.\n </p>\n </Banner>\n </div>\n </BlockStack>\n </Box>\n </div>\n </AppProvider>,\n )}\n <div id=\"graphiql-explorer\">Loading...</div>\n </div>\n <script\n src=\"https://cdn.jsdelivr.net/npm/graphiql@3.0.4/graphiql.min.js\"\n type=\"application/javascript\"\n ></script>\n <script>\n const macCommandKey = String.fromCodePoint(8984)\n const renderGraphiQL = function(apiVersion) {\n ReactDOM.render(\n React.createElement(GraphiQL, {\n fetcher: GraphiQL.createFetcher({\n url: '{{url}}/graphiql/graphql.json?key=${encodeURIComponent(key)}&api_version=' + apiVersion,\n }),\n defaultEditorToolsVisibility: true,\n {% if query %}\n query: {{query}},\n {% endif %}\n {% if variables %}\n variables: {{variables}},\n {% endif %}\n defaultTabs: [\n {query: \"${graphiqlIntroMessage\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')}\".replace(/MAC_COMMAND_KEY/g, macCommandKey)},\n {%for query in defaultQueries%}\n {query: \"{%if query.preface %}{{query.preface}}\\\\n{% endif %}{{query.query}}\", variables: \"{{query.variables}}\"},\n {%endfor%}\n ],\n isHeadersEditorEnabled: true,\n }),\n document.getElementById('graphiql-explorer'),\n )\n }\n renderGraphiQL('${apiVersion}')\n\n // Update the version when the select changes\n document.getElementById('version-select').addEventListener('change', function(event) {\n document.querySelector('#version-select .Polaris-Select__SelectedOption').innerText = event.target.value\n renderGraphiQL(event.target.value)\n })\n\n // Start out optimistic\n let serverIsLive = true\n let appIsInstalled = true\n\n const updateBadge = function() {\n const topErrorBar = document.querySelector('#graphiql #top-error-bar')\n const statusDiv = document.querySelector('#graphiql #status-badge')\n const allBadgeDivs = Array.from(statusDiv.querySelectorAll('.status-badge-option'))\n let activeBadge = 'running'\n if (!appIsInstalled) activeBadge = 'unauthorized'\n if (!serverIsLive) activeBadge = 'disconnected'\n allBadgeDivs.forEach(function(badge) {\n if (badge.id == ('status-badge-' + activeBadge)) {\n badge.style.display = 'flex'\n } else {\n badge.style.display = 'none'\n }\n })\n topErrorBar.style.display = serverIsLive ? 'none' : 'block'\n }\n const statusInterval = setInterval(updateBadge, 1000)\n\n // Warn when the server has been stopped\n const displayErrorServerStoppedTimeouts = []\n const pingInterval = setInterval(function() {\n displayErrorServerStoppedTimeouts.push(setTimeout(function() { serverIsLive = false }, 3000))\n fetch('{{url}}/graphiql/ping')\n .then(function(response) {\n if (response.status === 200) {\n while (displayErrorServerStoppedTimeouts.length > 0) {\n const timeout = displayErrorServerStoppedTimeouts.pop()\n clearTimeout(timeout)\n }\n serverIsLive = true\n } else {\n serverIsLive = false\n }\n })\n }, 2000)\n\n // Verify the current store/app connection\n setInterval(function() {\n fetch('{{ url }}/graphiql/status?key=${encodeURIComponent(key)}')\n .then(async function(response) {\n const {status, storeFqdn, appName, appUrl} = await response.json()\n appIsInstalled = status === 'OK'\n if (storeFqdn) {\n ${\n hasAppContext\n ? `document.getElementById('outbound-links').innerHTML = \\`${renderToStaticMarkup(\n <AppProvider i18n={{}}>\n {\n // eslint-disable-next-line no-template-curly-in-string\n linkPills({storeFqdn: '${storeFqdn}', appName: '${appName}', appUrl: '${appUrl}'})\n }\n </AppProvider>,\n )}\\``\n : `document.getElementById('outbound-links').innerHTML = \\`${renderToStaticMarkup(\n <AppProvider i18n={{}}>\n {\n // eslint-disable-next-line no-template-curly-in-string\n linkPills({storeFqdn: '${storeFqdn}'})\n }\n </AppProvider>,\n )}\\``\n }\n }\n })\n }, 5000)\n </script>\n </body>\n</html>\n`\n}\n\ninterface LinkPillOptions {\n storeFqdn: string\n appName?: string\n appUrl?: string\n}\n\nfunction linkPills({storeFqdn, appName, appUrl}: LinkPillOptions) {\n return (\n <div id=\"outbound-links\" className=\"top-bar-section with-shrunk-icon\">\n <span className=\"top-bar-section-title\">Store: </span>\n <Link url={`https://${storeFqdn}/admin`} target=\"_blank\">\n <Badge tone=\"info\" icon={LinkIcon} children={storeFqdn} />\n </Link>\n {appName && appUrl ? (\n <>\n <span className=\"top-bar-section-title\">App: </span>\n <Link url={appUrl} target=\"_blank\">\n <Badge tone=\"info\" icon={LinkIcon} children={appName} />\n </Link>\n </>\n ) : null}\n </div>\n )\n}\n\nfunction scopesNoteText({\n hasAppContext,\n protectMutations,\n}: {\n hasAppContext: boolean\n protectMutations: boolean\n}): string {\n if (protectMutations) {\n return MUTATIONS_BLOCKED_MESSAGE\n }\n if (hasAppContext) {\n return \"GraphiQL runs on the same access scopes you've defined in the TOML file for your app.\"\n }\n return 'GraphiQL runs with the access scopes granted to the stored app authentication for this store.'\n}\n"]}
|
|
1
|
+
{"version":3,"file":"graphiql.js","sourceRoot":"","sources":["../../../../../src/public/node/graphiql/templates/graphiql.tsx"],"names":[],"mappings":"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","sourcesContent":["import {platformAndArch} from '../../os.js'\nimport {MUTATIONS_BLOCKED_MESSAGE} from '../server.js'\nimport React from 'react'\nimport {renderToStaticMarkup} from 'react-dom/server'\nimport {AppProvider, Badge, Banner, BlockStack, Box, Grid, InlineStack, Link, Select, Text} from '@shopify/polaris'\nimport {AlertCircleIcon, DisabledIcon, LinkIcon} from '@shopify/polaris-icons'\n\nconst controlKey = platformAndArch().platform === 'darwin' ? 'MAC_COMMAND_KEY' : 'Ctrl'\n\nconst graphiqlIntroMessage = `\n# Welcome to GraphiQL for the Shopify Admin API! If you've used\n# GraphiQL before, you can jump to the next tab.\n#\n# GraphiQL is an in-browser tool for writing, validating, and\n# testing GraphQL queries.\n#\n# Type queries into this side of the screen, and you will see intelligent\n# typeaheads aware of the current GraphQL type schema and live syntax and\n# validation errors highlighted within the text.\n#\n# GraphQL queries typically start with a \"{\" character. Lines that start\n# with a # are ignored.\n#\n# Keyboard shortcuts:\n#\n# Prettify query: Shift-${controlKey}-P (or press the prettify button)\n#\n# Merge fragments: Shift-${controlKey}-M (or press the merge button)\n#\n# Run Query: ${controlKey}-Enter (or press the play button)\n#\n# Auto Complete: ${controlKey}-Space (or just start typing)\n#\n`\n\nexport const defaultQuery = `query shopInfo {\n shop {\n name\n url\n myshopifyDomain\n plan {\n displayName\n partnerDevelopment\n shopifyPlus\n }\n }\n}\n`.replace(/\\n/g, '\\\\n')\n\ninterface GraphiQLTemplateOptions {\n apiVersion: string\n apiVersions: string[]\n appName?: string\n appUrl?: string\n key: string\n storeFqdn: string\n protectMutations?: boolean\n}\n\nexport function graphiqlTemplate({\n apiVersion,\n apiVersions,\n appName,\n appUrl,\n key,\n storeFqdn,\n protectMutations = false,\n}: GraphiQLTemplateOptions): string {\n const hasAppContext = Boolean(appName && appUrl)\n const unauthorizedLabel = hasAppContext ? 'App uninstalled' : 'Auth invalid'\n return `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>GraphiQL</title>\n <link rel=\"shortcut icon\" href=\"{{url}}/graphiql/favicon.ico\" type=\"image/x-icon\" />\n <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@shopify/polaris@12.10.0/build/esm/styles.css\" />\n <style>\n body {\n height: 100%;\n margin: 0;\n width: 100%;\n overflow: hidden;\n }\n .Polaris-Page--fullWidth {\n width: 100%;\n }\n #top-bar {\n border-bottom: 1px solid var(--p-color-border);\n }\n #top-bar #top-error-bar {\n display: none;\n }\n #top-error-bar .Polaris-FullscreenBar__BackAction {\n /* hide default back button in FullscreenBar component */\n display: none;\n }\n #top-error-bar button {\n /* hide X to dismiss banner */\n display: none;\n }\n #top-bar .top-bar-section {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n }\n #top-bar .Polaris-Grid-Cell:nth-child(2) {\n justify-self: right;\n }\n #top-bar #scopes-note {\n display: inline-flex;\n align-items: center;\n height: 100%;\n }\n #top-bar .status-badge-option {\n gap: 8px;\n display: none;\n }\n #top-bar #status-badge-running {\n display: flex;\n }\n #graphiql {\n height: 100vh;\n display: flex;\n flex-direction: column;\n }\n #graphiql-explorer {\n flex-grow: 1;\n overflow: auto;\n }\n #top-bar #outbound-links a {\n line-height: 0;\n }\n #top-bar #outbound-links a:hover .Polaris-Text--root {\n text-decoration: underline;\n }\n #top-bar #outbound-links a span.Polaris-Text--root {\n max-width: max(12vw, 150px);\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n }\n .with-shrunk-icon .Polaris-Icon {\n height: 1rem;\n width: 1rem;\n margin: 0.125rem;\n }\n @media only screen and (max-width: 1550px) {\n .top-bar-section-title {\n display: none;\n }\n }\n @media only screen and (max-width: 1150px) {\n #top-bar #outbound-links a span.Polaris-Text--root {\n max-width: max(12vw, 140px);\n }\n }\n @media only screen and (max-width: 1080px) {\n #top-bar .Polaris-Grid-Cell:nth-child(2) {\n justify-self: left;\n }\n }\n @media only screen and (max-width: 650px) {\n #top-bar #outbound-links a span.Polaris-Text--root {\n max-width: 17vw;\n }\n }\n </style>\n\n <script\n src=\"https://cdn.jsdelivr.net/npm/react@17/umd/react.development.js\"\n integrity=\"sha512-Vf2xGDzpqUOEIKO+X2rgTLWPY+65++WPwCHkX2nFMu9IcstumPsf/uKKRd5prX3wOu8Q0GBylRpsDB26R6ExOg==\"\n crossorigin=\"anonymous\"\n ></script>\n <script\n src=\"https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.development.js\"\n integrity=\"sha512-Wr9OKCTtq1anK0hq5bY3X/AvDI5EflDSAh0mE9gma+4hl+kXdTJPKZ3TwLMBcrgUeoY0s3dq9JjhCQc7vddtFg==\"\n crossorigin=\"anonymous\"\n ></script>\n <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/graphiql@3.0.4/graphiql.min.css\" />\n </head>\n <body>\n <div id=\"graphiql\">\n ${renderToStaticMarkup(\n <AppProvider i18n={{}}>\n <div id=\"top-bar\">\n <Box background=\"bg-surface\" padding=\"400\">\n <BlockStack gap=\"300\">\n <Grid columns={{xs: 3, sm: 3, md: 3}}>\n <Grid.Cell columnSpan={{xs: 3, sm: 3, md: 3, lg: 7, xl: 7}}>\n <InlineStack gap=\"400\">\n <div id=\"status-badge\" className=\"top-bar-section\">\n <div className=\"status-badge-option\" id=\"status-badge-running\">\n <span className=\"top-bar-section-title\">Status: </span>\n <Badge tone=\"success\" progress=\"complete\">\n Running\n </Badge>\n </div>\n <div className=\"status-badge-option with-shrunk-icon\" id=\"status-badge-unauthorized\">\n <span className=\"top-bar-section-title\">Status: </span>\n <Badge tone=\"attention\" icon={AlertCircleIcon}>\n {unauthorizedLabel}\n </Badge>\n </div>\n <div className=\"status-badge-option with-shrunk-icon\" id=\"status-badge-disconnected\">\n <span className=\"top-bar-section-title\">Status: </span>\n <Badge tone=\"critical\" icon={DisabledIcon}>\n Disconnected\n </Badge>\n </div>\n </div>\n <div id=\"version-select\" className=\"top-bar-section\">\n <span className=\"top-bar-section-title\">API version: </span>\n <Select\n label=\"API version\"\n labelHidden\n options={apiVersions}\n value={apiVersion}\n onChange={() => {}}\n />\n </div>\n {linkPills({storeFqdn, appName, appUrl})}\n </InlineStack>\n </Grid.Cell>\n <Grid.Cell columnSpan={{xs: 3, sm: 3, md: 3, lg: 5, xl: 5}}>\n <div id=\"scopes-note\" className=\"top-bar-section\">\n <Text as=\"span\" tone=\"subdued\">\n {scopesNoteText({hasAppContext, protectMutations})}\n </Text>\n </div>\n </Grid.Cell>\n </Grid>\n <div id=\"top-error-bar\">\n <Banner tone=\"critical\" onDismiss={() => {}} icon={DisabledIcon}>\n <p>The server has been stopped. Restart it from the CLI.</p>\n </Banner>\n </div>\n </BlockStack>\n </Box>\n </div>\n </AppProvider>,\n )}\n <div id=\"graphiql-explorer\">Loading...</div>\n </div>\n <script\n src=\"https://cdn.jsdelivr.net/npm/graphiql@3.0.4/graphiql.min.js\"\n type=\"application/javascript\"\n ></script>\n <script>\n const macCommandKey = String.fromCodePoint(8984)\n const renderGraphiQL = function(apiVersion) {\n ReactDOM.render(\n React.createElement(GraphiQL, {\n fetcher: GraphiQL.createFetcher({\n url: '{{url}}/graphiql/graphql.json?key=${encodeURIComponent(key)}&api_version=' + apiVersion,\n }),\n defaultEditorToolsVisibility: true,\n {% if query %}\n query: {{query}},\n {% endif %}\n {% if variables %}\n variables: {{variables}},\n {% endif %}\n defaultTabs: [\n {query: \"${graphiqlIntroMessage\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')}\".replace(/MAC_COMMAND_KEY/g, macCommandKey)},\n {%for query in defaultQueries%}\n {query: \"{%if query.preface %}{{query.preface}}\\\\n{% endif %}{{query.query}}\", variables: \"{{query.variables}}\"},\n {%endfor%}\n ],\n isHeadersEditorEnabled: true,\n }),\n document.getElementById('graphiql-explorer'),\n )\n }\n renderGraphiQL('${apiVersion}')\n\n // Update the version when the select changes\n document.getElementById('version-select').addEventListener('change', function(event) {\n document.querySelector('#version-select .Polaris-Select__SelectedOption').innerText = event.target.value\n renderGraphiQL(event.target.value)\n })\n\n // Start out optimistic\n let serverIsLive = true\n let appIsInstalled = true\n\n const updateBadge = function() {\n const topErrorBar = document.querySelector('#graphiql #top-error-bar')\n const statusDiv = document.querySelector('#graphiql #status-badge')\n const allBadgeDivs = Array.from(statusDiv.querySelectorAll('.status-badge-option'))\n let activeBadge = 'running'\n if (!appIsInstalled) activeBadge = 'unauthorized'\n if (!serverIsLive) activeBadge = 'disconnected'\n allBadgeDivs.forEach(function(badge) {\n if (badge.id == ('status-badge-' + activeBadge)) {\n badge.style.display = 'flex'\n } else {\n badge.style.display = 'none'\n }\n })\n topErrorBar.style.display = serverIsLive ? 'none' : 'block'\n }\n const statusInterval = setInterval(updateBadge, 1000)\n\n // Warn when the server has been stopped\n const displayErrorServerStoppedTimeouts = []\n const pingInterval = setInterval(function() {\n displayErrorServerStoppedTimeouts.push(setTimeout(function() { serverIsLive = false }, 3000))\n fetch('{{url}}/graphiql/ping')\n .then(function(response) {\n if (response.status === 200) {\n while (displayErrorServerStoppedTimeouts.length > 0) {\n const timeout = displayErrorServerStoppedTimeouts.pop()\n clearTimeout(timeout)\n }\n serverIsLive = true\n } else {\n serverIsLive = false\n }\n })\n }, 2000)\n\n // Verify the current store/app connection\n setInterval(function() {\n fetch('{{ url }}/graphiql/status?key=${encodeURIComponent(key)}')\n .then(async function(response) {\n const {status, storeFqdn, appName, appUrl} = await response.json()\n appIsInstalled = status === 'OK'\n if (storeFqdn) {\n ${\n hasAppContext\n ? `document.getElementById('outbound-links').innerHTML = \\`${renderToStaticMarkup(\n <AppProvider i18n={{}}>\n {\n // eslint-disable-next-line no-template-curly-in-string\n linkPills({storeFqdn: '${storeFqdn}', appName: '${appName}', appUrl: '${appUrl}'})\n }\n </AppProvider>,\n )}\\``\n : `document.getElementById('outbound-links').innerHTML = \\`${renderToStaticMarkup(\n <AppProvider i18n={{}}>\n {\n // eslint-disable-next-line no-template-curly-in-string\n linkPills({storeFqdn: '${storeFqdn}'})\n }\n </AppProvider>,\n )}\\``\n }\n }\n })\n }, 5000)\n </script>\n </body>\n</html>\n`\n}\n\ninterface LinkPillOptions {\n storeFqdn: string\n appName?: string\n appUrl?: string\n}\n\nfunction linkPills({storeFqdn, appName, appUrl}: LinkPillOptions) {\n return (\n <div id=\"outbound-links\" className=\"top-bar-section with-shrunk-icon\">\n <span className=\"top-bar-section-title\">Store: </span>\n <Link url={`https://${storeFqdn}/admin`} target=\"_blank\">\n <Badge tone=\"info\" icon={LinkIcon} children={storeFqdn} />\n </Link>\n {appName && appUrl ? (\n <>\n <span className=\"top-bar-section-title\">App: </span>\n <Link url={appUrl} target=\"_blank\">\n <Badge tone=\"info\" icon={LinkIcon} children={appName} />\n </Link>\n </>\n ) : null}\n </div>\n )\n}\n\nfunction scopesNoteText({\n hasAppContext,\n protectMutations,\n}: {\n hasAppContext: boolean\n protectMutations: boolean\n}): string {\n if (protectMutations) {\n return MUTATIONS_BLOCKED_MESSAGE\n }\n if (hasAppContext) {\n return \"GraphiQL runs on the same access scopes you've defined in the TOML file for your app.\"\n }\n return 'GraphiQL runs with the access scopes granted to the stored app authentication for this store.'\n}\n"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { LocalStorage } from './local-storage.js';
|
|
2
|
+
import type { AdminSession } from './session.js';
|
|
3
|
+
/**
|
|
4
|
+
* Discriminator for a stored store auth session.
|
|
5
|
+
*
|
|
6
|
+
* - 'standard': created via `shopify store auth`.
|
|
7
|
+
* - 'preview': created via `shopify store create preview`; backed by a server-issued Admin API token.
|
|
8
|
+
*
|
|
9
|
+
* Stored sessions written before this discriminator existed have no `kind` field and are
|
|
10
|
+
* read back as 'standard'.
|
|
11
|
+
*/
|
|
12
|
+
export type StoredStoreSessionKind = 'standard' | 'preview';
|
|
13
|
+
export interface StoredPreviewStoreMetadata {
|
|
14
|
+
/** Placeholder account UUID returned by the preview-store backend when available. */
|
|
15
|
+
placeholderAccountUuid?: string;
|
|
16
|
+
/** Numeric shop id returned by the preview-store backend. */
|
|
17
|
+
shopId: string;
|
|
18
|
+
/** Store name returned by the preview-store backend. */
|
|
19
|
+
name: string;
|
|
20
|
+
/** ISO country code requested for the store, when provided by the caller. */
|
|
21
|
+
country?: string;
|
|
22
|
+
/** ISO timestamp for when the preview store was created locally. */
|
|
23
|
+
createdAt: string;
|
|
24
|
+
/** Access URL returned by the preview-store backend. */
|
|
25
|
+
accessUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface StoredStoreAppSession {
|
|
28
|
+
store: string;
|
|
29
|
+
clientId: string;
|
|
30
|
+
userId: string;
|
|
31
|
+
accessToken: string;
|
|
32
|
+
refreshToken?: string;
|
|
33
|
+
scopes: string[];
|
|
34
|
+
acquiredAt: string;
|
|
35
|
+
expiresAt?: string;
|
|
36
|
+
refreshTokenExpiresAt?: string;
|
|
37
|
+
associatedUser?: {
|
|
38
|
+
id: number;
|
|
39
|
+
email?: string;
|
|
40
|
+
firstName?: string;
|
|
41
|
+
lastName?: string;
|
|
42
|
+
accountOwner?: boolean;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Discriminator. Optional in storage for back-compat with sessions written before the
|
|
46
|
+
* field existed; `sessionKind()` resolves missing values to 'standard'.
|
|
47
|
+
*/
|
|
48
|
+
kind?: StoredStoreSessionKind;
|
|
49
|
+
/** Preview-store-only metadata. Set iff `kind === 'preview'`. */
|
|
50
|
+
preview?: StoredPreviewStoreMetadata;
|
|
51
|
+
}
|
|
52
|
+
interface StoredStoreAppSessionBucket {
|
|
53
|
+
currentUserId: string;
|
|
54
|
+
sessionsByUserId: {
|
|
55
|
+
[userId: string]: StoredStoreAppSession;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
interface StoreAuthSessionSchema {
|
|
59
|
+
[key: string]: StoredStoreAppSessionBucket;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the local-storage key used for store-auth sessions.
|
|
63
|
+
*
|
|
64
|
+
* @param store - The normalized store FQDN.
|
|
65
|
+
* @returns The store-auth session storage key.
|
|
66
|
+
*/
|
|
67
|
+
export declare function storeAuthSessionKey(store: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* Project the current session for every store that has locally stored store auth.
|
|
70
|
+
*
|
|
71
|
+
* @param storage - Optional storage override for tests.
|
|
72
|
+
* @returns Current stored store auth sessions.
|
|
73
|
+
*/
|
|
74
|
+
export declare function listCurrentStoredStoreAppSessions(storage?: LocalStorage<StoreAuthSessionSchema>): StoredStoreAppSession[];
|
|
75
|
+
/**
|
|
76
|
+
* Get the current stored store auth session for a store.
|
|
77
|
+
*
|
|
78
|
+
* @param store - The store FQDN or URL to load a store-auth session for.
|
|
79
|
+
* @param storage - Optional storage override for tests.
|
|
80
|
+
* @returns The current stored store auth session, or undefined when missing or malformed.
|
|
81
|
+
*/
|
|
82
|
+
export declare function getCurrentStoredStoreAppSession(store: string, storage?: LocalStorage<StoreAuthSessionSchema>): StoredStoreAppSession | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Persist a store auth session and mark it as current for its store.
|
|
85
|
+
*
|
|
86
|
+
* @param session - The store auth session to persist.
|
|
87
|
+
* @param storage - Optional storage override for tests.
|
|
88
|
+
*/
|
|
89
|
+
export declare function setStoredStoreAppSession(session: StoredStoreAppSession, storage?: LocalStorage<StoreAuthSessionSchema>): void;
|
|
90
|
+
/**
|
|
91
|
+
* Clear stored store auth sessions for a store.
|
|
92
|
+
*
|
|
93
|
+
* @param store - The store FQDN or URL to clear sessions for.
|
|
94
|
+
* @param userIdOrStorage - Optional user ID to clear, or storage override when clearing all users.
|
|
95
|
+
* @param maybeStorage - Optional storage override when clearing one user.
|
|
96
|
+
*/
|
|
97
|
+
export declare function clearStoredStoreAppSession(store: string, userIdOrStorage?: string | LocalStorage<StoreAuthSessionSchema>, maybeStorage?: LocalStorage<StoreAuthSessionSchema>): void;
|
|
98
|
+
/**
|
|
99
|
+
* Load an Admin API session from the local store-auth cache when one is currently usable.
|
|
100
|
+
*
|
|
101
|
+
* @param store - The store FQDN or URL to load a store-auth session for.
|
|
102
|
+
* @param storage - Optional storage override for tests.
|
|
103
|
+
* @returns An Admin session, or undefined when no usable session is cached.
|
|
104
|
+
*/
|
|
105
|
+
export declare function getStoreAuthAdminSession(store: string, storage?: LocalStorage<StoreAuthSessionSchema>): AdminSession | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Check whether a stored store auth session is expired, including the refresh margin.
|
|
108
|
+
*
|
|
109
|
+
* @param session - The stored store auth session.
|
|
110
|
+
* @returns True when the session is expired or has an invalid expiry timestamp.
|
|
111
|
+
*/
|
|
112
|
+
export declare function isSessionExpired(session: StoredStoreAppSession): boolean;
|
|
113
|
+
export {};
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { STORE_AUTH_APP_CLIENT_ID } from './constants.js';
|
|
2
|
+
import { normalizeStoreFqdn } from './context/fqdn.js';
|
|
3
|
+
import { LocalStorage } from './local-storage.js';
|
|
4
|
+
import { setLastSeenUserId } from './session.js';
|
|
5
|
+
const STORE_AUTH_PROJECT_NAME = 'shopify-cli-store';
|
|
6
|
+
const EXPIRY_MARGIN_MS = 4 * 60 * 1000;
|
|
7
|
+
let _storeAuthSessionStorage;
|
|
8
|
+
function storeAuthSessionStorage() {
|
|
9
|
+
_storeAuthSessionStorage ?? (_storeAuthSessionStorage = new LocalStorage({ projectName: STORE_AUTH_PROJECT_NAME }));
|
|
10
|
+
return _storeAuthSessionStorage;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build the local-storage key used for store-auth sessions.
|
|
14
|
+
*
|
|
15
|
+
* @param store - The normalized store FQDN.
|
|
16
|
+
* @returns The store-auth session storage key.
|
|
17
|
+
*/
|
|
18
|
+
export function storeAuthSessionKey(store) {
|
|
19
|
+
return `${STORE_AUTH_APP_CLIENT_ID}::${escapeStoreAuthSessionKeySegment(store)}`;
|
|
20
|
+
}
|
|
21
|
+
function escapeStoreAuthSessionKeySegment(value) {
|
|
22
|
+
return value.replace(/\\/g, '\\\\').replace(/\./g, '\\.');
|
|
23
|
+
}
|
|
24
|
+
function isString(value) {
|
|
25
|
+
return typeof value === 'string';
|
|
26
|
+
}
|
|
27
|
+
function sanitizeAssociatedUser(value) {
|
|
28
|
+
if (!value || typeof value !== 'object')
|
|
29
|
+
return undefined;
|
|
30
|
+
const associatedUser = value;
|
|
31
|
+
if (typeof associatedUser.id !== 'number')
|
|
32
|
+
return undefined;
|
|
33
|
+
return {
|
|
34
|
+
id: associatedUser.id,
|
|
35
|
+
...(isString(associatedUser.email) ? { email: associatedUser.email } : {}),
|
|
36
|
+
...(isString(associatedUser.firstName) ? { firstName: associatedUser.firstName } : {}),
|
|
37
|
+
...(isString(associatedUser.lastName) ? { lastName: associatedUser.lastName } : {}),
|
|
38
|
+
...(typeof associatedUser.accountOwner === 'boolean' ? { accountOwner: associatedUser.accountOwner } : {}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function sanitizePreviewMetadata(value) {
|
|
42
|
+
if (!value || typeof value !== 'object')
|
|
43
|
+
return undefined;
|
|
44
|
+
const metadata = value;
|
|
45
|
+
if (!isString(metadata.shopId) || !isString(metadata.name) || !isString(metadata.createdAt))
|
|
46
|
+
return undefined;
|
|
47
|
+
return {
|
|
48
|
+
shopId: metadata.shopId,
|
|
49
|
+
name: metadata.name,
|
|
50
|
+
createdAt: metadata.createdAt,
|
|
51
|
+
...(isString(metadata.placeholderAccountUuid) ? { placeholderAccountUuid: metadata.placeholderAccountUuid } : {}),
|
|
52
|
+
...(isString(metadata.country) ? { country: metadata.country } : {}),
|
|
53
|
+
...(isString(metadata.accessUrl) ? { accessUrl: metadata.accessUrl } : {}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function sanitizeStoredStoreAppSession(value) {
|
|
57
|
+
if (!value || typeof value !== 'object')
|
|
58
|
+
return undefined;
|
|
59
|
+
const session = value;
|
|
60
|
+
if (!isString(session.store) ||
|
|
61
|
+
!isString(session.clientId) ||
|
|
62
|
+
!isString(session.userId) ||
|
|
63
|
+
!isString(session.accessToken) ||
|
|
64
|
+
!Array.isArray(session.scopes) ||
|
|
65
|
+
!session.scopes.every(isString) ||
|
|
66
|
+
!isString(session.acquiredAt)) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const associatedUser = sanitizeAssociatedUser(session.associatedUser);
|
|
70
|
+
// Discriminator is optional for back-compat: sessions written before this field existed
|
|
71
|
+
// are read back as 'standard'. Unknown values are coerced to 'standard' and the field is
|
|
72
|
+
// omitted from the result so it doesn't pollute legacy buckets.
|
|
73
|
+
const kind = session.kind === 'preview' ? 'preview' : 'standard';
|
|
74
|
+
const preview = kind === 'preview' ? sanitizePreviewMetadata(session.preview) : undefined;
|
|
75
|
+
// A session declared as 'preview' but missing/malformed metadata is rejected outright,
|
|
76
|
+
// because store-list fallback and future re-mint/claim flows rely on this metadata.
|
|
77
|
+
if (kind === 'preview' && !preview)
|
|
78
|
+
return undefined;
|
|
79
|
+
return {
|
|
80
|
+
store: session.store,
|
|
81
|
+
clientId: session.clientId,
|
|
82
|
+
userId: session.userId,
|
|
83
|
+
accessToken: session.accessToken,
|
|
84
|
+
scopes: session.scopes,
|
|
85
|
+
acquiredAt: session.acquiredAt,
|
|
86
|
+
...(isString(session.refreshToken) ? { refreshToken: session.refreshToken } : {}),
|
|
87
|
+
...(isString(session.expiresAt) ? { expiresAt: session.expiresAt } : {}),
|
|
88
|
+
...(isString(session.refreshTokenExpiresAt) ? { refreshTokenExpiresAt: session.refreshTokenExpiresAt } : {}),
|
|
89
|
+
...(associatedUser ? { associatedUser } : {}),
|
|
90
|
+
...(kind === 'preview' ? { kind } : {}),
|
|
91
|
+
...(preview ? { preview } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function sanitizeStoredStoreAppSessionBucket(store, storedBucket, storage) {
|
|
95
|
+
if (!storedBucket || typeof storedBucket !== 'object')
|
|
96
|
+
return undefined;
|
|
97
|
+
const { sessionsByUserId, currentUserId } = storedBucket;
|
|
98
|
+
const looksLikeBucket = sessionsByUserId !== undefined || currentUserId !== undefined;
|
|
99
|
+
if (!looksLikeBucket)
|
|
100
|
+
return undefined;
|
|
101
|
+
const key = storeAuthSessionKey(store);
|
|
102
|
+
if (!sessionsByUserId ||
|
|
103
|
+
typeof sessionsByUserId !== 'object' ||
|
|
104
|
+
Array.isArray(sessionsByUserId) ||
|
|
105
|
+
typeof currentUserId !== 'string') {
|
|
106
|
+
storage.delete(key);
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const sanitizedSessionsByUserId = Object.fromEntries(Object.entries(sessionsByUserId).flatMap(([userId, session]) => {
|
|
110
|
+
const sanitizedSession = sanitizeStoredStoreAppSession(session);
|
|
111
|
+
return sanitizedSession ? [[userId, sanitizedSession]] : [];
|
|
112
|
+
}));
|
|
113
|
+
if (Object.keys(sanitizedSessionsByUserId).length !== Object.keys(sessionsByUserId).length) {
|
|
114
|
+
if (sanitizedSessionsByUserId[currentUserId]) {
|
|
115
|
+
storage.set(key, {
|
|
116
|
+
currentUserId,
|
|
117
|
+
sessionsByUserId: sanitizedSessionsByUserId,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
storage.delete(key);
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
currentUserId,
|
|
127
|
+
sessionsByUserId: sanitizedSessionsByUserId,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function readStoredStoreAppSessionBucket(store, storage) {
|
|
131
|
+
return sanitizeStoredStoreAppSessionBucket(store, storage.get(storeAuthSessionKey(store)), storage);
|
|
132
|
+
}
|
|
133
|
+
// `conf` persists dotted keys as nested objects. Store-auth callers should not
|
|
134
|
+
// learn that layout directly; this helper keeps the current traversal private to
|
|
135
|
+
// the persistence seam while higher-level code projects summaries instead.
|
|
136
|
+
function readRawStoreAuthSessionStorage(storage) {
|
|
137
|
+
return storage.config?.store ?? {};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Project the current session for every store that has locally stored store auth.
|
|
141
|
+
*
|
|
142
|
+
* @param storage - Optional storage override for tests.
|
|
143
|
+
* @returns Current stored store auth sessions.
|
|
144
|
+
*/
|
|
145
|
+
export function listCurrentStoredStoreAppSessions(storage = storeAuthSessionStorage()) {
|
|
146
|
+
const sessions = [];
|
|
147
|
+
const keyPrefix = `${STORE_AUTH_APP_CLIENT_ID}::`;
|
|
148
|
+
for (const [key, value] of Object.entries(readRawStoreAuthSessionStorage(storage))) {
|
|
149
|
+
if (!key.startsWith(keyPrefix))
|
|
150
|
+
continue;
|
|
151
|
+
const bucket = sanitizeStoredStoreAppSessionBucket(key.slice(keyPrefix.length), value, storage);
|
|
152
|
+
const session = bucket?.sessionsByUserId[bucket.currentUserId];
|
|
153
|
+
if (session)
|
|
154
|
+
sessions.push(session);
|
|
155
|
+
}
|
|
156
|
+
return sessions;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get the current stored store auth session for a store.
|
|
160
|
+
*
|
|
161
|
+
* @param store - The store FQDN or URL to load a store-auth session for.
|
|
162
|
+
* @param storage - Optional storage override for tests.
|
|
163
|
+
* @returns The current stored store auth session, or undefined when missing or malformed.
|
|
164
|
+
*/
|
|
165
|
+
export function getCurrentStoredStoreAppSession(store, storage = storeAuthSessionStorage()) {
|
|
166
|
+
const storeFqdn = normalizeStoreFqdn(store);
|
|
167
|
+
const bucket = readStoredStoreAppSessionBucket(storeFqdn, storage);
|
|
168
|
+
if (!bucket)
|
|
169
|
+
return undefined;
|
|
170
|
+
const session = bucket.sessionsByUserId[bucket.currentUserId];
|
|
171
|
+
if (!session) {
|
|
172
|
+
storage.delete(storeAuthSessionKey(storeFqdn));
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
return session;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Persist a store auth session and mark it as current for its store.
|
|
179
|
+
*
|
|
180
|
+
* @param session - The store auth session to persist.
|
|
181
|
+
* @param storage - Optional storage override for tests.
|
|
182
|
+
*/
|
|
183
|
+
export function setStoredStoreAppSession(session, storage = storeAuthSessionStorage()) {
|
|
184
|
+
const key = storeAuthSessionKey(session.store);
|
|
185
|
+
const existingBucket = readStoredStoreAppSessionBucket(session.store, storage);
|
|
186
|
+
const nextBucket = {
|
|
187
|
+
currentUserId: session.userId,
|
|
188
|
+
sessionsByUserId: {
|
|
189
|
+
...(existingBucket?.sessionsByUserId ?? {}),
|
|
190
|
+
[session.userId]: session,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
storage.set(key, nextBucket);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Clear stored store auth sessions for a store.
|
|
197
|
+
*
|
|
198
|
+
* @param store - The store FQDN or URL to clear sessions for.
|
|
199
|
+
* @param userIdOrStorage - Optional user ID to clear, or storage override when clearing all users.
|
|
200
|
+
* @param maybeStorage - Optional storage override when clearing one user.
|
|
201
|
+
*/
|
|
202
|
+
export function clearStoredStoreAppSession(store, userIdOrStorage, maybeStorage) {
|
|
203
|
+
const storeFqdn = normalizeStoreFqdn(store);
|
|
204
|
+
const userId = typeof userIdOrStorage === 'string' ? userIdOrStorage : undefined;
|
|
205
|
+
const storage = (typeof userIdOrStorage === 'string' ? maybeStorage : userIdOrStorage) ?? storeAuthSessionStorage();
|
|
206
|
+
const key = storeAuthSessionKey(storeFqdn);
|
|
207
|
+
if (!userId) {
|
|
208
|
+
storage.delete(key);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const existingBucket = readStoredStoreAppSessionBucket(storeFqdn, storage);
|
|
212
|
+
if (!existingBucket)
|
|
213
|
+
return;
|
|
214
|
+
const { [userId]: _removedSession, ...remainingSessions } = existingBucket.sessionsByUserId;
|
|
215
|
+
const remainingUserIds = Object.keys(remainingSessions);
|
|
216
|
+
if (remainingUserIds.length === 0) {
|
|
217
|
+
storage.delete(key);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
storage.set(key, {
|
|
221
|
+
currentUserId: existingBucket.currentUserId === userId ? remainingUserIds[0] : existingBucket.currentUserId,
|
|
222
|
+
sessionsByUserId: remainingSessions,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Load an Admin API session from the local store-auth cache when one is currently usable.
|
|
227
|
+
*
|
|
228
|
+
* @param store - The store FQDN or URL to load a store-auth session for.
|
|
229
|
+
* @param storage - Optional storage override for tests.
|
|
230
|
+
* @returns An Admin session, or undefined when no usable session is cached.
|
|
231
|
+
*/
|
|
232
|
+
export function getStoreAuthAdminSession(store, storage = storeAuthSessionStorage()) {
|
|
233
|
+
const storeFqdn = normalizeStoreFqdn(store);
|
|
234
|
+
const session = getCurrentStoredStoreAppSession(storeFqdn, storage);
|
|
235
|
+
if (!session || isSessionExpired(session))
|
|
236
|
+
return undefined;
|
|
237
|
+
setLastSeenUserId(session.userId);
|
|
238
|
+
return {
|
|
239
|
+
token: session.accessToken,
|
|
240
|
+
storeFqdn,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Check whether a stored store auth session is expired, including the refresh margin.
|
|
245
|
+
*
|
|
246
|
+
* @param session - The stored store auth session.
|
|
247
|
+
* @returns True when the session is expired or has an invalid expiry timestamp.
|
|
248
|
+
*/
|
|
249
|
+
export function isSessionExpired(session) {
|
|
250
|
+
if (!session.expiresAt)
|
|
251
|
+
return false;
|
|
252
|
+
const expiresAtMs = new Date(session.expiresAt).getTime();
|
|
253
|
+
if (Number.isNaN(expiresAtMs))
|
|
254
|
+
return true;
|
|
255
|
+
return expiresAtMs - EXPIRY_MARGIN_MS < Date.now();
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=store-auth-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-auth-session.js","sourceRoot":"","sources":["../../../src/public/node/store-auth-session.ts"],"names":[],"mappings":"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","sourcesContent":["import {STORE_AUTH_APP_CLIENT_ID} from './constants.js'\nimport {normalizeStoreFqdn} from './context/fqdn.js'\nimport {LocalStorage} from './local-storage.js'\nimport {setLastSeenUserId} from './session.js'\nimport type {JsonMapType} from './toml/codec.js'\nimport type {AdminSession} from './session.js'\n\nconst STORE_AUTH_PROJECT_NAME = 'shopify-cli-store'\nconst EXPIRY_MARGIN_MS = 4 * 60 * 1000\n\n/**\n * Discriminator for a stored store auth session.\n *\n * - 'standard': created via `shopify store auth`.\n * - 'preview': created via `shopify store create preview`; backed by a server-issued Admin API token.\n *\n * Stored sessions written before this discriminator existed have no `kind` field and are\n * read back as 'standard'.\n */\nexport type StoredStoreSessionKind = 'standard' | 'preview'\n\nexport interface StoredPreviewStoreMetadata {\n /** Placeholder account UUID returned by the preview-store backend when available. */\n placeholderAccountUuid?: string\n /** Numeric shop id returned by the preview-store backend. */\n shopId: string\n /** Store name returned by the preview-store backend. */\n name: string\n /** ISO country code requested for the store, when provided by the caller. */\n country?: string\n /** ISO timestamp for when the preview store was created locally. */\n createdAt: string\n /** Access URL returned by the preview-store backend. */\n accessUrl?: string\n}\n\nexport interface StoredStoreAppSession {\n store: string\n clientId: string\n userId: string\n accessToken: string\n refreshToken?: string\n scopes: string[]\n acquiredAt: string\n expiresAt?: string\n refreshTokenExpiresAt?: string\n associatedUser?: {\n id: number\n email?: string\n firstName?: string\n lastName?: string\n accountOwner?: boolean\n }\n /**\n * Discriminator. Optional in storage for back-compat with sessions written before the\n * field existed; `sessionKind()` resolves missing values to 'standard'.\n */\n kind?: StoredStoreSessionKind\n /** Preview-store-only metadata. Set iff `kind === 'preview'`. */\n preview?: StoredPreviewStoreMetadata\n}\n\ninterface StoredStoreAppSessionBucket {\n currentUserId: string\n sessionsByUserId: {[userId: string]: StoredStoreAppSession}\n}\n\ninterface StoreAuthSessionSchema {\n [key: string]: StoredStoreAppSessionBucket\n}\n\ntype RawStoreAuthSessionStorage = JsonMapType\n\nlet _storeAuthSessionStorage: LocalStorage<StoreAuthSessionSchema> | undefined\n\nfunction storeAuthSessionStorage() {\n _storeAuthSessionStorage ??= new LocalStorage<StoreAuthSessionSchema>({projectName: STORE_AUTH_PROJECT_NAME})\n return _storeAuthSessionStorage\n}\n\n/**\n * Build the local-storage key used for store-auth sessions.\n *\n * @param store - The normalized store FQDN.\n * @returns The store-auth session storage key.\n */\nexport function storeAuthSessionKey(store: string): string {\n return `${STORE_AUTH_APP_CLIENT_ID}::${escapeStoreAuthSessionKeySegment(store)}`\n}\n\nfunction escapeStoreAuthSessionKeySegment(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\\./g, '\\\\.')\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string'\n}\n\nfunction sanitizeAssociatedUser(value: unknown): StoredStoreAppSession['associatedUser'] | undefined {\n if (!value || typeof value !== 'object') return undefined\n\n const associatedUser = value as Record<string, unknown>\n if (typeof associatedUser.id !== 'number') return undefined\n\n return {\n id: associatedUser.id,\n ...(isString(associatedUser.email) ? {email: associatedUser.email} : {}),\n ...(isString(associatedUser.firstName) ? {firstName: associatedUser.firstName} : {}),\n ...(isString(associatedUser.lastName) ? {lastName: associatedUser.lastName} : {}),\n ...(typeof associatedUser.accountOwner === 'boolean' ? {accountOwner: associatedUser.accountOwner} : {}),\n }\n}\n\nfunction sanitizePreviewMetadata(value: unknown): StoredPreviewStoreMetadata | undefined {\n if (!value || typeof value !== 'object') return undefined\n\n const metadata = value as Record<string, unknown>\n if (!isString(metadata.shopId) || !isString(metadata.name) || !isString(metadata.createdAt)) return undefined\n\n return {\n shopId: metadata.shopId,\n name: metadata.name,\n createdAt: metadata.createdAt,\n ...(isString(metadata.placeholderAccountUuid) ? {placeholderAccountUuid: metadata.placeholderAccountUuid} : {}),\n ...(isString(metadata.country) ? {country: metadata.country} : {}),\n ...(isString(metadata.accessUrl) ? {accessUrl: metadata.accessUrl} : {}),\n }\n}\n\nfunction sanitizeStoredStoreAppSession(value: unknown): StoredStoreAppSession | undefined {\n if (!value || typeof value !== 'object') return undefined\n\n const session = value as Record<string, unknown>\n if (\n !isString(session.store) ||\n !isString(session.clientId) ||\n !isString(session.userId) ||\n !isString(session.accessToken) ||\n !Array.isArray(session.scopes) ||\n !session.scopes.every(isString) ||\n !isString(session.acquiredAt)\n ) {\n return undefined\n }\n\n const associatedUser = sanitizeAssociatedUser(session.associatedUser)\n\n // Discriminator is optional for back-compat: sessions written before this field existed\n // are read back as 'standard'. Unknown values are coerced to 'standard' and the field is\n // omitted from the result so it doesn't pollute legacy buckets.\n const kind: StoredStoreSessionKind = session.kind === 'preview' ? 'preview' : 'standard'\n const preview = kind === 'preview' ? sanitizePreviewMetadata(session.preview) : undefined\n\n // A session declared as 'preview' but missing/malformed metadata is rejected outright,\n // because store-list fallback and future re-mint/claim flows rely on this metadata.\n if (kind === 'preview' && !preview) return undefined\n\n return {\n store: session.store,\n clientId: session.clientId,\n userId: session.userId,\n accessToken: session.accessToken,\n scopes: session.scopes,\n acquiredAt: session.acquiredAt,\n ...(isString(session.refreshToken) ? {refreshToken: session.refreshToken} : {}),\n ...(isString(session.expiresAt) ? {expiresAt: session.expiresAt} : {}),\n ...(isString(session.refreshTokenExpiresAt) ? {refreshTokenExpiresAt: session.refreshTokenExpiresAt} : {}),\n ...(associatedUser ? {associatedUser} : {}),\n ...(kind === 'preview' ? {kind} : {}),\n ...(preview ? {preview} : {}),\n }\n}\n\nfunction sanitizeStoredStoreAppSessionBucket(\n store: string,\n storedBucket: unknown,\n storage: LocalStorage<StoreAuthSessionSchema>,\n): StoredStoreAppSessionBucket | undefined {\n if (!storedBucket || typeof storedBucket !== 'object') return undefined\n\n const {sessionsByUserId, currentUserId} = storedBucket as Partial<StoredStoreAppSessionBucket>\n const looksLikeBucket = sessionsByUserId !== undefined || currentUserId !== undefined\n if (!looksLikeBucket) return undefined\n\n const key = storeAuthSessionKey(store)\n if (\n !sessionsByUserId ||\n typeof sessionsByUserId !== 'object' ||\n Array.isArray(sessionsByUserId) ||\n typeof currentUserId !== 'string'\n ) {\n storage.delete(key)\n return undefined\n }\n\n const sanitizedSessionsByUserId = Object.fromEntries(\n Object.entries(sessionsByUserId).flatMap(([userId, session]) => {\n const sanitizedSession = sanitizeStoredStoreAppSession(session)\n return sanitizedSession ? [[userId, sanitizedSession]] : []\n }),\n )\n\n if (Object.keys(sanitizedSessionsByUserId).length !== Object.keys(sessionsByUserId).length) {\n if (sanitizedSessionsByUserId[currentUserId]) {\n storage.set(key, {\n currentUserId,\n sessionsByUserId: sanitizedSessionsByUserId,\n })\n } else {\n storage.delete(key)\n return undefined\n }\n }\n\n return {\n currentUserId,\n sessionsByUserId: sanitizedSessionsByUserId,\n }\n}\n\nfunction readStoredStoreAppSessionBucket(\n store: string,\n storage: LocalStorage<StoreAuthSessionSchema>,\n): StoredStoreAppSessionBucket | undefined {\n return sanitizeStoredStoreAppSessionBucket(store, storage.get(storeAuthSessionKey(store)), storage)\n}\n\n// `conf` persists dotted keys as nested objects. Store-auth callers should not\n// learn that layout directly; this helper keeps the current traversal private to\n// the persistence seam while higher-level code projects summaries instead.\nfunction readRawStoreAuthSessionStorage(storage: LocalStorage<StoreAuthSessionSchema>): RawStoreAuthSessionStorage {\n return (storage as unknown as {config?: {store?: RawStoreAuthSessionStorage}}).config?.store ?? {}\n}\n\n/**\n * Project the current session for every store that has locally stored store auth.\n *\n * @param storage - Optional storage override for tests.\n * @returns Current stored store auth sessions.\n */\nexport function listCurrentStoredStoreAppSessions(\n storage: LocalStorage<StoreAuthSessionSchema> = storeAuthSessionStorage(),\n): StoredStoreAppSession[] {\n const sessions: StoredStoreAppSession[] = []\n const keyPrefix = `${STORE_AUTH_APP_CLIENT_ID}::`\n\n for (const [key, value] of Object.entries(readRawStoreAuthSessionStorage(storage))) {\n if (!key.startsWith(keyPrefix)) continue\n\n const bucket = sanitizeStoredStoreAppSessionBucket(key.slice(keyPrefix.length), value, storage)\n const session = bucket?.sessionsByUserId[bucket.currentUserId]\n if (session) sessions.push(session)\n }\n\n return sessions\n}\n\n/**\n * Get the current stored store auth session for a store.\n *\n * @param store - The store FQDN or URL to load a store-auth session for.\n * @param storage - Optional storage override for tests.\n * @returns The current stored store auth session, or undefined when missing or malformed.\n */\nexport function getCurrentStoredStoreAppSession(\n store: string,\n storage: LocalStorage<StoreAuthSessionSchema> = storeAuthSessionStorage(),\n): StoredStoreAppSession | undefined {\n const storeFqdn = normalizeStoreFqdn(store)\n const bucket = readStoredStoreAppSessionBucket(storeFqdn, storage)\n if (!bucket) return undefined\n\n const session = bucket.sessionsByUserId[bucket.currentUserId]\n if (!session) {\n storage.delete(storeAuthSessionKey(storeFqdn))\n return undefined\n }\n\n return session\n}\n\n/**\n * Persist a store auth session and mark it as current for its store.\n *\n * @param session - The store auth session to persist.\n * @param storage - Optional storage override for tests.\n */\nexport function setStoredStoreAppSession(\n session: StoredStoreAppSession,\n storage: LocalStorage<StoreAuthSessionSchema> = storeAuthSessionStorage(),\n): void {\n const key = storeAuthSessionKey(session.store)\n const existingBucket = readStoredStoreAppSessionBucket(session.store, storage)\n\n const nextBucket: StoredStoreAppSessionBucket = {\n currentUserId: session.userId,\n sessionsByUserId: {\n ...(existingBucket?.sessionsByUserId ?? {}),\n [session.userId]: session,\n },\n }\n\n storage.set(key, nextBucket)\n}\n\n/**\n * Clear stored store auth sessions for a store.\n *\n * @param store - The store FQDN or URL to clear sessions for.\n * @param userIdOrStorage - Optional user ID to clear, or storage override when clearing all users.\n * @param maybeStorage - Optional storage override when clearing one user.\n */\nexport function clearStoredStoreAppSession(\n store: string,\n userIdOrStorage?: string | LocalStorage<StoreAuthSessionSchema>,\n maybeStorage?: LocalStorage<StoreAuthSessionSchema>,\n): void {\n const storeFqdn = normalizeStoreFqdn(store)\n const userId = typeof userIdOrStorage === 'string' ? userIdOrStorage : undefined\n const storage = (typeof userIdOrStorage === 'string' ? maybeStorage : userIdOrStorage) ?? storeAuthSessionStorage()\n\n const key = storeAuthSessionKey(storeFqdn)\n\n if (!userId) {\n storage.delete(key)\n return\n }\n\n const existingBucket = readStoredStoreAppSessionBucket(storeFqdn, storage)\n if (!existingBucket) return\n\n const {[userId]: _removedSession, ...remainingSessions} = existingBucket.sessionsByUserId\n\n const remainingUserIds = Object.keys(remainingSessions)\n if (remainingUserIds.length === 0) {\n storage.delete(key)\n return\n }\n\n storage.set(key, {\n currentUserId: existingBucket.currentUserId === userId ? remainingUserIds[0]! : existingBucket.currentUserId,\n sessionsByUserId: remainingSessions,\n })\n}\n\n/**\n * Load an Admin API session from the local store-auth cache when one is currently usable.\n *\n * @param store - The store FQDN or URL to load a store-auth session for.\n * @param storage - Optional storage override for tests.\n * @returns An Admin session, or undefined when no usable session is cached.\n */\nexport function getStoreAuthAdminSession(\n store: string,\n storage: LocalStorage<StoreAuthSessionSchema> = storeAuthSessionStorage(),\n): AdminSession | undefined {\n const storeFqdn = normalizeStoreFqdn(store)\n const session = getCurrentStoredStoreAppSession(storeFqdn, storage)\n if (!session || isSessionExpired(session)) return undefined\n\n setLastSeenUserId(session.userId)\n\n return {\n token: session.accessToken,\n storeFqdn,\n }\n}\n\n/**\n * Check whether a stored store auth session is expired, including the refresh margin.\n *\n * @param session - The stored store auth session.\n * @returns True when the session is expired or has an invalid expiry timestamp.\n */\nexport function isSessionExpired(session: StoredStoreAppSession): boolean {\n if (!session.expiresAt) return false\n\n const expiresAtMs = new Date(session.expiresAt).getTime()\n if (Number.isNaN(expiresAtMs)) return true\n\n return expiresAtMs - EXPIRY_MARGIN_MS < Date.now()\n}\n"]}
|
package/dist/public/node/ui.d.ts
CHANGED
|
@@ -69,10 +69,7 @@ export type RenderAlertOptions = Omit<AlertOptions, 'type'>;
|
|
|
69
69
|
* │ │
|
|
70
70
|
* ╰──────────────────────────────────────────────────────────╯
|
|
71
71
|
* [1] https://shopify.dev
|
|
72
|
-
* [2] https://www.google.com/search?q=
|
|
73
|
-
* 9s2xvzla01d8cn6j7yq&rlz=1C1GCEU_enUS832US832&oq=jh56t9l34kpo
|
|
74
|
-
* 35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j
|
|
75
|
-
* 69i60.2711j0j7&sourceid=chrome&ie=UTF-8
|
|
72
|
+
* [2] https://www.google.com/search?q=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&rlz=1C1GCEU_enUS832US832&oq=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j69i60.2711j0j7&sourceid=chrome&ie=UTF-8
|
|
76
73
|
* [3] https://shopify.com
|
|
77
74
|
*
|
|
78
75
|
*/
|
|
@@ -100,8 +97,7 @@ export declare function renderInfo(options: RenderAlertOptions): string | undefi
|
|
|
100
97
|
* │ • See your deployment and set it live [1] │
|
|
101
98
|
* │ │
|
|
102
99
|
* ╰──────────────────────────────────────────────────────────╯
|
|
103
|
-
* [1] https://partners.shopify.com/1797046/apps/4523695/
|
|
104
|
-
* ments
|
|
100
|
+
* [1] https://partners.shopify.com/1797046/apps/4523695/deployments
|
|
105
101
|
*
|
|
106
102
|
*/
|
|
107
103
|
export declare function renderSuccess(options: RenderAlertOptions): string | undefined;
|
package/dist/public/node/ui.js
CHANGED
|
@@ -67,10 +67,7 @@ export async function renderConcurrent({ renderOptions, ...props }) {
|
|
|
67
67
|
* │ │
|
|
68
68
|
* ╰──────────────────────────────────────────────────────────╯
|
|
69
69
|
* [1] https://shopify.dev
|
|
70
|
-
* [2] https://www.google.com/search?q=
|
|
71
|
-
* 9s2xvzla01d8cn6j7yq&rlz=1C1GCEU_enUS832US832&oq=jh56t9l34kpo
|
|
72
|
-
* 35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j
|
|
73
|
-
* 69i60.2711j0j7&sourceid=chrome&ie=UTF-8
|
|
70
|
+
* [2] https://www.google.com/search?q=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&rlz=1C1GCEU_enUS832US832&oq=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j69i60.2711j0j7&sourceid=chrome&ie=UTF-8
|
|
74
71
|
* [3] https://shopify.com
|
|
75
72
|
*
|
|
76
73
|
*/
|
|
@@ -100,8 +97,7 @@ export function renderInfo(options) {
|
|
|
100
97
|
* │ • See your deployment and set it live [1] │
|
|
101
98
|
* │ │
|
|
102
99
|
* ╰──────────────────────────────────────────────────────────╯
|
|
103
|
-
* [1] https://partners.shopify.com/1797046/apps/4523695/
|
|
104
|
-
* ments
|
|
100
|
+
* [1] https://partners.shopify.com/1797046/apps/4523695/deployments
|
|
105
101
|
*
|
|
106
102
|
*/
|
|
107
103
|
export function renderSuccess(options) {
|