@thoughtbot/superglue 0.54.0 → 1.0.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/.prettierrc +3 -1
- package/dist/action_creators.d.mts +1 -23
- package/dist/action_creators.mjs +3 -7
- package/dist/{chunk-MNVGYKSD.mjs → chunk-LGUVOEZ3.mjs} +253 -242
- package/dist/chunk-LGUVOEZ3.mjs.map +1 -0
- package/dist/cjs/action_creators.cjs +215 -172
- package/dist/cjs/action_creators.cjs.map +1 -1
- package/dist/cjs/superglue.cjs +666 -766
- package/dist/cjs/superglue.cjs.map +1 -1
- package/dist/index-BYr1PoYr.d.mts +232 -0
- package/dist/superglue.d.mts +53 -54
- package/dist/superglue.mjs +368 -482
- package/dist/superglue.mjs.map +1 -1
- package/package.json +9 -10
- package/typedoc.json +3 -1
- package/dist/chunk-MNVGYKSD.mjs.map +0 -1
- package/dist/index-DfWsUSqv.d.mts +0 -246
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/utils/url.ts","../lib/utils/helpers.ts","../lib/utils/immutability.ts","../lib/utils/request.ts","../lib/config.ts","../lib/utils/ujs.ts","../lib/utils/window.ts","../lib/action_creators/index.ts","../lib/actions.ts","../lib/action_creators/requests.ts"],"sourcesContent":["import parse from 'url-parse'\nimport { PageKey } from '../types'\n\nexport function pathQuery(url: string): string {\n const { pathname, query } = new parse(url, {})\n\n return pathname + query\n}\n\nexport function pathQueryHash(url: string): string {\n const { pathname, query, hash } = new parse(url, {})\n\n return pathname + query + hash\n}\n\nexport function hasPropsAt(url: string): boolean {\n const parsed = new parse(url, {}, true)\n const query = parsed.query\n\n return !!query['props_at']\n}\n\nexport function propsAtParam(url: string): string | undefined {\n const parsed = new parse(url, {}, true)\n const query = parsed.query\n\n return query['props_at']\n}\n\nexport function withFormatJson(url: string): string {\n const parsed = new parse(url, {}, true)\n parsed.query['format'] = 'json'\n\n return parsed.toString()\n}\n\nexport function pathWithoutBZParams(url: string): string {\n const parsed = new parse(url, {}, true)\n const query = parsed.query\n\n delete query['props_at']\n delete query['format']\n parsed.set('query', query)\n\n return pathQueryHash(parsed.toString())\n}\n\nexport function removePropsAt(url: string): string {\n const parsed = new parse(url, {}, true)\n const query = parsed.query\n\n delete query['props_at']\n parsed.set('query', query)\n\n return parsed.toString()\n}\n\n/**\n * Converts a url to a PageKey.\n *\n * @param url\n * @returns\n */\nexport function urlToPageKey(url: string): PageKey {\n const parsed = new parse(url, {}, true)\n const query = parsed.query\n\n delete query['props_at']\n delete query['format']\n parsed.set('query', query)\n\n return pathQuery(parsed.toString())\n}\n\nexport function withoutHash(url: string): string {\n const parsed = new parse(url, {}, true)\n parsed.set('hash', '')\n return parsed.toString()\n}\n\nexport function withoutBusters(url: string): string {\n const parsed = new parse(url, {}, true)\n const query = parsed.query\n delete query['format']\n parsed.set('query', query)\n\n return pathQuery(parsed.toString())\n}\n\nexport function formatForXHR(url: string): string {\n const formats = [withoutHash, withFormatJson]\n\n return formats.reduce((memo, f) => f(memo), url)\n}\n\nexport function parsePageKey(pageKey: PageKey) {\n const { pathname, query } = new parse(pageKey, {}, true)\n\n return {\n pathname,\n search: query,\n }\n}\n","import { GraftResponse, HistoryState, VisitResponse } from '../types'\nimport { urlToPageKey } from './url'\n\nexport function isGraft(page: GraftResponse | VisitResponse): boolean {\n return 'action' in page && page.action === 'graft'\n}\n\nexport function extractNodeAndPath(page: GraftResponse): {\n node: unknown\n pathToNode: string\n} {\n const { data: node, action, path: pathToNode } = page\n\n if (action === 'graft') {\n return { node, pathToNode }\n } else {\n const errMsg =\n 'Expected page to be a graft response rendered from node filtering.'\n throw new Error(errMsg)\n }\n}\n\nexport function argsForHistory(path: string): [string, HistoryState] {\n const pageKey = urlToPageKey(path)\n\n return [\n path,\n {\n superglue: true,\n pageKey,\n posX: 0,\n posY: 0,\n },\n ]\n}\n","// These were taken from Scour.js\n// Then, modified to respect the id=0 keypath\n\nimport { JSONMappable, JSONValue, Keypath } from '../types'\n\nconst canLookAhead = /^[\\da-zA-Z\\-_]+=[\\da-zA-Z\\-_]+$/\n\nclass KeyPathError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'KeyPathError'\n }\n}\n\n/**\n * Retrieves data from a JSON object using a {@link Keypath}\n *\n * @param node\n * @param path\n * @returns\n */\nfunction getIn(node: JSONMappable, path: Keypath): JSONValue {\n const keyPath = normalizeKeyPath(path)\n let result: JSONValue = node\n let i: number\n\n for (i = 0; i < keyPath.length; i++) {\n const key = keyPath[i]\n\n if (typeof result === 'object' && result !== null) {\n if (!Array.isArray(result) && canLookAhead.test(key)) {\n throw new KeyPathError(\n `Expected to find an Array when using the key: ${key}`\n )\n }\n\n result = atKey(result, key)\n } else {\n throw new KeyPathError(\n `Expected to traverse an Array or Obj, got ${JSON.stringify(result)}`\n )\n }\n }\n\n if (i === keyPath.length) {\n return result\n } else {\n return undefined\n }\n}\n\nfunction clone(node: JSONMappable): JSONMappable {\n return Array.isArray(node) ? [].slice.call(node) : { ...node }\n}\n\nfunction getKey(node: JSONMappable, key: string): string | number | never {\n if (Array.isArray(node) && Number.isNaN(Number(key))) {\n const key_parts = Array.from(key.split('='))\n const attr = key_parts[0]\n const id = key_parts[1]\n\n if (!id || !attr) {\n return key\n }\n\n let i: number\n let child: JSONValue\n\n for (i = 0; i < node.length; i++) {\n child = node[i]\n if (\n typeof child === 'object' &&\n !Array.isArray(child) &&\n child !== null\n ) {\n const val = child[attr]\n if (val && val.toString() === id) {\n break\n }\n } else {\n throw new KeyPathError(`Could not look ahead ${key} at ${child}`)\n }\n }\n\n if (i === node.length) {\n throw new KeyPathError(`Could not find ${key} while looking ahead`)\n }\n\n return i\n } else {\n return key\n }\n}\n\nfunction atKey(node: JSONMappable, key: string) {\n const actualKey = getKey(node, key)\n\n if (Array.isArray(node)) {\n return node[actualKey as number]\n } else {\n return node[actualKey]\n }\n}\n\nfunction normalizeKeyPath(path: string): string[] {\n if (typeof path === 'string') {\n path = path.replace(/ /g, '')\n if (path === '') {\n return []\n }\n\n return path.split('.')\n } else {\n return path\n }\n}\n/**\n * Sets data into a JSON object using a {@link Keypath}\n *\n * @param object\n * @param path\n * @param value\n * @returns\n */\nfunction setIn<T extends JSONMappable>(\n object: T,\n path: string,\n value: JSONValue\n): T | never {\n const keypath = normalizeKeyPath(path)\n\n const results: {\n 0: T\n [key: number]: JSONValue\n } = { 0: object }\n\n const parents: {\n 0: T\n [key: number]: JSONValue\n } = { 0: object }\n\n let i: number\n\n for (i = 0; i < keypath.length; i++) {\n const parent = parents[i]\n\n if (!(typeof parent === 'object' && parent !== null)) {\n throw new KeyPathError(\n `Expected to traverse an Array or Obj, got ${JSON.stringify(parent)}`\n )\n }\n\n const child = atKey(parent, keypath[i])\n parents[i + 1] = child\n }\n\n results[keypath.length] = value\n\n for (i = keypath.length - 1; i >= 0; i--) {\n // Parents will always have a JSONValue at\n // keypath.length so this loop skips that one element\n // Every other element in parents is a JSONMappable\n const target = clone(parents[i] as JSONMappable)\n results[i] = target\n const key = getKey(results[i] as JSONMappable, keypath[i])\n if (Array.isArray(target)) {\n target[key as number] = results[i + 1]\n } else {\n target[key] = results[i + 1]\n }\n }\n\n return results[0]\n}\n\nexport { getIn, setIn, KeyPathError }\n","import parse from 'url-parse'\nimport { formatForXHR } from './url'\nimport { config } from '../config'\nimport { BasicRequestInit, ParsedResponse, RootState } from '../types'\n\nexport function isValidResponse(xhr: Response): boolean {\n return isValidContent(xhr) && !downloadingFile(xhr)\n}\n\nexport function isValidContent(rsp: Response): boolean {\n const contentType = rsp.headers.get('content-type')\n const jsContent = /^(?:application\\/json)(?:;|$)/\n\n return !!(contentType && contentType.match(jsContent))\n}\n\nfunction downloadingFile(xhr: Response): boolean {\n const disposition = xhr.headers.get('content-disposition')\n\n return !!(disposition && disposition.match(/^attachment/) !== null)\n}\n\nclass SuperglueResponseError extends Error {\n response: Response\n\n constructor(message: string) {\n super(message)\n this.name = 'SuperglueResponseError'\n }\n}\n\nexport function validateResponse(args: ParsedResponse): ParsedResponse {\n const { rsp } = args\n if (isValidResponse(rsp)) {\n return args\n } else {\n const error = new SuperglueResponseError('Invalid Superglue Response')\n error.response = rsp\n throw error\n }\n}\n\nexport function handleServerErrors(args: ParsedResponse): ParsedResponse {\n const { rsp } = args\n if (!rsp.ok && rsp.status !== 422) {\n if (rsp.status === 406) {\n console.error(\n \"Superglue encountered a 406 Not Acceptable response. This can happen if you used respond_to and didn't specify format.json in the block. Try adding it to your respond_to. For example:\\n\\n\" +\n 'respond_to do |format|\\n' +\n ' format.html\\n' +\n ' format.json\\n' +\n ' format.csv\\n' +\n 'end'\n )\n }\n const error = new SuperglueResponseError(rsp.statusText)\n error.response = rsp\n throw error\n }\n return args\n}\n\nexport function argsForFetch(\n getState: () => RootState,\n pathQuery: string,\n {\n method = 'GET',\n headers = {},\n body = '',\n signal,\n ...rest\n }: BasicRequestInit = {}\n): [string, BasicRequestInit] {\n method = method.toUpperCase()\n const currentState = getState().superglue\n\n const nextHeaders = { ...headers }\n nextHeaders['x-requested-with'] = 'XMLHttpRequest'\n nextHeaders['accept'] = 'application/json'\n nextHeaders['x-superglue-request'] = 'true'\n\n if (method != 'GET' && method != 'HEAD') {\n nextHeaders['content-type'] = 'application/json'\n }\n\n if (body instanceof FormData) {\n delete nextHeaders['content-type']\n }\n\n if (currentState.csrfToken) {\n nextHeaders['x-csrf-token'] = currentState.csrfToken\n }\n\n const fetchPath = new parse(\n formatForXHR(pathQuery),\n config.baseUrl || {},\n true\n )\n\n const credentials = 'same-origin'\n\n if (!(method == 'GET' || method == 'HEAD')) {\n nextHeaders['x-http-method-override'] = method\n method = 'POST'\n }\n\n const options: BasicRequestInit = {\n method,\n headers: nextHeaders,\n body,\n credentials,\n signal,\n }\n\n if (currentState.currentPageKey) {\n const referrer = new parse(\n currentState.currentPageKey,\n config.baseUrl || {},\n false\n ).href\n\n options.referrer = referrer\n }\n\n if (method == 'GET' || method == 'HEAD') {\n if (options.body instanceof FormData) {\n const allData = new URLSearchParams(\n options.body as unknown as Record<string, string>\n )\n\n // TODO: Add coverage for this\n const nextQuery = { ...fetchPath.query, ...Object.fromEntries(allData) }\n fetchPath.set('query', nextQuery)\n }\n\n delete options.body\n }\n\n return [fetchPath.toString(), { ...options, ...rest }]\n}\n\nexport function extractJSON(rsp: Response): PromiseLike<ParsedResponse> {\n return rsp\n .json()\n .then((json) => {\n return { rsp, json }\n })\n .catch((e) => {\n e.response = rsp\n throw e\n })\n}\n\nexport function parseResponse(prm: Response): PromiseLike<ParsedResponse> {\n return Promise.resolve(prm)\n .then(extractJSON)\n .then(handleServerErrors)\n .then(validateResponse)\n}\n","export const config = {\n baseUrl: '',\n maxPages: 20,\n}\n","import { withoutBusters } from './url'\nimport {\n Handlers,\n UJSHandlers,\n SuperglueStore,\n ApplicationVisit,\n ApplicationRemote,\n RemoteProps,\n VisitProps,\n} from '../types'\n\nexport class HandlerBuilder {\n public attributePrefix: string\n public visit: ApplicationVisit\n public remote: ApplicationRemote\n private store: SuperglueStore\n\n constructor({\n ujsAttributePrefix,\n visit,\n remote,\n store,\n }: {\n ujsAttributePrefix: string\n visit: ApplicationVisit\n remote: ApplicationRemote\n store: SuperglueStore\n }) {\n this.attributePrefix = ujsAttributePrefix\n this.isUJS = this.isUJS.bind(this)\n this.store = store\n\n this.handleSubmit = this.handleSubmit.bind(this)\n this.handleClick = this.handleClick.bind(this)\n\n this.visit = visit\n this.remote = remote\n this.visitOrRemote = this.visitOrRemote.bind(this)\n }\n\n retrieveLink(target: Element): HTMLAnchorElement | undefined {\n const link = target.closest<HTMLAnchorElement>('a')\n if (link && link.href.length !== 0) {\n return link\n }\n }\n\n isNonStandardClick(\n event: React.MouseEvent<HTMLDivElement, MouseEvent>\n ): boolean {\n return (\n event.button > 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n }\n\n isUJS(node: HTMLFormElement | HTMLAnchorElement): boolean {\n const hasVisit = !!node.getAttribute(this.attributePrefix + '-visit')\n const hasRemote = !!node.getAttribute(this.attributePrefix + '-remote')\n\n return hasVisit || hasRemote\n }\n\n handleSubmit(event: React.FormEvent<HTMLDivElement>): void {\n const form = event.target\n\n if (!(form instanceof HTMLFormElement)) {\n return\n }\n\n if (!this.isUJS(form)) {\n return\n }\n\n event.preventDefault()\n\n let url = form.getAttribute('action')\n if (!url) {\n return\n }\n\n const method = (form.getAttribute('method') || 'POST').toUpperCase()\n url = withoutBusters(url)\n\n this.visitOrRemote(form, url, {\n method,\n body: new FormData(form),\n })\n }\n\n handleClick(event: React.MouseEvent<HTMLDivElement, MouseEvent>): void {\n if (!(event.target instanceof Element)) {\n return\n }\n\n const link = this.retrieveLink(event.target)\n const isNonStandard = this.isNonStandardClick(event)\n if (!link || isNonStandard || !this.isUJS(link)) {\n return\n }\n\n event.preventDefault()\n let url = link.getAttribute('href')\n if (!url) {\n return\n }\n url = withoutBusters(url)\n\n this.visitOrRemote(link, url, { method: 'GET' })\n }\n\n visitOrRemote(\n linkOrForm: HTMLAnchorElement | HTMLFormElement,\n url: string,\n opts: RemoteProps | VisitProps\n ): void {\n const dataset = { ...linkOrForm.dataset }\n\n if (linkOrForm.getAttribute(this.attributePrefix + '-visit')) {\n this.visit(url, { ...opts, dataset })\n }\n\n if (linkOrForm.getAttribute(this.attributePrefix + '-remote')) {\n const { currentPageKey } = this.store.getState().superglue\n this.remote(url, {\n ...opts,\n pageKey: currentPageKey,\n dataset,\n })\n }\n }\n\n handlers(): Handlers {\n return {\n onClick: this.handleClick,\n onSubmit: this.handleSubmit,\n }\n }\n}\n\nexport const ujsHandlers: UJSHandlers = ({\n ujsAttributePrefix,\n visit,\n remote,\n store,\n}) => {\n const builder = new HandlerBuilder({\n visit,\n remote,\n ujsAttributePrefix,\n store,\n })\n\n return builder.handlers()\n}\n","export function needsRefresh(\n prevAssets: string[],\n newAssets: string[]\n): boolean {\n if (prevAssets && newAssets) {\n const hasNewAssets = !newAssets.every((asset) => prevAssets.includes(asset))\n return hasNewAssets\n } else {\n return false\n }\n}\n","import { urlToPageKey, getIn } from '../utils'\nimport parse from 'url-parse'\nimport {\n saveResponse,\n GRAFTING_ERROR,\n GRAFTING_SUCCESS,\n updateFragments,\n handleGraft,\n} from '../actions'\nimport { remote } from './requests'\nimport {\n VisitResponse,\n SaveAndProcessPageThunk,\n DefermentThunk,\n GraftResponse,\n Defer,\n JSONMappable,\n} from '../types'\nexport * from './requests'\n\nfunction fetchDeferments(\n pageKey: string,\n defers: Defer[] = []\n): DefermentThunk {\n pageKey = urlToPageKey(pageKey)\n return (dispatch) => {\n const fetches = defers\n .filter(({ type }) => type === 'auto')\n .map(function ({\n url,\n successAction = GRAFTING_SUCCESS,\n failAction = GRAFTING_ERROR,\n }) {\n const parsedUrl = new parse(url, true)\n\n // props_at will always be present in a graft response\n // That's why this is marked `as string`\n const keyPath = parsedUrl.query.props_at as string\n\n return dispatch(remote(url, { pageKey }))\n .then(() => {\n dispatch({\n type: successAction,\n payload: {\n pageKey,\n keyPath,\n },\n })\n })\n .catch((err) => {\n dispatch({\n type: failAction,\n payload: {\n url,\n err,\n pageKey,\n keyPath,\n },\n })\n })\n })\n\n return Promise.all(fetches)\n }\n}\n\n/**\n * Save and process a rendered view from PropsTemplate. This is the primitive\n * function that `visit` and `remote` calls when it receives a page.\n *\n * If you render a page outside the normal request response cycle, e.g,\n * websocket, you can use this function to save the payload.\n */\nexport function saveAndProcessPage(\n pageKey: string,\n page: VisitResponse | GraftResponse\n): SaveAndProcessPageThunk {\n return (dispatch, getState) => {\n pageKey = urlToPageKey(pageKey)\n\n const { defers = [] } = page\n\n if ('action' in page) {\n const prevPage = getState().pages[pageKey]\n dispatch(handleGraft({ pageKey, page }))\n const currentPage = getState().pages[pageKey]\n\n currentPage.fragments.forEach((fragment) => {\n const { type, path } = fragment\n // A fragment only works on a block in props_template. So using getIn\n // will always return a JSONMappable\n const currentFragment = getIn(currentPage, path) as JSONMappable\n const prevFragment = getIn(prevPage, path) as JSONMappable\n if (!prevFragment) {\n dispatch(\n updateFragments({\n name: type,\n pageKey: pageKey,\n value: currentFragment,\n path,\n })\n )\n } else if (currentFragment !== prevFragment) {\n dispatch(\n updateFragments({\n name: type,\n pageKey: pageKey,\n value: currentFragment,\n previousValue: prevFragment,\n path,\n })\n )\n }\n })\n } else {\n dispatch(saveResponse({ pageKey, page }))\n const currentPage = getState().pages[pageKey]\n\n currentPage.fragments.forEach((fragment) => {\n const { type, path } = fragment\n const currentFragment = getIn(currentPage, path) as JSONMappable\n\n dispatch(\n updateFragments({\n name: type,\n pageKey: pageKey,\n value: currentFragment,\n path,\n })\n )\n })\n }\n\n const hasFetch = typeof fetch != 'undefined'\n if (hasFetch) {\n return dispatch(fetchDeferments(pageKey, defers)).then(() =>\n Promise.resolve()\n )\n } else {\n return Promise.resolve()\n }\n }\n}\n","import { createAction } from '@reduxjs/toolkit'\nimport {\n FetchArgs,\n PageKey,\n GraftResponse,\n VisitResponse,\n JSONMappable,\n Keypath,\n} from './types'\nimport { urlToPageKey } from './utils'\n\nexport const GRAFTING_ERROR = '@@superglue/GRAFTING_ERROR'\nexport const GRAFTING_SUCCESS = '@@superglue/GRAFTING_SUCCESS'\n\nexport const saveResponse = createAction(\n '@@superglue/SAVE_RESPONSE',\n ({ pageKey, page }: { pageKey: string; page: VisitResponse }) => {\n pageKey = urlToPageKey(pageKey)\n\n return {\n payload: {\n pageKey,\n page,\n },\n }\n }\n)\n\nexport const handleGraft = createAction(\n '@@superglue/HANDLE_GRAFT',\n ({ pageKey, page }: { pageKey: string; page: GraftResponse }) => {\n pageKey = urlToPageKey(pageKey)\n\n return {\n payload: {\n page,\n pageKey,\n },\n }\n }\n)\n\nexport const superglueError = createAction<{ message: string }>(\n '@@superglue/ERROR'\n)\n\n/**\n * A redux action called whenever a fragment is received from `visit` or updated\n * using `remote`. Its a useful action to use for cross cutting concerns like a\n * shared header or a shopping cart. For example:\n *\n * ```\n * import { updateFragments } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(updateFragments, (state, action) => {\n * // Update the slice using the latest and greatest.\n * return action.value\n * ```\n */\nexport const updateFragments = createAction<{\n name: string\n path: Keypath\n pageKey: PageKey\n value: JSONMappable\n previousValue?: JSONMappable\n}>('@@superglue/UPDATE_FRAGMENTS')\n\n/**\n * A redux action you can dispatch to copy a page from one pageKey to another. Its\n * a very useful way to create optimistic updates with a URL change. For example:\n *\n * ```\n * import { copyPage, remote } from '@thoughtbot/superglue'\n *\n * dispatch(copyPage({ from: originalKey, to: targetKey}))\n *\n * ... make edits to target page and finally\n *\n * navigateTo(targetKey)\n * ```\n */\nexport const copyPage = createAction<{ from: PageKey; to: PageKey }>(\n '@@superglue/COPY_PAGE'\n)\n\n/**\n * A redux action you can dispatch to remove a page from your store.\n *\n * ```\n * import { removePage } from '@thoughtbot/superglue'\n *\n * dispatch(removePage({ pageKey: '/delete_me_please\"}))\n * ```\n */\nexport const removePage = createAction<{ pageKey: PageKey }>(\n '@@superglue/REMOVE_PAGE'\n)\n\n/**\n * A redux action called before a `fetch` takes place. It will fire in `remote`\n * and `visit`. You can hook into this event in your redux slices like this:\n *\n * ```\n * import { beforeFetch } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeFetch, (state, action) => {\n * ```\n */\nexport const beforeFetch = createAction<{ fetchArgs: FetchArgs }>(\n '@@superglue/BEFORE_FETCH'\n)\n\n/**\n * A redux action called before a `visit` takes place. You can hook into this event\n * in your redux slices like this:\n *\n * ```\n * import { beforeVisit } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeVisit, (state, action) => {\n * ```\n */\nexport const beforeVisit = createAction<{\n currentPageKey: PageKey\n fetchArgs: FetchArgs\n}>('@@superglue/BEFORE_VISIT')\n\n/**\n * A redux action called before `remote` takes place. You can hook into this event\n * in your redux slices like this:\n *\n * ```\n * import { beforeRemote } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeRemote, (state, action) => {\n * ```\n */\nexport const beforeRemote = createAction<{\n currentPageKey: PageKey\n fetchArgs: FetchArgs\n}>('@@superglue/BEFORE_REMOTE')\n\nexport const setCSRFToken = createAction<{\n csrfToken: string | undefined\n}>('@@superglue/SET_CSRF_TOKEN')\n\nexport const historyChange = createAction<{\n pageKey: PageKey\n}>('@@superglue/HISTORY_CHANGE')\n\nexport const setActivePage = createAction<{\n pageKey: PageKey\n}>('@@superglue/SET_ACTIVE_PAGE')\n","import {\n argsForFetch,\n parseResponse,\n needsRefresh,\n urlToPageKey,\n withoutBusters,\n hasPropsAt,\n propsAtParam,\n removePropsAt,\n} from '../utils'\nimport {\n beforeFetch,\n beforeVisit,\n beforeRemote,\n copyPage,\n superglueError,\n} from '../actions'\nimport { saveAndProcessPage } from './index'\nimport {\n FetchArgs,\n VisitResponse,\n PageResponse,\n Page,\n SuperglueState,\n Meta,\n Dispatch,\n RemoteCreator,\n VisitCreator,\n NavigationAction,\n VisitMeta,\n} from '../types'\n\nfunction handleFetchErr(\n err: Error,\n fetchArgs: FetchArgs,\n dispatch: Dispatch\n): never {\n dispatch(superglueError({ message: err.message }))\n throw err\n}\n\nfunction buildMeta(\n pageKey: string,\n page: VisitResponse,\n state: SuperglueState,\n rsp: Response,\n fetchArgs: FetchArgs\n): Meta {\n const { assets: prevAssets } = state\n const { assets: nextAssets } = page\n\n return {\n pageKey,\n page,\n redirected: rsp.redirected,\n rsp,\n fetchArgs,\n componentIdentifier: page.componentIdentifier,\n needsRefresh: needsRefresh(prevAssets, nextAssets),\n }\n}\n\nexport class MismatchedComponentError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MismatchedComponentError'\n }\n}\n\nexport const remote: RemoteCreator = (\n path,\n {\n pageKey: targetPageKey,\n force = false,\n beforeSave = (prevPage: Page, receivedPage: PageResponse) => receivedPage,\n ...rest\n } = {}\n) => {\n path = withoutBusters(path)\n targetPageKey = targetPageKey && urlToPageKey(targetPageKey)\n\n return (dispatch, getState) => {\n const fetchArgs = argsForFetch(getState, path, rest)\n const currentPageKey = getState().superglue.currentPageKey\n\n dispatch(beforeRemote({ currentPageKey, fetchArgs }))\n dispatch(beforeFetch({ fetchArgs }))\n\n return fetch(...fetchArgs)\n .then(parseResponse)\n .then(({ rsp, json }) => {\n const { superglue, pages = {} } = getState()\n\n let pageKey\n if (targetPageKey === undefined) {\n const isGet = fetchArgs[1].method === 'GET'\n pageKey = calculatePageKey(rsp, isGet, currentPageKey)\n } else {\n pageKey = targetPageKey\n }\n\n const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs)\n\n const existingId = pages[pageKey]?.componentIdentifier\n const receivedId = json.componentIdentifier\n if (!!existingId && existingId != receivedId && !force) {\n const message = `You cannot replace or update an existing page\nlocated at pages[\"${currentPageKey}\"] that has a componentIdentifier\nof \"${existingId}\" with the contents of a page response that has a\ncomponentIdentifier of \"${receivedId}\".\n\nThis can happen if you're using data-sg-remote or remote but your\nresponse redirected to a page with a different componentIdentifier\nthan the target page. \n\nThis limitation exists because the resulting page shape from grafting\n\"${receivedId}\"'s \"${propsAtParam(path)}\" into \"${existingId}\" may not be\ncompatible with the page component associated with \"${existingId}\".\n\nConsider using data-sg-visit, the visit function, or redirect_back to\nthe same page. Or if you're sure you want to proceed, use force: true.\n `\n throw new MismatchedComponentError(message)\n }\n\n const page = beforeSave(pages[pageKey], json)\n return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta)\n })\n .catch((e) => handleFetchErr(e, fetchArgs, dispatch))\n }\n}\n\nlet lastVisitController = {\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n abort: (_reason: string) => {\n // noop\n },\n}\n\nexport const visit: VisitCreator = (\n path,\n {\n placeholderKey,\n beforeSave = (prevPage: Page, receivedPage: PageResponse) => receivedPage,\n revisit = false,\n ...rest\n } = {}\n) => {\n path = withoutBusters(path)\n\n return (dispatch, getState) => {\n const currentPageKey = getState().superglue.currentPageKey\n placeholderKey =\n (placeholderKey && urlToPageKey(placeholderKey)) || currentPageKey\n const hasPlaceholder = placeholderKey in getState().pages\n\n if (hasPropsAt(path) && !hasPlaceholder) {\n console.warn(\n `Could not find placeholder with key ${placeholderKey} in state. The props_at param will be ignored`\n )\n path = removePropsAt(path)\n }\n\n const controller = new AbortController()\n const { signal } = controller\n const fetchArgs = argsForFetch(getState, path, {\n ...rest,\n signal,\n })\n\n dispatch(beforeVisit({ currentPageKey, fetchArgs }))\n dispatch(beforeFetch({ fetchArgs }))\n\n lastVisitController.abort(\n 'Aborting the previous `visit`. There can be one visit at a time. Use `remote` if there is a need for async requests.'\n )\n lastVisitController = controller\n\n return fetch(...fetchArgs)\n .then(parseResponse)\n .then(({ rsp, json }) => {\n const { superglue, pages = {} } = getState()\n const isGet = fetchArgs[1].method === 'GET'\n const pageKey = calculatePageKey(rsp, isGet, currentPageKey)\n if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {\n const existingId = pages[placeholderKey]?.componentIdentifier\n const receivedId = json.componentIdentifier\n if (!!existingId && existingId != receivedId) {\n const message = `You received a page response with a\ncomponentIdentifier \"${receivedId}\" that is different than the\ncomponentIdentifier \"${existingId}\" located at ${placeholderKey}.\n\nThis can happen if you're using data-sg-visit or visit with a\nprops_at param, but the response redirected to a page with a\ndifferent componentIdentifier than the target page. \n\nThis limitation exists because the resulting page shape from grafting\n\"${receivedId}\"'s \"${propsAtParam(path)}\" into \"${existingId}\" may not be\ncompatible with the page component associated with \"${existingId}\".\n\nCheck that you're rendering a page with a matching\ncomponentIdentifier, or consider using redirect_back_with_props_at\nto the same page.\n `\n throw new MismatchedComponentError(message)\n }\n dispatch(copyPage({ from: placeholderKey, to: pageKey }))\n }\n\n const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs)\n\n const visitMeta: VisitMeta = {\n ...meta,\n navigationAction: calculateNavAction(\n meta,\n rsp,\n isGet,\n pageKey,\n currentPageKey,\n revisit\n ),\n }\n\n const page = beforeSave(pages[pageKey], json)\n return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta)\n })\n .catch((e) => handleFetchErr(e, fetchArgs, dispatch))\n }\n}\n\nfunction calculateNavAction(\n meta: Meta,\n rsp: Response,\n isGet: boolean,\n pageKey: string,\n currentPageKey: string,\n revisit: boolean\n) {\n let navigationAction: NavigationAction = 'push'\n if (!rsp.redirected && !isGet) {\n navigationAction = 'replace'\n }\n const isSamePage = pageKey == currentPageKey\n if (isSamePage) {\n navigationAction = 'none'\n }\n if (revisit && isGet) {\n if (rsp.redirected) {\n navigationAction = 'replace'\n } else {\n navigationAction = 'none'\n }\n }\n\n return navigationAction\n}\n\nfunction calculatePageKey(\n rsp: Response,\n isGet: boolean,\n currentPageKey: string\n) {\n let pageKey = urlToPageKey(rsp.url)\n if (!isGet && !rsp.redirected) {\n pageKey = currentPageKey\n }\n\n const contentLocation = rsp.headers.get('content-location')\n if (contentLocation) {\n pageKey = urlToPageKey(contentLocation)\n }\n return pageKey\n}\n"],"mappings":"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","names":["parse","pathQuery","parse","visit","remote","parse","parse"]}
|
|
@@ -30,11 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// lib/action_creators/index.ts
|
|
31
31
|
var action_creators_exports = {};
|
|
32
32
|
__export(action_creators_exports, {
|
|
33
|
-
|
|
34
|
-
handleGraft: () => handleGraft,
|
|
33
|
+
MismatchedComponentError: () => MismatchedComponentError,
|
|
35
34
|
remote: () => remote,
|
|
36
35
|
saveAndProcessPage: () => saveAndProcessPage,
|
|
37
|
-
saveResponse: () => saveResponse,
|
|
38
36
|
visit: () => visit
|
|
39
37
|
});
|
|
40
38
|
module.exports = __toCommonJS(action_creators_exports);
|
|
@@ -50,6 +48,11 @@ function hasPropsAt(url) {
|
|
|
50
48
|
const query = parsed.query;
|
|
51
49
|
return !!query["props_at"];
|
|
52
50
|
}
|
|
51
|
+
function propsAtParam(url) {
|
|
52
|
+
const parsed = new import_url_parse.default(url, {}, true);
|
|
53
|
+
const query = parsed.query;
|
|
54
|
+
return query["props_at"];
|
|
55
|
+
}
|
|
53
56
|
function withFormatJson(url) {
|
|
54
57
|
const parsed = new import_url_parse.default(url, {}, true);
|
|
55
58
|
parsed.query["format"] = "json";
|
|
@@ -209,7 +212,7 @@ function validateResponse(args) {
|
|
|
209
212
|
}
|
|
210
213
|
function handleServerErrors(args) {
|
|
211
214
|
const { rsp } = args;
|
|
212
|
-
if (!rsp.ok) {
|
|
215
|
+
if (!rsp.ok && rsp.status !== 422) {
|
|
213
216
|
if (rsp.status === 406) {
|
|
214
217
|
console.error(
|
|
215
218
|
"Superglue encountered a 406 Not Acceptable response. This can happen if you used respond_to and didn't specify format.json in the block. Try adding it to your respond_to. For example:\n\nrespond_to do |format|\n format.html\n format.json\n format.csv\nend"
|
|
@@ -221,7 +224,13 @@ function handleServerErrors(args) {
|
|
|
221
224
|
}
|
|
222
225
|
return args;
|
|
223
226
|
}
|
|
224
|
-
function argsForFetch(getState, pathQuery2, {
|
|
227
|
+
function argsForFetch(getState, pathQuery2, {
|
|
228
|
+
method = "GET",
|
|
229
|
+
headers = {},
|
|
230
|
+
body = "",
|
|
231
|
+
signal,
|
|
232
|
+
...rest
|
|
233
|
+
} = {}) {
|
|
225
234
|
method = method.toUpperCase();
|
|
226
235
|
const currentState = getState().superglue;
|
|
227
236
|
const nextHeaders = { ...headers };
|
|
@@ -272,7 +281,7 @@ function argsForFetch(getState, pathQuery2, { method = "GET", headers = {}, body
|
|
|
272
281
|
}
|
|
273
282
|
delete options.body;
|
|
274
283
|
}
|
|
275
|
-
return [fetchPath.toString(), options];
|
|
284
|
+
return [fetchPath.toString(), { ...options, ...rest }];
|
|
276
285
|
}
|
|
277
286
|
function extractJSON(rsp) {
|
|
278
287
|
return rsp.json().then((json) => {
|
|
@@ -300,46 +309,55 @@ function needsRefresh(prevAssets, newAssets) {
|
|
|
300
309
|
var import_url_parse3 = __toESM(require("url-parse"));
|
|
301
310
|
|
|
302
311
|
// lib/actions.ts
|
|
303
|
-
var
|
|
304
|
-
var BEFORE_VISIT = "@@superglue/BEFORE_VISIT";
|
|
305
|
-
var BEFORE_REMOTE = "@@superglue/BEFORE_REMOTE";
|
|
306
|
-
var SAVE_RESPONSE = "@@superglue/SAVE_RESPONSE";
|
|
307
|
-
var HANDLE_GRAFT = "@@superglue/HANDLE_GRAFT";
|
|
308
|
-
var SUPERGLUE_ERROR = "@@superglue/ERROR";
|
|
312
|
+
var import_toolkit = require("@reduxjs/toolkit");
|
|
309
313
|
var GRAFTING_ERROR = "@@superglue/GRAFTING_ERROR";
|
|
310
314
|
var GRAFTING_SUCCESS = "@@superglue/GRAFTING_SUCCESS";
|
|
311
|
-
var
|
|
312
|
-
|
|
315
|
+
var saveResponse = (0, import_toolkit.createAction)(
|
|
316
|
+
"@@superglue/SAVE_RESPONSE",
|
|
317
|
+
({ pageKey, page }) => {
|
|
318
|
+
pageKey = urlToPageKey(pageKey);
|
|
319
|
+
return {
|
|
320
|
+
payload: {
|
|
321
|
+
pageKey,
|
|
322
|
+
page
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
var handleGraft = (0, import_toolkit.createAction)(
|
|
328
|
+
"@@superglue/HANDLE_GRAFT",
|
|
329
|
+
({ pageKey, page }) => {
|
|
330
|
+
pageKey = urlToPageKey(pageKey);
|
|
331
|
+
return {
|
|
332
|
+
payload: {
|
|
333
|
+
page,
|
|
334
|
+
pageKey
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
var superglueError = (0, import_toolkit.createAction)(
|
|
340
|
+
"@@superglue/ERROR"
|
|
341
|
+
);
|
|
342
|
+
var updateFragments = (0, import_toolkit.createAction)("@@superglue/UPDATE_FRAGMENTS");
|
|
343
|
+
var copyPage = (0, import_toolkit.createAction)(
|
|
344
|
+
"@@superglue/COPY_PAGE"
|
|
345
|
+
);
|
|
346
|
+
var removePage = (0, import_toolkit.createAction)(
|
|
347
|
+
"@@superglue/REMOVE_PAGE"
|
|
348
|
+
);
|
|
349
|
+
var beforeFetch = (0, import_toolkit.createAction)(
|
|
350
|
+
"@@superglue/BEFORE_FETCH"
|
|
351
|
+
);
|
|
352
|
+
var beforeVisit = (0, import_toolkit.createAction)("@@superglue/BEFORE_VISIT");
|
|
353
|
+
var beforeRemote = (0, import_toolkit.createAction)("@@superglue/BEFORE_REMOTE");
|
|
354
|
+
var setCSRFToken = (0, import_toolkit.createAction)("@@superglue/SET_CSRF_TOKEN");
|
|
355
|
+
var historyChange = (0, import_toolkit.createAction)("@@superglue/HISTORY_CHANGE");
|
|
356
|
+
var setActivePage = (0, import_toolkit.createAction)("@@superglue/SET_ACTIVE_PAGE");
|
|
313
357
|
|
|
314
358
|
// lib/action_creators/requests.ts
|
|
315
|
-
function beforeVisit(payload) {
|
|
316
|
-
return {
|
|
317
|
-
type: BEFORE_VISIT,
|
|
318
|
-
payload
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
function beforeRemote(payload) {
|
|
322
|
-
return {
|
|
323
|
-
type: BEFORE_REMOTE,
|
|
324
|
-
payload
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
function beforeFetch(payload) {
|
|
328
|
-
return {
|
|
329
|
-
type: BEFORE_FETCH,
|
|
330
|
-
payload
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
function handleError(err) {
|
|
334
|
-
return {
|
|
335
|
-
type: SUPERGLUE_ERROR,
|
|
336
|
-
payload: {
|
|
337
|
-
message: err.message
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
359
|
function handleFetchErr(err, fetchArgs, dispatch) {
|
|
342
|
-
dispatch(
|
|
360
|
+
dispatch(superglueError({ message: err.message }));
|
|
343
361
|
throw err;
|
|
344
362
|
}
|
|
345
363
|
function buildMeta(pageKey, page, state, rsp, fetchArgs) {
|
|
@@ -355,47 +373,55 @@ function buildMeta(pageKey, page, state, rsp, fetchArgs) {
|
|
|
355
373
|
needsRefresh: needsRefresh(prevAssets, nextAssets)
|
|
356
374
|
};
|
|
357
375
|
}
|
|
376
|
+
var MismatchedComponentError = class extends Error {
|
|
377
|
+
constructor(message) {
|
|
378
|
+
super(message);
|
|
379
|
+
this.name = "MismatchedComponentError";
|
|
380
|
+
}
|
|
381
|
+
};
|
|
358
382
|
var remote = (path, {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
beforeSave = (prevPage, receivedPage) => receivedPage
|
|
383
|
+
pageKey: targetPageKey,
|
|
384
|
+
force = false,
|
|
385
|
+
beforeSave = (prevPage, receivedPage) => receivedPage,
|
|
386
|
+
...rest
|
|
364
387
|
} = {}) => {
|
|
365
388
|
path = withoutBusters(path);
|
|
366
|
-
|
|
389
|
+
targetPageKey = targetPageKey && urlToPageKey(targetPageKey);
|
|
367
390
|
return (dispatch, getState) => {
|
|
368
|
-
const fetchArgs = argsForFetch(getState, path,
|
|
369
|
-
method,
|
|
370
|
-
headers,
|
|
371
|
-
body
|
|
372
|
-
});
|
|
373
|
-
if (rawPageKey === void 0) {
|
|
374
|
-
rawPageKey = getState().superglue.currentPageKey;
|
|
375
|
-
}
|
|
376
|
-
const pageKey = rawPageKey;
|
|
391
|
+
const fetchArgs = argsForFetch(getState, path, rest);
|
|
377
392
|
const currentPageKey = getState().superglue.currentPageKey;
|
|
378
393
|
dispatch(beforeRemote({ currentPageKey, fetchArgs }));
|
|
379
394
|
dispatch(beforeFetch({ fetchArgs }));
|
|
380
395
|
return fetch(...fetchArgs).then(parseResponse).then(({ rsp, json }) => {
|
|
381
396
|
const { superglue, pages = {} } = getState();
|
|
397
|
+
let pageKey;
|
|
398
|
+
if (targetPageKey === void 0) {
|
|
399
|
+
const isGet = fetchArgs[1].method === "GET";
|
|
400
|
+
pageKey = calculatePageKey(rsp, isGet, currentPageKey);
|
|
401
|
+
} else {
|
|
402
|
+
pageKey = targetPageKey;
|
|
403
|
+
}
|
|
382
404
|
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
383
|
-
const
|
|
384
|
-
const existingId = pages[currentPageKey]?.componentIdentifier;
|
|
405
|
+
const existingId = pages[pageKey]?.componentIdentifier;
|
|
385
406
|
const receivedId = json.componentIdentifier;
|
|
386
|
-
if (
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
407
|
+
if (!!existingId && existingId != receivedId && !force) {
|
|
408
|
+
const message = `You cannot replace or update an existing page
|
|
409
|
+
located at pages["${currentPageKey}"] that has a componentIdentifier
|
|
410
|
+
of "${existingId}" with the contents of a page response that has a
|
|
411
|
+
componentIdentifier of "${receivedId}".
|
|
391
412
|
|
|
392
|
-
This can happen if you're using data-sg-remote or remote but your
|
|
393
|
-
redirected to a
|
|
394
|
-
|
|
395
|
-
receive a shape that is unexpected and cause issues with rendering.
|
|
413
|
+
This can happen if you're using data-sg-remote or remote but your
|
|
414
|
+
response redirected to a page with a different componentIdentifier
|
|
415
|
+
than the target page.
|
|
396
416
|
|
|
397
|
-
|
|
398
|
-
|
|
417
|
+
This limitation exists because the resulting page shape from grafting
|
|
418
|
+
"${receivedId}"'s "${propsAtParam(path)}" into "${existingId}" may not be
|
|
419
|
+
compatible with the page component associated with "${existingId}".
|
|
420
|
+
|
|
421
|
+
Consider using data-sg-visit, the visit function, or redirect_back to
|
|
422
|
+
the same page. Or if you're sure you want to proceed, use force: true.
|
|
423
|
+
`;
|
|
424
|
+
throw new MismatchedComponentError(message);
|
|
399
425
|
}
|
|
400
426
|
const page = beforeSave(pages[pageKey], json);
|
|
401
427
|
return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta);
|
|
@@ -403,121 +429,115 @@ Consider using data-sg-visit, the visit function, or redirect_back.`
|
|
|
403
429
|
};
|
|
404
430
|
};
|
|
405
431
|
var lastVisitController = {
|
|
406
|
-
|
|
432
|
+
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
|
|
433
|
+
abort: (_reason) => {
|
|
407
434
|
}
|
|
408
435
|
};
|
|
409
436
|
var visit = (path, {
|
|
410
|
-
method = "GET",
|
|
411
|
-
headers,
|
|
412
|
-
body,
|
|
413
437
|
placeholderKey,
|
|
414
438
|
beforeSave = (prevPage, receivedPage) => receivedPage,
|
|
415
|
-
revisit = false
|
|
439
|
+
revisit = false,
|
|
440
|
+
...rest
|
|
416
441
|
} = {}) => {
|
|
417
442
|
path = withoutBusters(path);
|
|
418
|
-
let pageKey = urlToPageKey(path);
|
|
419
443
|
return (dispatch, getState) => {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
}
|
|
425
|
-
if (placeholderKey && !hasPlaceholder) {
|
|
444
|
+
const currentPageKey = getState().superglue.currentPageKey;
|
|
445
|
+
placeholderKey = placeholderKey && urlToPageKey(placeholderKey) || currentPageKey;
|
|
446
|
+
const hasPlaceholder = placeholderKey in getState().pages;
|
|
447
|
+
if (hasPropsAt(path) && !hasPlaceholder) {
|
|
426
448
|
console.warn(
|
|
427
449
|
`Could not find placeholder with key ${placeholderKey} in state. The props_at param will be ignored`
|
|
428
450
|
);
|
|
429
451
|
path = removePropsAt(path);
|
|
430
452
|
}
|
|
431
|
-
if (!placeholderKey && hasPropsAt(path)) {
|
|
432
|
-
console.warn(
|
|
433
|
-
`visit was called with props_at param in the path ${path}, this will be ignore unless you provide a placeholder.`
|
|
434
|
-
);
|
|
435
|
-
path = removePropsAt(path);
|
|
436
|
-
}
|
|
437
453
|
const controller = new AbortController();
|
|
438
454
|
const { signal } = controller;
|
|
439
455
|
const fetchArgs = argsForFetch(getState, path, {
|
|
440
|
-
|
|
441
|
-
body,
|
|
442
|
-
method,
|
|
456
|
+
...rest,
|
|
443
457
|
signal
|
|
444
458
|
});
|
|
445
|
-
const currentPageKey = getState().superglue.currentPageKey;
|
|
446
459
|
dispatch(beforeVisit({ currentPageKey, fetchArgs }));
|
|
447
460
|
dispatch(beforeFetch({ fetchArgs }));
|
|
448
|
-
lastVisitController.abort(
|
|
461
|
+
lastVisitController.abort(
|
|
462
|
+
"Aborting the previous `visit`. There can be one visit at a time. Use `remote` if there is a need for async requests."
|
|
463
|
+
);
|
|
449
464
|
lastVisitController = controller;
|
|
450
465
|
return fetch(...fetchArgs).then(parseResponse).then(({ rsp, json }) => {
|
|
451
466
|
const { superglue, pages = {} } = getState();
|
|
452
|
-
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
453
467
|
const isGet = fetchArgs[1].method === "GET";
|
|
454
|
-
|
|
455
|
-
if (
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
468
|
+
const pageKey = calculatePageKey(rsp, isGet, currentPageKey);
|
|
469
|
+
if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {
|
|
470
|
+
const existingId = pages[placeholderKey]?.componentIdentifier;
|
|
471
|
+
const receivedId = json.componentIdentifier;
|
|
472
|
+
if (!!existingId && existingId != receivedId) {
|
|
473
|
+
const message = `You received a page response with a
|
|
474
|
+
componentIdentifier "${receivedId}" that is different than the
|
|
475
|
+
componentIdentifier "${existingId}" located at ${placeholderKey}.
|
|
476
|
+
|
|
477
|
+
This can happen if you're using data-sg-visit or visit with a
|
|
478
|
+
props_at param, but the response redirected to a page with a
|
|
479
|
+
different componentIdentifier than the target page.
|
|
480
|
+
|
|
481
|
+
This limitation exists because the resulting page shape from grafting
|
|
482
|
+
"${receivedId}"'s "${propsAtParam(path)}" into "${existingId}" may not be
|
|
483
|
+
compatible with the page component associated with "${existingId}".
|
|
484
|
+
|
|
485
|
+
Check that you're rendering a page with a matching
|
|
486
|
+
componentIdentifier, or consider using redirect_back_with_props_at
|
|
487
|
+
to the same page.
|
|
488
|
+
`;
|
|
489
|
+
throw new MismatchedComponentError(message);
|
|
463
490
|
}
|
|
491
|
+
dispatch(copyPage({ from: placeholderKey, to: pageKey }));
|
|
464
492
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
493
|
+
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
494
|
+
const visitMeta = {
|
|
495
|
+
...meta,
|
|
496
|
+
navigationAction: calculateNavAction(
|
|
497
|
+
meta,
|
|
498
|
+
rsp,
|
|
499
|
+
isGet,
|
|
500
|
+
pageKey,
|
|
501
|
+
currentPageKey,
|
|
502
|
+
revisit
|
|
503
|
+
)
|
|
504
|
+
};
|
|
473
505
|
const page = beforeSave(pages[pageKey], json);
|
|
474
|
-
return dispatch(saveAndProcessPage(pageKey, page)).then(() =>
|
|
475
|
-
meta.pageKey = pageKey;
|
|
476
|
-
return meta;
|
|
477
|
-
});
|
|
506
|
+
return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta);
|
|
478
507
|
}).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
|
|
479
508
|
};
|
|
480
509
|
};
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
function saveResponse({
|
|
496
|
-
pageKey,
|
|
497
|
-
page
|
|
498
|
-
}) {
|
|
499
|
-
pageKey = urlToPageKey(pageKey);
|
|
500
|
-
return {
|
|
501
|
-
type: SAVE_RESPONSE,
|
|
502
|
-
payload: {
|
|
503
|
-
pageKey,
|
|
504
|
-
page
|
|
510
|
+
function calculateNavAction(meta, rsp, isGet, pageKey, currentPageKey, revisit) {
|
|
511
|
+
let navigationAction = "push";
|
|
512
|
+
if (!rsp.redirected && !isGet) {
|
|
513
|
+
navigationAction = "replace";
|
|
514
|
+
}
|
|
515
|
+
const isSamePage = pageKey == currentPageKey;
|
|
516
|
+
if (isSamePage) {
|
|
517
|
+
navigationAction = "none";
|
|
518
|
+
}
|
|
519
|
+
if (revisit && isGet) {
|
|
520
|
+
if (rsp.redirected) {
|
|
521
|
+
navigationAction = "replace";
|
|
522
|
+
} else {
|
|
523
|
+
navigationAction = "none";
|
|
505
524
|
}
|
|
506
|
-
}
|
|
525
|
+
}
|
|
526
|
+
return navigationAction;
|
|
507
527
|
}
|
|
508
|
-
function
|
|
509
|
-
pageKey
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
};
|
|
528
|
+
function calculatePageKey(rsp, isGet, currentPageKey) {
|
|
529
|
+
let pageKey = urlToPageKey(rsp.url);
|
|
530
|
+
if (!isGet && !rsp.redirected) {
|
|
531
|
+
pageKey = currentPageKey;
|
|
532
|
+
}
|
|
533
|
+
const contentLocation = rsp.headers.get("content-location");
|
|
534
|
+
if (contentLocation) {
|
|
535
|
+
pageKey = urlToPageKey(contentLocation);
|
|
536
|
+
}
|
|
537
|
+
return pageKey;
|
|
520
538
|
}
|
|
539
|
+
|
|
540
|
+
// lib/action_creators/index.ts
|
|
521
541
|
function fetchDeferments(pageKey, defers = []) {
|
|
522
542
|
pageKey = urlToPageKey(pageKey);
|
|
523
543
|
return (dispatch) => {
|
|
@@ -551,35 +571,60 @@ function fetchDeferments(pageKey, defers = []) {
|
|
|
551
571
|
return Promise.all(fetches);
|
|
552
572
|
};
|
|
553
573
|
}
|
|
554
|
-
function updateFragmentsUsing(page) {
|
|
555
|
-
const changedFragments = {};
|
|
556
|
-
page.fragments.forEach((fragment) => {
|
|
557
|
-
const { type, path } = fragment;
|
|
558
|
-
changedFragments[type] = getIn(page, path);
|
|
559
|
-
});
|
|
560
|
-
return {
|
|
561
|
-
type: UPDATE_FRAGMENTS,
|
|
562
|
-
payload: { changedFragments }
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
574
|
function saveAndProcessPage(pageKey, page) {
|
|
566
575
|
return (dispatch, getState) => {
|
|
567
576
|
pageKey = urlToPageKey(pageKey);
|
|
568
577
|
const { defers = [] } = page;
|
|
569
578
|
if ("action" in page) {
|
|
579
|
+
const prevPage = getState().pages[pageKey];
|
|
570
580
|
dispatch(handleGraft({ pageKey, page }));
|
|
581
|
+
const currentPage = getState().pages[pageKey];
|
|
582
|
+
currentPage.fragments.forEach((fragment) => {
|
|
583
|
+
const { type, path } = fragment;
|
|
584
|
+
const currentFragment = getIn(currentPage, path);
|
|
585
|
+
const prevFragment = getIn(prevPage, path);
|
|
586
|
+
if (!prevFragment) {
|
|
587
|
+
dispatch(
|
|
588
|
+
updateFragments({
|
|
589
|
+
name: type,
|
|
590
|
+
pageKey,
|
|
591
|
+
value: currentFragment,
|
|
592
|
+
path
|
|
593
|
+
})
|
|
594
|
+
);
|
|
595
|
+
} else if (currentFragment !== prevFragment) {
|
|
596
|
+
dispatch(
|
|
597
|
+
updateFragments({
|
|
598
|
+
name: type,
|
|
599
|
+
pageKey,
|
|
600
|
+
value: currentFragment,
|
|
601
|
+
previousValue: prevFragment,
|
|
602
|
+
path
|
|
603
|
+
})
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
571
607
|
} else {
|
|
572
608
|
dispatch(saveResponse({ pageKey, page }));
|
|
609
|
+
const currentPage = getState().pages[pageKey];
|
|
610
|
+
currentPage.fragments.forEach((fragment) => {
|
|
611
|
+
const { type, path } = fragment;
|
|
612
|
+
const currentFragment = getIn(currentPage, path);
|
|
613
|
+
dispatch(
|
|
614
|
+
updateFragments({
|
|
615
|
+
name: type,
|
|
616
|
+
pageKey,
|
|
617
|
+
value: currentFragment,
|
|
618
|
+
path
|
|
619
|
+
})
|
|
620
|
+
);
|
|
621
|
+
});
|
|
573
622
|
}
|
|
574
623
|
const hasFetch = typeof fetch != "undefined";
|
|
575
624
|
if (hasFetch) {
|
|
576
|
-
return dispatch(fetchDeferments(pageKey, defers)).then(
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
dispatch(updateFragmentsUsing(finishedPage));
|
|
580
|
-
return Promise.resolve();
|
|
581
|
-
}
|
|
582
|
-
});
|
|
625
|
+
return dispatch(fetchDeferments(pageKey, defers)).then(
|
|
626
|
+
() => Promise.resolve()
|
|
627
|
+
);
|
|
583
628
|
} else {
|
|
584
629
|
return Promise.resolve();
|
|
585
630
|
}
|
|
@@ -587,11 +632,9 @@ function saveAndProcessPage(pageKey, page) {
|
|
|
587
632
|
}
|
|
588
633
|
// Annotate the CommonJS export names for ESM import in node:
|
|
589
634
|
0 && (module.exports = {
|
|
590
|
-
|
|
591
|
-
handleGraft,
|
|
635
|
+
MismatchedComponentError,
|
|
592
636
|
remote,
|
|
593
637
|
saveAndProcessPage,
|
|
594
|
-
saveResponse,
|
|
595
638
|
visit
|
|
596
639
|
});
|
|
597
640
|
//# sourceMappingURL=action_creators.cjs.map
|