Files
zeekayandHanzo Dev 6410b85b4d Six bundles target Safari 15, as the other fourteen do
`pnpm build` failed in clio, epic, notion, office, outlook and sketch with
esbuild's "Transforming destructuring to the configured target
environment ("safari14") is not supported yet". esbuild 0.28, the
catalog's version, does not count Safari 14.0 as supporting
destructuring (14.1 passes), and cannot lower it, so a plain
`const { a } = b` stopped the build, in these packages' own code and in
@hanzo/ai and @hanzo/iam.

The other fourteen packages that name a Safari target, the browser
extension among them, already name Safari 15. These six now do too.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-19 09:06:04 -07:00

99 lines
3.5 KiB
JavaScript

// Build the Notion integration into dist/: bundle the SPA (app.ts, browser) and
// the OAuth + proxy service (server.ts, node), copy the static HTML/CSS/assets.
//
// node build.js β†’ production (base https://notion.hanzo.ai)
// HANZO_NOTION_BASE=http://localhost:8788 node build.js β†’ local dev
//
// The Notion public integration's PUBLIC client_id + redirect are stamped into
// the SPA via esbuild `define` (the client_id is public; the SECRET is read from
// the environment by the running server, never bundled). One place, one source.
import esbuild from 'esbuild';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const BASE = (process.env.HANZO_NOTION_BASE || 'https://notion.hanzo.ai').replace(/\/+$/, '');
const NOTION_CLIENT_ID = process.env.NOTION_CLIENT_ID || '';
const NOTION_REDIRECT_URI = process.env.NOTION_REDIRECT_URI || `${BASE}/oauth/callback`;
const watch = process.argv.includes('--watch');
const root = path.dirname(fileURLToPath(import.meta.url));
const src = path.join(root, 'src');
const dist = path.join(root, 'dist');
async function build() {
fs.rmSync(dist, { recursive: true, force: true });
fs.mkdirSync(dist, { recursive: true });
// The browser SPA β€” client_id/redirect stamped via define. Secrets are NOT
// define-able here; server.ts reads NOTION_CLIENT_SECRET from process.env.
const spa = await esbuild.context({
entryPoints: [path.join(src, 'app.ts')],
outfile: path.join(dist, 'app.js'),
bundle: true,
format: 'iife',
platform: 'browser',
target: ['chrome90', 'edge90', 'safari15', 'firefox90'],
sourcemap: true,
minify: !watch,
define: {
NOTION_CLIENT_ID: JSON.stringify(NOTION_CLIENT_ID),
NOTION_REDIRECT_URI: JSON.stringify(NOTION_REDIRECT_URI),
},
logLevel: 'info',
});
await spa.rebuild();
// The OAuth + Notion-proxy service β€” a Node ESM bundle. No secrets baked in;
// it reads NOTION_CLIENT_SECRET etc. from the environment when it runs.
const server = await esbuild.context({
entryPoints: [path.join(src, 'server.ts')],
outfile: path.join(dist, 'server.js'),
bundle: true,
format: 'esm',
platform: 'node',
target: ['node18'],
sourcemap: true,
minify: !watch,
banner: { js: '// Hanzo Notion OAuth + proxy service β€” run: node server.js' },
logLevel: 'info',
});
await server.rebuild();
// Static files.
for (const f of ['index.html', 'styles.css']) {
fs.copyFileSync(path.join(src, f), path.join(dist, f));
}
// assets/ (icons) β€” create the dir even if empty so index.html's <img> resolves.
const assetsSrc = path.join(root, 'assets');
const assetsDst = path.join(dist, 'assets');
fs.mkdirSync(assetsDst, { recursive: true });
if (fs.existsSync(assetsSrc)) {
for (const f of fs.readdirSync(assetsSrc)) {
fs.copyFileSync(path.join(assetsSrc, f), path.join(assetsDst, f));
}
}
console.log(`βœ… Notion integration built β†’ dist/ (base ${BASE})`);
console.log(' Serve dist/{index.html,app.js,styles.css,assets} as static; run dist/server.js for /oauth/* + /notion/* proxy.');
if (!NOTION_CLIENT_ID) {
console.log(' ⚠ NOTION_CLIENT_ID not set β€” set it (and NOTION_CLIENT_SECRET on the server) before deploy.');
}
if (watch) {
await spa.watch();
await server.watch();
console.log('πŸ‘€ watching…');
} else {
await spa.dispose();
await server.dispose();
}
}
build().catch((e) => {
console.error(e);
process.exit(1);
});