Deployment docs need some additional guidance #492
scottdixon
started this conversation in
Ideas + Feature Requests
Replies: 1 comment 10 replies
-
Thank you @scottdixon for bringing this up here. For further context this is the (very unrefined) // Virtual entry point for the app
import * as remixBuild from '@remix-run/dev/server-build';
import {createRequestHandler} from '@remix-run/server-runtime';
import {createStorefrontClient, storefrontRedirect} from '@shopify/hydrogen';
import {HydrogenSession} from '~/lib/session.server';
/**
* Export a fetch handler in module format.
*/
export default async function (request: Request): Promise<Response> {
const env = process.env;
try {
/**
* Open a cache instance in the worker and a custom session instance.
*/
if (!env?.SESSION_SECRET) {
throw new Error('SESSION_SECRET environment variable is not set');
}
const [session] = await Promise.all([
HydrogenSession.init(request, [env.SESSION_SECRET]),
]);
/**
* Create Hydrogen's Storefront client.
*/
const {storefront} = createStorefrontClient({
buyerIp: request.headers.get('x-forwarded-for') ?? undefined,
i18n: {
language: 'DE',
country: 'DE',
},
publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
storeDomain: `https://${env.PUBLIC_STORE_DOMAIN}`,
storefrontApiVersion: env.PUBLIC_STOREFRONT_API_VERSION || '2023-01',
// storefrontId: env.PUBLIC_STOREFRONT_ID,
// requestGroupId: request.headers.get('request-id'),
});
const handleRequest = createRequestHandler(remixBuild as any, 'production');
const response = await handleRequest(request, {
session,
storefront,
env,
waitUntil: () => Promise.resolve(),
});
if (response.status === 404) {
/**
* Check for redirects only when there's a 404 from the app.
* If the redirect doesn't exist, then `storefrontRedirect`
* will pass through the 404 response.
*/
// return storefrontRedirect({request, response, storefront});
}
return response;
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);
return new Response('An unexpected error occurred', {status: 500});
}
} And this is the modified import {
createCookieSessionStorageFactory,
createCookieFactory,
type SessionStorage,
type Session,
} from '@remix-run/server-runtime';
import type {SignFunction, UnsignFunction} from '@remix-run/server-runtime';
const encoder = new TextEncoder();
export const sign: SignFunction = async (value, secret) => {
const data = encoder.encode(value);
const key = await createKey(secret, ['sign']);
const signature = await crypto.subtle.sign('HMAC', key, data);
const hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(
/=+$/,
'',
);
return value + '.' + hash;
};
export const unsign: UnsignFunction = async (cookie, secret) => {
const value = cookie.slice(0, cookie.lastIndexOf('.'));
const hash = cookie.slice(cookie.lastIndexOf('.') + 1);
const data = encoder.encode(value);
const key = await createKey(secret, ['verify']);
const signature = byteStringToUint8Array(atob(hash));
const valid = await crypto.subtle.verify('HMAC', key, signature, data);
return valid ? value : false;
};
async function createKey(
secret: string,
usages: CryptoKey['usages'],
): Promise<CryptoKey> {
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(secret),
{name: 'HMAC', hash: 'SHA-256'},
false,
usages,
);
return key;
}
function byteStringToUint8Array(byteString: string): Uint8Array {
const array = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
array[i] = byteString.charCodeAt(i);
}
return array;
}
/**
* This is a custom session implementation for your Hydrogen shop.
* Feel free to customize it to your needs, add helper methods, or
* swap out the cookie-based implementation with something else!
*/
export class HydrogenSession {
constructor(
private sessionStorage: SessionStorage,
private session: Session,
) {}
static async init(request: Request, secrets: string[]) {
const createCookie = createCookieFactory({sign, unsign});
const createCookieSessionStorage =
createCookieSessionStorageFactory(createCookie);
const storage = createCookieSessionStorage({
cookie: {
name: 'session',
httpOnly: true,
path: '/',
sameSite: 'lax',
secrets,
},
});
const session = await storage.getSession(request.headers.get('Cookie'));
return new this(storage, session);
}
get(key: string) {
return this.session.get(key);
}
destroy() {
return this.sessionStorage.destroySession(this.session);
}
flash(key: string, value: any) {
this.session.flash(key, value);
}
unset(key: string) {
this.session.unset(key);
}
set(key: string, value: any) {
this.session.set(key, value);
}
commit() {
return this.sessionStorage.commitSession(this.session);
}
} Please note that I'm pretty new to Remix, so this is what I came up with last night while trying to digg through the Remix docs and other implementations. I'm very open for suggestions. |
Beta Was this translation helpful? Give feedback.
10 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Flagged by @MurmeltierS in the Partner Slack, Vercel deployment instructions are a little misleading. It would be great to create some more detailed guides for the most common platforms.
cc) @benjaminsehl
Beta Was this translation helpful? Give feedback.
All reactions