Skip to content

Commit a97b3ed

Browse files
committed
feat: implement ObjectStackClient integration and add node polyfills for compatibility
1 parent 29a03e1 commit a97b3ed

4 files changed

Lines changed: 130 additions & 4 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
export class EventEmitter {
2+
on() { return this; }
3+
off() { return this; }
4+
emit() { return true; }
5+
once() { return this; }
6+
addListener() { return this; }
7+
removeListener() { return this; }
8+
removeAllListeners() { return this; }
9+
}
10+
export default { EventEmitter };
11+
12+
export class Stream extends EventEmitter {
13+
pipe() { return this; }
14+
}
15+
export class Readable extends Stream {}
16+
export class Writable extends Stream {}
17+
export class Transform extends Stream {}
18+
19+
export class StringDecoder {
20+
write() { return ''; }
21+
end() { return ''; }
22+
}
23+
24+
export const promises = {
25+
readFile: async () => '',
26+
writeFile: async () => {},
27+
stat: async () => ({ isDirectory: () => false, isFile: () => false }),
28+
mkdir: async () => {},
29+
rm: async () => {},
30+
access: async () => { throw new Error('ENOENT: no such file or directory (polyfill)'); },
31+
};
32+
33+
// os polyfills
34+
export const type = () => 'Browser';
35+
export const platform = () => 'browser';
36+
export const release = () => '1.0.0';
37+
export const tmpdir = () => '/tmp';
38+
export const homedir = () => '/';
39+
export const endianness = () => 'LE';
40+
export const arch = () => 'javascript';
41+
export const EOL = '\n';
42+
43+
export const readFileSync = () => '';
44+
export const writeFileSync = () => {};
45+
export const statSync = () => ({ isDirectory: () => false, isFile: () => false, isSymbolicLink: () => false });
46+
export const lstatSync = () => ({ isDirectory: () => false, isFile: () => false, isSymbolicLink: () => false });
47+
export const existsSync = () => false;
48+
export const join = (...args) => args.join('/');
49+
export const resolve = (...args) => args.join('/');
50+
export const dirname = (path) => path;
51+
export const basename = (path) => path;
52+
export const extname = (path) => '';
53+
export const sep = '/';
54+
export const relative = () => '';
55+
export const isAbsolute = () => false;
56+
export const normalize = (p: string) => p;
57+
58+
export const posix = {};
59+
export const win32 = {};
60+
61+
// fs/promises and other missing exports
62+
export const open = async () => ({ close: async () => {} });
63+
export class Stats {
64+
isDirectory() { return false; }
65+
isFile() { return false; }
66+
isSymbolicLink() { return false; }
67+
}
68+
export const watchFile = () => {};
69+
export const unwatchFile = () => {};
70+
71+
export const fileURLToPath = () => '';
72+
export const pathToFileURL = () => '';
73+
74+
export const readdir = () => {};
75+
export const readdirSync = () => [];
76+
export const readlink = () => {};
77+
export const readlinkSync = () => '';
78+
export const realpath = async () => '';
79+
export const realpathSync = () => '';
80+
realpathSync.native = () => '';
81+
82+
export const constants = {};
83+
export const lstat = async () => ({ isDirectory: () => false, isFile: () => false, isSymbolicLink: () => false });
84+
export const stat = async () => ({ isDirectory: () => false, isFile: () => false, isSymbolicLink: () => false });
85+
export const access = async () => { throw new Error('ENOENT: no such file or directory (polyfill)'); };
86+
export const accessSync = () => { throw new Error('ENOENT: no such file or directory (polyfill)'); };
87+
export const mkdir = () => {};
88+
export const mkdirSync = () => {};
89+
export const rmdir = () => {};
90+
export const rmdirSync = () => {};
91+
export const unlink = () => {};
92+
export const unlinkSync = () => {};
93+
export const copyFile = () => {};
94+
export const copyFileSync = () => {};
95+
export const createReadStream = () => new Readable();
96+
export const createWriteStream = () => new Writable();
97+
export const watch = () => new EventEmitter();
98+
99+
export const readFile = async () => '';
100+
export const writeFile = async () => {};
101+
export const rename = async () => {};
102+
export const renameSync = () => {};
103+
export const createHash = () => ({ update: () => ({ digest: () => '' }) });
104+
export const randomUUID = () => '00000000-0000-0000-0000-000000000000';

apps/account/src/routes/__root.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

33
import { createRootRoute, Navigate, Outlet, useLocation, useNavigate } from '@tanstack/react-router';
4-
import { useEffect } from 'react';
4+
import { useEffect, useMemo } from 'react';
55
import { ObjectStackProvider } from '@objectstack/client-react';
6+
import { ObjectStackClient } from '@objectstack/client';
67
import { Toaster } from '@/components/ui/toaster';
78
import { SessionProvider, useSession } from '@/hooks/useSession';
89
import { getApiBaseUrl } from '@/lib/config';
@@ -55,9 +56,10 @@ function RequireAuth({ children }: { children: React.ReactNode }) {
5556

5657
function RootComponent() {
5758
const baseUrl = getApiBaseUrl();
59+
const client = useMemo(() => new ObjectStackClient({ baseUrl }), [baseUrl]);
5860

5961
return (
60-
<ObjectStackProvider baseUrl={baseUrl}>
62+
<ObjectStackProvider client={client}>
6163
<SessionProvider>
6264
<RequireAuth>
6365
<Outlet />

apps/account/src/routes/account.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,12 +483,12 @@ function TwoFactorTab() {
483483
// ---------------------------------------------------------------------------
484484

485485
function AccountPage() {
486-
const { user } = useSession();
486+
const { user, logout } = useSession();
487487
const navigate = useNavigate();
488488

489489
const handleSignOut = async () => {
490490
try {
491-
await fetch('/api/v1/auth/sign-out', { method: 'POST', credentials: 'include' });
491+
await logout();
492492
} finally {
493493
navigate({ to: '/login' });
494494
}

apps/account/vite.config.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ export default defineConfig({
1616
'react': path.resolve(__dirname, './node_modules/react'),
1717
'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
1818
'@': path.resolve(__dirname, './src'),
19+
'node:fs/promises': path.resolve(__dirname, './mocks/node-polyfills.ts'),
20+
'node:fs': path.resolve(__dirname, './mocks/node-polyfills.ts'),
21+
'node:events': path.resolve(__dirname, './mocks/node-polyfills.ts'),
22+
'node:stream': path.resolve(__dirname, './mocks/node-polyfills.ts'),
23+
'node:string_decoder': path.resolve(__dirname, './mocks/node-polyfills.ts'),
24+
'node:path': path.resolve(__dirname, './mocks/node-polyfills.ts'),
25+
'node:url': path.resolve(__dirname, './mocks/node-polyfills.ts'),
26+
'node:util': path.resolve(__dirname, './mocks/node-polyfills.ts'),
27+
'node:os': path.resolve(__dirname, './mocks/node-polyfills.ts'),
28+
'node:crypto': path.resolve(__dirname, './mocks/node-polyfills.ts'),
29+
'events': path.resolve(__dirname, './mocks/node-polyfills.ts'),
30+
'stream': path.resolve(__dirname, './mocks/node-polyfills.ts'),
31+
'string_decoder': path.resolve(__dirname, './mocks/node-polyfills.ts'),
32+
'path': path.resolve(__dirname, './mocks/node-polyfills.ts'),
33+
'fs/promises': path.resolve(__dirname, './mocks/node-polyfills.ts'),
34+
'fs': path.resolve(__dirname, './mocks/node-polyfills.ts'),
35+
'util': path.resolve(__dirname, './mocks/node-polyfills.ts'),
36+
'os': path.resolve(__dirname, './mocks/node-polyfills.ts'),
37+
'crypto': path.resolve(__dirname, './mocks/node-polyfills.ts'),
38+
'url': path.resolve(__dirname, './mocks/node-polyfills.ts'),
1939
},
2040
},
2141
define: {

0 commit comments

Comments
 (0)