@basenative /分享
每个可共享的BaseNative应用都需要三个要素:
- 本地共享+剪贴板回退 对于浏览器。
- Share-card薄荷 -服务器端存储+ POST处理程序 game/post/result变成一个稳定的短URL。
- og重定向登陆页 -面向爬虫的HTML at
/s/{id}所以 iMessage / Discord / Twitter / LinkedIn渲染正确的卡片图像; 而真正的游客则会被js重新引导。
组合在一起 @basenative/og-image 为每股PNG。
安装
pnpm add @basenative/share
# Optional — server-side PNG rendering
pnpm add @basenative/og-image
从浏览器共享客户端
import { nativeShare, mintShareCard, composeShareText } from '@basenative/share/client';
const { id, url } = await mintShareCard({
sessionId, category, score, won, grid,
});
const text = composeShareText(
'T4BS · ${category} · ${score}pts · ${verdict}\n\n${grid}',
{ category, score, verdict: won ? 'Solved' : 'Busted', grid }
);
const result = await nativeShare({ text, url });
// result.status: 'shared' | 'copied' | 'failed'
nativeShare 在可用的情况下使用Web共享API,回落到
navigator.clipboard.writeText 附加URL,并尊重用户
取消(AbortError),所以我们不会通过默默地复制来伏击他们。
服务器铸造+着陆
在 functions/api/share-cards.js:
import { defineShareCards, mintHandler } from '@basenative/share/server';
export const onRequestPost = async (ctx) => {
const store = defineShareCards({ db: ctx.env.DB });
return mintHandler({
store,
validate: (b) => {
if (typeof b.category !== 'string' || !b.category) return 'bad-category';
if (typeof b.score !== 'number') return 'bad-score';
return true;
},
})(ctx);
};
在 functions/s/[id].js:
import { defineShareCards, landingHandler } from '@basenative/share/server';
export const onRequestGet = async (ctx) => {
const store = defineShareCards({ db: ctx.env.DB });
return landingHandler({
store,
ogImage: (_card, { origin, id }) => `${origin}/og/score/${id}.png`,
buildMeta: (card, { origin, id, ogImage }) => ({
title: `T4BS — ${card.won ? 'Solved' : 'Busted'} ${card.category} for ${card.score}pts`,
description: `Five-letter battle of bullshit — ${card.category}.`,
imageUrl: ogImage,
imageAlt: `T4BS score card`,
canonicalUrl: `${origin}/s/${id}`,
siteName: 'T4BS',
themeColor: '#0C0B09',
}),
redirectTo: '/',
})(ctx);
};
应用 migrations/0001_share_cards.sql 要设置 share_cards 表格。
勾搭 @basenative/og-image
在 functions/og/score/[id].png.js:
import { defineShareCards } from '@basenative/share/server';
import { renderPng, defaultTheme } from '@basenative/og-image';
import { scoreCard } from '@basenative/og-image/presets';
export const onRequestGet = async ({ env, params }) => {
const store = defineShareCards({ db: env.DB });
const card = await store.get(params.id);
if (!card) return new Response('not found', { status: 404 });
const png = await renderPng(scoreCard({
category: card.category,
score: card.score,
won: !!card.won,
grid: card.grid,
theme: defaultTheme,
}));
return new Response(png, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 'public, max-age=31536000, immutable',
},
});
};
这个 landingHandler 引用这个URL,爬虫获取它,然后
预览渲染。
自定义域,自定义根
origin接受字符串或(env) => string.path默认为/s/.idPattern默认为/^[a-z0-9]{4,16}$/i.validate允许您内联拒绝格式错误的薄荷请求。
链接
- 碱性单氧- https://github.com/DuganLabs/basenative
- 问题- - - - - - https://github.com/DuganLabs/basenative/issues
- 文档- https://github.com/DuganLabs/basenative#readme
许可证
apache - 2.0。