-
-
+
+
{
+ setTokenScope(undefined)
+ setVisible(true)
+ }}
+ >
+ Generate new token
+
+
+
}
+ />
+
+
+ {
- setTokenScope(undefined)
- setIsOpen(true)
+ setTokenScope('V0')
+ setVisible(true)
}}
>
- Generate new token
-
-
-
- }
- />
-
-
- {
- setTokenScope('V0')
- setIsOpen(true)
- }}
- >
-
-
Generate token for experimental API
-
-
-
-
-
-
+
+
Generate token for experimental API
+
+
+
+
-
setIsOpen(!isOpen)}
- header={
-
-
- {tokenScope === 'V0' ? 'Generate token for experimental API' : 'Generate New Token'}
-
-
- }
+ {
+ if (!open) form.reset()
+ setVisible(open)
+ }}
>
-
-
+
+
+
+
+ {
+ form.reset()
+ setVisible(false)
+ }}
+ >
+ Cancel
+
+
+ Generate token
+
+
+
+
>
)
}
diff --git a/apps/studio/components/interfaces/Organization/OrgNotFound.tsx b/apps/studio/components/interfaces/Organization/OrgNotFound.tsx
index 673c8e116c0c2..2da3c4f293dc5 100644
--- a/apps/studio/components/interfaces/Organization/OrgNotFound.tsx
+++ b/apps/studio/components/interfaces/Organization/OrgNotFound.tsx
@@ -15,17 +15,19 @@ export const OrgNotFound = ({ slug }: { slug?: string }) => {
return (
<>
-
- The selected organization does not exist or you don't have permission to access it.{' '}
- {slug ? (
- <>
- Contact the owner or administrator to create a new project in the {slug}{' '}
- organization.
- >
- ) : (
- <>Contact the owner or administrator to create a new project.>
- )}
-
+ {slug !== '_' && (
+
+ The selected organization does not exist or you don't have permission to access it.{' '}
+ {slug ? (
+ <>
+ Contact the owner or administrator to create a new project in the {slug}{' '}
+ organization.
+ >
+ ) : (
+ <>Contact the owner or administrator to create a new project.>
+ )}
+
+ )}
Select an organization to create your new project from
diff --git a/apps/studio/lib/ai/model.test.ts b/apps/studio/lib/ai/model.test.ts
index 0f4f75eca3d31..8418ad36893b9 100644
--- a/apps/studio/lib/ai/model.test.ts
+++ b/apps/studio/lib/ai/model.test.ts
@@ -18,7 +18,7 @@ describe('getModel', () => {
beforeEach(() => {
vi.resetAllMocks()
- vi.stubEnv('AWS_BEDROCK_PROFILE', 'test')
+ vi.stubEnv('AWS_BEDROCK_ROLE_ARN', 'test')
})
afterEach(() => {
diff --git a/apps/studio/lib/ai/model.ts b/apps/studio/lib/ai/model.ts
index 57698f2aaeb2a..79e52cd4e2015 100644
--- a/apps/studio/lib/ai/model.ts
+++ b/apps/studio/lib/ai/model.ts
@@ -33,10 +33,10 @@ export const ModelErrorMessage =
export async function getModel(routingKey?: string, isLimited?: boolean): Promise
{
const hasAwsCredentials = await checkAwsCredentials()
- const hasAwsBedrockprofile = !!process.env.AWS_BEDROCK_PROFILE
+ const hasAwsBedrockRoleArn = !!process.env.AWS_BEDROCK_ROLE_ARN
const hasOpenAIKey = !!process.env.OPENAI_API_KEY
- if (hasAwsBedrockprofile && hasAwsCredentials) {
+ if (hasAwsBedrockRoleArn && hasAwsCredentials) {
const bedrockModel = IS_THROTTLED || isLimited ? BEDROCK_NORMAL_MODEL : BEDROCK_PRO_MODEL
const bedrock = createRoutedBedrock(routingKey)
@@ -45,6 +45,7 @@ export async function getModel(routingKey?: string, isLimited?: boolean): Promis
}
}
+ // [Joshen] Only for local/self-hosted, hosted should always only use bedrock
if (hasOpenAIKey) {
return {
model: openai(OPENAI_MODEL),
diff --git a/apps/studio/package.json b/apps/studio/package.json
index 3085a3d6de7f8..038669dd94734 100644
--- a/apps/studio/package.json
+++ b/apps/studio/package.json
@@ -146,6 +146,7 @@
"zxcvbn": "^4.4.2"
},
"devDependencies": {
+ "@faker-js/faker": "^9.9.0",
"@graphql-codegen/cli": "5.0.5",
"@graphql-typed-document-node/core": "^3.2.0",
"@radix-ui/react-use-escape-keydown": "^1.0.3",
diff --git a/apps/studio/pages/new/[slug].tsx b/apps/studio/pages/new/[slug].tsx
index 2ba15120023c5..99d23500a1b87 100644
--- a/apps/studio/pages/new/[slug].tsx
+++ b/apps/studio/pages/new/[slug].tsx
@@ -146,6 +146,15 @@ const Wizard: NextPageWithLayout = () => {
''
)
+ // This is to make the database.new redirect work correctly. The database.new redirect should be set to supabase.com/dashboard/new/last-visited-org
+ if (slug === 'last-visited-org') {
+ if (lastVisitedOrganization) {
+ router.replace(`/new/${lastVisitedOrganization}`, undefined, { shallow: true })
+ } else {
+ router.replace(`/new/_`, undefined, { shallow: true })
+ }
+ }
+
const { mutate: sendEvent } = useSendEventMutation()
const projectCreationDisabled = useFlag('disableProjectCreationAndUpdate')
@@ -156,7 +165,10 @@ const Wizard: NextPageWithLayout = () => {
{ enabled: isFreePlan }
)
- const { data: approvedOAuthApps } = useAuthorizedAppsQuery({ slug }, { enabled: !isFreePlan })
+ const { data: approvedOAuthApps } = useAuthorizedAppsQuery(
+ { slug },
+ { enabled: !isFreePlan && slug !== '_' }
+ )
const hasOAuthApps = approvedOAuthApps && approvedOAuthApps.length > 0
@@ -623,7 +635,9 @@ const Wizard: NextPageWithLayout = () => {
/>
)}
- {!isAdmin && !orgNotFound && }
+ {isOrganizationsSuccess && !isAdmin && !orgNotFound && (
+
+ )}
{orgNotFound && }
diff --git a/apps/studio/tests/vitestSetup.ts b/apps/studio/tests/vitestSetup.ts
index 00ac0696c074a..e32fd66226fb0 100644
--- a/apps/studio/tests/vitestSetup.ts
+++ b/apps/studio/tests/vitestSetup.ts
@@ -40,10 +40,11 @@ beforeAll(() => {
routerMock.useParser(createDynamicRouteParser(['/projects/[ref]']))
})
-afterAll(() => mswServer.close())
-
-afterEach(() => mswServer.resetHandlers())
-
afterEach(() => {
+ mswServer.resetHandlers()
cleanup()
})
+
+afterAll(() => {
+ mswServer.close()
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6f2a902f58768..a239e511204cd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -615,6 +615,9 @@ importers:
shiki:
specifier: ^3.2.1
version: 3.2.1
+ shx:
+ specifier: ^0.4.0
+ version: 0.4.0
simple-git:
specifier: ^3.24.0
version: 3.24.0(supports-color@8.1.1)
@@ -1009,6 +1012,9 @@ importers:
specifier: ^4.4.2
version: 4.4.2
devDependencies:
+ '@faker-js/faker':
+ specifier: ^9.9.0
+ version: 9.9.0
'@graphql-codegen/cli':
specifier: 5.0.5
version: 5.0.5(@parcel/watcher@2.5.1)(@types/node@22.13.14)(encoding@0.1.13)(graphql-sock@1.0.1(graphql@16.11.0))(graphql@16.11.0)(supports-color@8.1.1)(typescript@5.5.2)
@@ -2184,7 +2190,7 @@ importers:
version: 6.6.3
'@testing-library/react':
specifier: ^16.0.0
- version: 16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ version: 16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@types/lodash':
specifier: 4.17.5
version: 4.17.5
@@ -3659,6 +3665,10 @@ packages:
resolution: {integrity: sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==}
engines: {node: '>=14.0.0', npm: '>=6.0.0'}
+ '@faker-js/faker@9.9.0':
+ resolution: {integrity: sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==}
+ engines: {node: '>=18.0.0', npm: '>=9.0.0'}
+
'@fal-works/esbuild-plugin-global-externals@2.1.2':
resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==}
@@ -8421,6 +8431,10 @@ packages:
resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==}
engines: {node: '>=18'}
+ '@testing-library/dom@10.4.0':
+ resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==}
+ engines: {node: '>=18'}
+
'@testing-library/jest-dom@6.6.3':
resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==}
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
@@ -11481,6 +11495,10 @@ packages:
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
engines: {node: '>=18.0.0'}
+ execa@1.0.0:
+ resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==}
+ engines: {node: '>=6'}
+
execa@7.2.0:
resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
@@ -11969,6 +11987,10 @@ packages:
resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==}
engines: {node: '>=10'}
+ get-stream@4.1.0:
+ resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
+ engines: {node: '>=6'}
+
get-stream@6.0.1:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
@@ -12601,6 +12623,10 @@ packages:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
+ interpret@1.4.0:
+ resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
+ engines: {node: '>= 0.10'}
+
intersection-observer@0.10.0:
resolution: {integrity: sha512-fn4bQ0Xq8FTej09YC/jqKZwtijpvARlRp6wxL5WTA6yPe2YWSJ5RJh7Nm79rK2qB0wr6iDQzH60XGq5V/7u8YQ==}
@@ -12882,6 +12908,10 @@ packages:
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
engines: {node: '>= 0.4'}
+ is-stream@1.1.0:
+ resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
+ engines: {node: '>=0.10.0'}
+
is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
@@ -14514,6 +14544,10 @@ packages:
engines: {node: '>= 4'}
hasBin: true
+ npm-run-path@2.0.2:
+ resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
+ engines: {node: '>=4'}
+
npm-run-path@5.3.0:
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -14776,6 +14810,10 @@ packages:
resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}
engines: {node: '>= 0.4'}
+ p-finally@1.0.0:
+ resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
+ engines: {node: '>=4'}
+
p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
@@ -15889,6 +15927,10 @@ packages:
react: ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
+ rechoir@0.6.2:
+ resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
+ engines: {node: '>= 0.10'}
+
redent@3.0.0:
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
engines: {node: '>=8'}
@@ -16420,6 +16462,11 @@ packages:
shell-quote@1.8.1:
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
+ shelljs@0.9.2:
+ resolution: {integrity: sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
shiki@1.6.0:
resolution: {integrity: sha512-P31ROeXcVgW/k3Z+vUUErcxoTah7ZRaimctOpzGuqAntqnnSmx1HOsvnbAB8Z2qfXPRhw61yptAzCsuKOhTHwQ==}
@@ -16447,6 +16494,11 @@ packages:
should@13.2.3:
resolution: {integrity: sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==}
+ shx@0.4.0:
+ resolution: {integrity: sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
@@ -16820,6 +16872,10 @@ packages:
resolution: {integrity: sha512-p9LsUieSjWNNAxVCXLeilaDlmuUOrDS5/dF9znM1nZc7EGX5+zEFC0bEevsNIaldjlks+2jns5Siz6F9iK6jwA==}
engines: {node: '>=0.10.0'}
+ strip-eof@1.0.0:
+ resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
+ engines: {node: '>=0.10.0'}
+
strip-final-newline@3.0.0:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
@@ -20296,7 +20352,7 @@ snapshots:
'@contentlayer2/core': 0.5.3(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1)
'@contentlayer2/utils': 0.5.3
chokidar: 3.5.3
- fast-glob: 3.3.2
+ fast-glob: 3.3.3
gray-matter: 4.0.3
imagescript: 1.3.0
micromatch: 4.0.8
@@ -20751,6 +20807,8 @@ snapshots:
'@faker-js/faker@7.6.0': {}
+ '@faker-js/faker@9.9.0': {}
+
'@fal-works/esbuild-plugin-global-externals@2.1.2': {}
'@fastify/ajv-compiler@3.6.0':
@@ -27715,6 +27773,17 @@ snapshots:
lz-string: 1.5.0
pretty-format: 27.5.1
+ '@testing-library/dom@10.4.0':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/runtime': 7.26.10
+ '@types/aria-query': 5.0.2
+ aria-query: 5.3.0
+ chalk: 4.1.2
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ pretty-format: 27.5.1
+
'@testing-library/jest-dom@6.6.3':
dependencies:
'@adobe/css-tools': 4.4.0
@@ -27735,6 +27804,16 @@ snapshots:
'@types/react': 18.3.3
'@types/react-dom': 18.3.0
+ '@testing-library/react@16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@babel/runtime': 7.26.10
+ '@testing-library/dom': 10.4.0
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.3
+ '@types/react-dom': 18.3.0
+
'@testing-library/user-event@14.6.1(@testing-library/dom@10.1.0)':
dependencies:
'@testing-library/dom': 10.1.0
@@ -27748,7 +27827,7 @@ snapshots:
'@ts-morph/common@0.19.0':
dependencies:
- fast-glob: 3.3.2
+ fast-glob: 3.3.3
minimatch: 7.4.6
mkdirp: 2.1.6
path-browserify: 1.0.1
@@ -31203,6 +31282,16 @@ snapshots:
dependencies:
eventsource-parser: 3.0.2
+ execa@1.0.0:
+ dependencies:
+ cross-spawn: 6.0.6
+ get-stream: 4.1.0
+ is-stream: 1.1.0
+ npm-run-path: 2.0.2
+ p-finally: 1.0.0
+ signal-exit: 3.0.7
+ strip-eof: 1.0.0
+
execa@7.2.0:
dependencies:
cross-spawn: 7.0.6
@@ -31782,6 +31871,10 @@ snapshots:
get-stdin@8.0.0: {}
+ get-stream@4.1.0:
+ dependencies:
+ pump: 3.0.3
+
get-stream@6.0.1: {}
get-stream@8.0.1: {}
@@ -32710,6 +32803,8 @@ snapshots:
internmap@2.0.3: {}
+ interpret@1.4.0: {}
+
intersection-observer@0.10.0: {}
invariant@2.2.4:
@@ -32964,6 +33059,8 @@ snapshots:
dependencies:
call-bound: 1.0.4
+ is-stream@1.1.0: {}
+
is-stream@2.0.1: {}
is-stream@3.0.0: {}
@@ -35374,6 +35471,10 @@ snapshots:
shell-quote: 1.8.1
string.prototype.padend: 3.1.5
+ npm-run-path@2.0.2:
+ dependencies:
+ path-key: 2.0.1
+
npm-run-path@5.3.0:
dependencies:
path-key: 4.0.0
@@ -35688,6 +35789,8 @@ snapshots:
object-keys: 1.1.1
safe-push-apply: 1.0.0
+ p-finally@1.0.0: {}
+
p-limit@3.1.0:
dependencies:
yocto-queue: 0.1.0
@@ -36991,6 +37094,10 @@ snapshots:
tiny-invariant: 1.3.3
victory-vendor: 36.6.11
+ rechoir@0.6.2:
+ dependencies:
+ resolve: 1.22.10
+
redent@3.0.0:
dependencies:
indent-string: 4.0.0
@@ -37816,6 +37923,13 @@ snapshots:
shell-quote@1.8.1: {}
+ shelljs@0.9.2:
+ dependencies:
+ execa: 1.0.0
+ fast-glob: 3.3.3
+ interpret: 1.4.0
+ rechoir: 0.6.2
+
shiki@1.6.0:
dependencies:
'@shikijs/core': 1.6.0
@@ -37859,6 +37973,11 @@ snapshots:
should-type-adaptors: 1.1.0
should-util: 1.0.1
+ shx@0.4.0:
+ dependencies:
+ minimist: 1.2.8
+ shelljs: 0.9.2
+
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
@@ -38292,6 +38411,8 @@ snapshots:
strip-color@0.1.0: {}
+ strip-eof@1.0.0: {}
+
strip-final-newline@3.0.0: {}
strip-indent@3.0.0: