Add preview-store discriminator to stored store auth sessions#7557
Draft
alfonso-noriega wants to merge 2 commits into
Draft
Add preview-store discriminator to stored store auth sessions#7557alfonso-noriega wants to merge 2 commits into
alfonso-noriega wants to merge 2 commits into
Conversation
Adds a 'kind' discriminator ('standard' | 'preview') and optional 'preview'
metadata sub-object to StoredStoreAppSession, plus a recovery dispatcher that
surfaces a preview-specific error when a placeholder-owned session can no
longer be reached.
This is internal scaffolding for the upcoming 'shopify store create preview'
command. No user-visible change yet:
- Standard sessions written before this field existed read back as
'standard' (sanitizer defaults missing/unknown 'kind' to 'standard' and
omits the field on write to keep legacy buckets quiet).
- Preview-kind sessions require valid 'preview' metadata
(placeholderAccountUuid + coreUrl) or they're rejected by the sanitizer.
- session-lifecycle skips the PKCE refresh path entirely for preview
sessions and surfaces the preview-specific recovery error.
- admin-transport's 401 paths (both versions and the main GraphQL request)
route through the new dispatcher so preview sessions don't get told to
re-run 'shopify store auth'.
The follow-up PR will introduce 'store create preview' itself and start
writing 'kind: preview' sessions.
Contributor
Author
This stack of pull requests is managed by Graphite. Learn more about stacking. |
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

WHY are these changes introduced?
Internal scaffolding for the upcoming
shopify store create previewcommand (part of the Preview Store for AI Agent Surfaces M1 milestone, Foundations/DevTools epic).Preview stores are backed by a placeholder identity rather than a real Shopify account. They are minted by Core's
/services/preview-storesorchestrator, hand back a shop-scoped Admin API token, and have no relationship with the OAuth token endpoint — so the existing PKCE refresh and re-authentication paths in@shopify/storedon't apply to them.Before we can wire up
store create previewand start persisting these sessions, the stored-session schema needs a discriminator and the recovery surfaces insession-lifecycleandadmin-transportneed to know not to send users back throughshopify store authfor a placeholder-owned store.This PR is intentionally scoped to that scaffolding. There is no new command, no new way to mint a preview session, and no user-visible behavior change. The follow-up PR introduces
shopify store create previewand starts writingkind: 'preview'sessions through the existingsetStoredStoreAppSession.WHAT is this pull request doing?
Schema additions in
session-store.ts:kind?: 'standard' | 'preview'onStoredStoreAppSession. Optional in storage so sessions written before this field existed read back as'standard'.preview?: { placeholderAccountUuid, coreUrl, magicLinkUrl?, magicLinkExpiresAt? }sub-object, present iffkind === 'preview'.sessionKind(session)and the type guardisPreviewStoreSession(session).Sanitizer updates in
session-store.ts:kindvalues are coerced to'standard'and the field is omitted on write — legacy buckets stay byte-identical to today.kind: 'preview'session with missing or malformedpreviewmetadata is rejected outright (downstream code requiresplaceholderAccountUuidandcoreUrlto act on it).Recovery dispatcher in
recovery.ts:throwReauthenticatePreviewStoreError(message, store)surfaces a preview-specific error that does not point users atshopify store auth(which would be meaningless for a placeholder-owned store).throwReauthenticateForSession(message, session)dispatches to the right helper based onisPreviewStoreSession(session).throwReauthenticateStoreAuthErroris unchanged and retained as the standard-session helper.Wiring in
session-lifecycle.tsandadmin-transport.ts:loadStoredStoreSessionshort-circuits the PKCE refresh path entirely for preview sessions and surfaces the preview-specific recovery error directly.admin-transport.ts401 paths) now route throughthrowReauthenticateForSession.Decisions worth calling out:
LocalStorage<StoreSessionSchema>shape already accommodates them; splitting storage would force every reader (store execute, attribution, last-seen-user, futurestore list) to do two lookups instead of branching on a field.shopify store create previewdoes not exist yet. The follow-up PR will plug in the actual command.StoredStoreSessionKindandStoredPreviewStoreSessionare kept module-internal for now and become exports the moment the next PR consumes them.How to test your changes?
Coverage of interest:
session-store.test.ts > preview-store discriminator— round-trip of preview sessions, legacy-session back-compat (nokindreads as standard, write omits the field), unknown-kind coercion, malformed-metadata rejection, side-by-side standard + preview sessions on the same store fqdn.recovery.test.ts > throwReauthenticateForSession— dispatches standard sessions to the PKCE re-auth helper and preview sessions to the preview-specific helper; defensively falls back to the standard helper whenkind: 'preview'is set without metadata.session-lifecycle.test.ts > preview-store sessions— never invokesrefreshStoreAccessTokenfor preview sessions even when arefreshTokenis present, surfaces the preview-specific recovery message, returns preview sessions as-is whenexpiresAtis unset.The two pre-existing failures in
callback.test.ts("doesn't"vs"does not"string mismatch) are unchanged onmainand unrelated to this PR.There is no runtime CLI command to exercise — invoking
shopify store auth,shopify store execute, etc. continues to behave exactly as before for all standard sessions.Post-release steps
None.
Checklist
shopify store create previewin the follow-up PR.setLastSeenUserIdcontinues to receive the session'suserId; analytics for theplaceholder:prefix used by preview sessions will be addressed whenstore create previewlands.patchfor bug fixes ·minorfor new features ·majorfor breaking changes) and added a changeset withpnpm changeset add—minorbump on@shopify/store. No bug fix here; the change extends the stored-session schema with a new discriminator and metadata sub-object as the first slice of the preview-store feature.