Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,19 @@
]
}
},
"packages/store": {
"entry": [
"**/{commands,hooks}/**/*.ts!",
"**/index.ts!"
],
"project": "**/*.ts!",
"ignore": [
"**/graphql/**/generated/*.ts"
],
"ignoreDependencies": [
"@graphql-typed-document-node/core"
]
},
"packages/theme": {
"project": "**/*.ts!",
"entry": [
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/cli/api/graphql/admin/generated/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ export type MetafieldOwnerType =
| 'SELLING_PLAN'
/** The Shop metafield owner type. */
| 'SHOP'
/** The Transfer metafield owner type. */
| 'TRANSFER'
/** The Validation metafield owner type. */
| 'VALIDATION';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ export type MetafieldOwnerType =
| 'SELLING_PLAN'
/** The Shop metafield owner type. */
| 'SHOP'
/** The Transfer metafield owner type. */
| 'TRANSFER'
/** The Validation metafield owner type. */
| 'VALIDATION';

Expand Down
3 changes: 2 additions & 1 deletion packages/cli-kit/src/private/node/session/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export async function fetch(): Promise<Sessions | undefined> {
let contentJson: unknown
try {
contentJson = JSON.parse(content)
} catch {
} catch (error) {
if (!(error instanceof SyntaxError)) throw error
await remove()
return undefined
}
Expand Down
3 changes: 2 additions & 1 deletion packages/e2e/data/snapshots/commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@
├─ search
├─ store
│ ├─ auth
│ └─ execute
│ ├─ execute
│ └─ list
├─ theme
│ ├─ check
│ ├─ console
Expand Down
2 changes: 1 addition & 1 deletion packages/organizations/src/cli/services/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {businessPlatformRequestDoc} from '@shopify/cli-kit/node/api/business-pla
import {ensureAuthenticatedBusinessPlatform} from '@shopify/cli-kit/node/session'
import {AbortError} from '@shopify/cli-kit/node/error'

export interface FetchOrganizationsWithAccessInfoResult {
interface FetchOrganizationsWithAccessInfoResult {
organizations: Organization[]
currentUserResolved: boolean
currentUserEmail?: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,11 @@ enum AttestationTypeHandle {
Confirms that the listed beneficial owners (UBOs) are accurate and complete.
"""
OWNERSHIP_DECLARATION

"""
Records merchant acceptance of the Shopify Payments Terms of Service.
"""
SHOPIFY_PAYMENTS_TOS_ACCEPTED
}

type AuthorizedApplication {
Expand Down Expand Up @@ -6347,6 +6352,11 @@ enum Document {
"""
GI_CERTIFICATE_OF_INCORPORATION

"""
Certificate of Incumbency
"""
GI_CERTIFICATE_OF_INCUMBENCY

"""
Companies House Document
"""
Expand All @@ -6367,11 +6377,26 @@ enum Document {
"""
GI_IDENTITY_CARD

"""
Partnership Agreement
"""
GI_PARTNERSHIP_AGREEMENT

"""
Passport
"""
GI_PASSPORT

"""
Recent Annual Return
"""
GI_RECENT_ANNUAL_RETURN

"""
Shareholder Register
"""
GI_SHAREHOLDER_REGISTER

"""
UBO Attestation
"""
Expand Down Expand Up @@ -7652,11 +7677,26 @@ enum Document {
"""
NO_BANK_STATEMENT

"""
Beneficial Owner Report
"""
NO_BENEFICIAL_OWNER_REPORT

"""
Certificate of Incorporation
"""
NO_CERTIFICATE_OF_INCORPORATION

"""
Certificate of Registration
"""
NO_CERTIFICATE_OF_REGISTRATION

"""
Commercial Register Extract
"""
NO_COMMERCIAL_REGISTER_EXTRACT

"""
Director Attestation
"""
Expand All @@ -7682,6 +7722,11 @@ enum Document {
"""
NO_IDENTITY_CARD

"""
Partnership Agreement
"""
NO_PARTNERSHIP_AGREEMENT

"""
Passport
"""
Expand All @@ -7697,6 +7742,11 @@ enum Document {
"""
NO_RESIDENT_PERMIT

"""
Shareholder Register
"""
NO_SHAREHOLDER_REGISTER

"""
UBO Attestation
"""
Expand Down Expand Up @@ -15210,10 +15260,10 @@ type Query {

"""
Returns entity supporting document types for the given country code and
category. Optionally filter by purpose. When purpose is not provided, all
document types for the given country and category are returned.
category. Optionally filter by purpose and/or legal entity type. When neither
filter is provided, all document types for the given country and category are returned.
"""
entitySupportingDocumentTypes(category: Category!, countryCode: CountryCodeWithDefault!, purpose: DocumentPurpose): [SupportingDocumentType!]!
entitySupportingDocumentTypes(category: Category!, countryCode: CountryCodeWithDefault!, legalEntityType: LegalEntityTypeInput, purpose: DocumentPurpose): [SupportingDocumentType!]!

"""
Returns the government identifier type with the given handle.
Expand Down Expand Up @@ -15326,6 +15376,11 @@ type Query {
Indicates whether a subdomain is available for a new shop.
"""
shopSubdomainAvailable(subdomain: String!): Boolean

"""
Validate whether a shop is ready for a Vibe transfer.
"""
validateVibeTransferReadiness(shopId: PropertyPublicID!): ValidateVibeTransferReadinessResult!
}

input RemoveOrganizationUserRoleInput {
Expand Down Expand Up @@ -19040,3 +19095,15 @@ enum ValidLegalEntityCategoryInput {
INDIVIDUAL
UNSPECIFIED
}

type ValidateVibeTransferReadinessResult {
"""
Whether the shop is ready for a Vibe transfer.
"""
readyToTransfer: Boolean!

"""
The collection of errors.
"""
userErrors: [UserError!]
}
2 changes: 1 addition & 1 deletion packages/store/src/cli/commands/store/list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ describe('store list command', () => {

test('defines the expected flags', () => {
expect(StoreList.flags.json).toBeDefined()
expect(StoreList.flags.source).toBeUndefined()
expect('source' in StoreList.flags).toBe(false)
})
})
2 changes: 2 additions & 0 deletions packages/store/src/cli/services/store/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {outputContent, outputDebug, outputToken} from '@shopify/cli-kit/node/out
import {AbortError} from '@shopify/cli-kit/node/error'
import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn'

export {listStoredStoreAuthSummaries, type StoredStoreAuthSummary} from './stored-auth.js'

interface StoreAuthInput {
store: string
scopes: string
Expand Down
66 changes: 62 additions & 4 deletions packages/store/src/cli/services/store/auth/session-store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {storeAuthSessionKey} from './config.js'
import {STORE_AUTH_APP_CLIENT_ID, storeAuthSessionKey} from './config.js'
import {LocalStorage} from '@shopify/cli-kit/node/local-storage'

export interface StoredStoreAppSession {
Expand Down Expand Up @@ -87,15 +87,18 @@ function sanitizeStoredStoreAppSession(value: unknown): StoredStoreAppSession |
}
}

function readStoredStoreAppSessionBucket(
function sanitizeStoredStoreAppSessionBucket(
store: string,
storedBucket: unknown,
storage: LocalStorage<StoreSessionSchema>,
): StoredStoreAppSessionBucket | undefined {
const key = storeAuthSessionKey(store)
const storedBucket = storage.get(key)
if (!storedBucket || typeof storedBucket !== 'object') return undefined

const {sessionsByUserId, currentUserId} = storedBucket as Partial<StoredStoreAppSessionBucket>
const looksLikeBucket = sessionsByUserId !== undefined || currentUserId !== undefined
if (!looksLikeBucket) return undefined

const key = storeAuthSessionKey(store)
if (
!sessionsByUserId ||
typeof sessionsByUserId !== 'object' ||
Expand Down Expand Up @@ -131,6 +134,61 @@ function readStoredStoreAppSessionBucket(
}
}

function readStoredStoreAppSessionBucket(
store: string,
storage: LocalStorage<StoreSessionSchema>,
): StoredStoreAppSessionBucket | undefined {
return sanitizeStoredStoreAppSessionBucket(store, storage.get(storeAuthSessionKey(store)), storage)
}

// `conf` persists dotted keys as nested objects. Store-auth callers should not
// learn that layout directly; this helper keeps the current traversal private to
// the persistence seam while higher-level code projects summaries instead.
function readRawStoreSessionStorage(storage: LocalStorage<StoreSessionSchema>): Record<string, unknown> {
return ((storage as unknown as {config: {store: Record<string, unknown>}}).config.store ?? {}) as Record<
string,
unknown
>
}

function collectCurrentStoredStoreAppSessions(
storage: LocalStorage<StoreSessionSchema>,
store: string,
value: unknown,
sessions: StoredStoreAppSession[],
): void {
if (!value || typeof value !== 'object' || Array.isArray(value)) return

const bucket = sanitizeStoredStoreAppSessionBucket(store, value, storage)
if (bucket) {
const session = bucket.sessionsByUserId[bucket.currentUserId]
if (session) sessions.push(session)
return
}

for (const [childKey, childValue] of Object.entries(value as Record<string, unknown>)) {
collectCurrentStoredStoreAppSessions(storage, `${store}.${childKey}`, childValue, sessions)
}
}

/**
* Internal persistence helper for projecting the current session for every
* store that has locally stored store auth.
*/
export function listCurrentStoredStoreAppSessions(
storage: LocalStorage<StoreSessionSchema> = storeSessionStorage(),
): StoredStoreAppSession[] {
const sessions: StoredStoreAppSession[] = []
const keyPrefix = `${STORE_AUTH_APP_CLIENT_ID}::`

for (const [key, value] of Object.entries(readRawStoreSessionStorage(storage))) {
if (!key.startsWith(keyPrefix)) continue
collectCurrentStoredStoreAppSessions(storage, key.slice(keyPrefix.length), value, sessions)
}

return sessions
}

export function getCurrentStoredStoreAppSession(
store: string,
storage: LocalStorage<StoreSessionSchema> = storeSessionStorage(),
Expand Down
Loading
Loading