@shipfox/client-shell 1.0.0 → 3.0.1
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/assets/apple-touch-icon.png +0 -0
- package/assets/favicon-96x96.png +0 -0
- package/assets/favicon.ico +0 -0
- package/assets/favicon.svg +1 -0
- package/assets/site.webmanifest +22 -0
- package/assets/web-app-manifest-192x192.png +0 -0
- package/assets/web-app-manifest-512x512.png +0 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +1 -0
- package/dist/vite/index.js.map +1 -1
- package/dist/vite/manifest.d.ts +3 -0
- package/dist/vite/manifest.d.ts.map +1 -0
- package/dist/vite/manifest.js +140 -0
- package/dist/vite/manifest.js.map +1 -0
- package/package.json +15 -9
- package/.turbo/turbo-build.log +0 -2
- package/.turbo/turbo-type$colon$emit.log +0 -1
- package/.turbo/turbo-type.log +0 -1
- package/CHANGELOG.md +0 -41
- package/src/components/main-layout.tsx +0 -45
- package/src/components/nav-bar.tsx +0 -41
- package/src/components/nav-tabs.test.tsx +0 -60
- package/src/components/nav-tabs.tsx +0 -47
- package/src/components/not-found-page.tsx +0 -14
- package/src/components/settings-nav.tsx +0 -35
- package/src/components/user-menu.tsx +0 -59
- package/src/components/workspace-crumb.tsx +0 -43
- package/src/components/workspace-switcher.tsx +0 -75
- package/src/compose/compose-routes.test.ts +0 -112
- package/src/compose/compose-routes.ts +0 -60
- package/src/compose/errors.ts +0 -54
- package/src/compose/merge-config.test.ts +0 -26
- package/src/compose/merge-config.ts +0 -27
- package/src/compose/normalize-route-path.ts +0 -6
- package/src/compose/validate-providers.test.ts +0 -31
- package/src/compose/validate-providers.ts +0 -36
- package/src/compose/validate-registries.test.ts +0 -92
- package/src/compose/validate-registries.ts +0 -61
- package/src/config/config-screen.test.tsx +0 -37
- package/src/config/shell-config.ts +0 -10
- package/src/contract.ts +0 -47
- package/src/index.ts +0 -1
- package/src/runtime/active-workspace.ts +0 -13
- package/src/runtime/anchor-paths.ts +0 -18
- package/src/runtime/anchors.tsx +0 -106
- package/src/runtime/assemble-route-tree.ts +0 -42
- package/src/runtime/auth.tsx +0 -213
- package/src/runtime/chrome-context.tsx +0 -22
- package/src/runtime/compose-client-app.tsx +0 -122
- package/src/runtime/define-route.test.ts +0 -15
- package/src/runtime/define-route.ts +0 -33
- package/src/runtime/index.ts +0 -19
- package/src/runtime/last-workspace.ts +0 -22
- package/src/runtime/nav-order.ts +0 -1
- package/src/runtime/provider-stack.tsx +0 -39
- package/src/runtime/providers.test.tsx +0 -51
- package/src/runtime/registries.test.tsx +0 -100
- package/src/runtime/registries.ts +0 -42
- package/src/runtime/router-context.ts +0 -9
- package/src/runtime/routes.test.tsx +0 -48
- package/src/runtime/workspace-setup.tsx +0 -61
- package/src/testing/index.test.tsx +0 -57
- package/src/testing/index.tsx +0 -51
- package/src/vite/evaluate-features.test.ts +0 -89
- package/src/vite/evaluate-features.ts +0 -114
- package/src/vite/generate.test.ts +0 -22
- package/src/vite/generate.ts +0 -99
- package/src/vite/generated-router.test.tsx +0 -58
- package/src/vite/index.ts +0 -1
- package/src/vite/plugin.test.ts +0 -231
- package/src/vite/plugin.ts +0 -101
- package/src/vite/validate.test.ts +0 -166
- package/test/default-route-impl.tsx +0 -3
- package/test/external/FINDINGS.md +0 -41
- package/test/external/README.md +0 -37
- package/test/external/fixture/index.html +0 -12
- package/test/external/fixture/package.json +0 -31
- package/test/external/fixture/src/app.fixture.tsx +0 -104
- package/test/external/fixture/src/features/external-settings.tsx +0 -19
- package/test/external/fixture/src/features/login-override.tsx +0 -9
- package/test/external/fixture/src/features.collision.ts +0 -15
- package/test/external/fixture/src/features.ts +0 -50
- package/test/external/fixture/src/link-typecheck.tsx +0 -10
- package/test/external/fixture/src/main.tsx +0 -86
- package/test/external/fixture/src/provider.ts +0 -45
- package/test/external/fixture/tsconfig.json +0 -15
- package/test/external/fixture/vite.config.ts +0 -21
- package/test/external/fixture/vitest.config.ts +0 -17
- package/test/external/verify.mjs +0 -504
- package/test/fixtures/features.ts +0 -56
- package/test/named-route-impl.tsx +0 -3
- package/test/render.tsx +0 -67
- package/test/search-route-impl.tsx +0 -7
- package/test/setup.ts +0 -3
- package/test/typecheck/shipfox-app.gen.ts +0 -85
- package/test/typecheck/types.tsx +0 -23
- package/tsconfig.build.json +0 -10
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -1
- package/tsconfig.test.json +0 -12
- package/vitest.config.ts +0 -22
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# External composition findings
|
|
2
|
-
|
|
3
|
-
The graduated fixture uses the production `@shipfox/client-features` default composition and the
|
|
4
|
-
complete recursive client runtime closure from `publication-closure.json`. The external feature is
|
|
5
|
-
application-local, so route implementations and generated types cross the same package boundary as
|
|
6
|
-
a downstream distribution.
|
|
7
|
-
|
|
8
|
-
## Contract proof
|
|
9
|
-
|
|
10
|
-
The fixture proves that:
|
|
11
|
-
|
|
12
|
-
- every default feature contributes its production routes to the generated application module;
|
|
13
|
-
- an application-local settings route is added and the default login route is explicitly replaced;
|
|
14
|
-
- two application-local providers receive the shell query client and Jotai store, then nest in
|
|
15
|
-
declaration order;
|
|
16
|
-
- application navigation and settings data render through the shell-owned registries;
|
|
17
|
-
- the external config fragment is required, merged, and readable by both providers and the route;
|
|
18
|
-
- the generated router types an application-local `Link` and `useParams` call; and
|
|
19
|
-
- the unapproved login collision fails with the exact normative diagnostic.
|
|
20
|
-
|
|
21
|
-
## Distribution isolation
|
|
22
|
-
|
|
23
|
-
Packed mode builds declarations and runtime files before creating tarballs, then productionizes a
|
|
24
|
-
temporary copy of each package manifest like `release:publish` so source conditions cannot leak into
|
|
25
|
-
the consumer artifact or mutate the worktree. The fixture declares only the documented client
|
|
26
|
-
composition roots, plus `@shipfox/client-config` for its own config proof, while `file:` overrides
|
|
27
|
-
keep every first-party runtime dependency in the full closure on its local tarball. It rejects
|
|
28
|
-
registry-resolved Shipfox packages and `workspace:` ranges across every installed closure package,
|
|
29
|
-
checks that generated package imports are direct fixture dependencies, and confirms full-closure
|
|
30
|
-
runtime imports resolve through `dist` under default and `development` conditions while TypeScript
|
|
31
|
-
checks every packed declaration graph. Linked mode keeps the
|
|
32
|
-
minimal-consumer, generated-route, behavior, collision, and type checks for faster local iteration;
|
|
33
|
-
its workspace packages intentionally resolve `development` to source.
|
|
34
|
-
|
|
35
|
-
## Collision diagnostic
|
|
36
|
-
|
|
37
|
-
The rejected build must return this diagnostic and a non-zero status:
|
|
38
|
-
|
|
39
|
-
```text
|
|
40
|
-
Route "/auth/login" is contributed by both features "shipfox.auth" and "fixture.unapproved-collision". Set override: true to replace it explicitly.
|
|
41
|
-
```
|
package/test/external/README.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# External client runtime fixture
|
|
2
|
-
|
|
3
|
-
This fixture packs the published client runtime closure into a Vite application outside the pnpm
|
|
4
|
-
workspace. The application starts from `defaultFeatures()` and adds one external feature that
|
|
5
|
-
replaces the login route, adds a settings route, appends providers, contributes navigation and
|
|
6
|
-
settings entries, and merges a config fragment.
|
|
7
|
-
|
|
8
|
-
## Run the required packed gate
|
|
9
|
-
|
|
10
|
-
The package script builds runtime files and declarations from a clean checkout before packing the
|
|
11
|
-
full client closure:
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
pnpm --filter=@shipfox/client-shell test:external
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
The gate installs only the nine documented client composition roots, plus
|
|
18
|
-
`@shipfox/client-config` used by the fixture's own config proof, as direct dependencies. It uses
|
|
19
|
-
release-shaped local tarballs and overrides for the full `@shipfox/*` runtime closure. It verifies
|
|
20
|
-
that generated package imports are declared direct dependencies, checks default and `development`
|
|
21
|
-
condition resolution through `dist`, type-checks every packed declaration graph, generates the
|
|
22
|
-
composed TanStack router, builds and type-checks the consumer, runs the behavioral fixture, and
|
|
23
|
-
asserts the exact rejected-collision diagnostic. CI runs this command during static verification.
|
|
24
|
-
|
|
25
|
-
## Run the linked iteration mode
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
pnpm --filter=@shipfox/client-shell test:external -- --link
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
This copies the Vite template to a temporary directory and links the workspace-built closure. It
|
|
32
|
-
runs the same minimal-consumer, generated-route, behavior, collision, and type assertions without
|
|
33
|
-
packing tarballs. The packed-only `development` check is omitted because linked workspace packages
|
|
34
|
-
intentionally resolve that condition to source.
|
|
35
|
-
|
|
36
|
-
Both modes remove their temporary directories after completion. The behavioral composition fixture
|
|
37
|
-
uses Vitest with JSDOM and does not need browser E2E infrastructure.
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Shipfox client composition fixture</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
-
</body>
|
|
12
|
-
</html>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "shipfox-client-shell-external-fixture",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"build": "vite build",
|
|
8
|
-
"test": "vitest run",
|
|
9
|
-
"type": "tsc --noEmit"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@tanstack/react-query": "5.101.0",
|
|
13
|
-
"@tanstack/react-router": "1.170.16",
|
|
14
|
-
"@tanstack/router-core": "1.171.13",
|
|
15
|
-
"jotai": "2.20.1",
|
|
16
|
-
"react": "19.2.7",
|
|
17
|
-
"react-dom": "19.2.7",
|
|
18
|
-
"zod": "4.4.3"
|
|
19
|
-
},
|
|
20
|
-
"devDependencies": {
|
|
21
|
-
"@storybook/react": "10.4.6",
|
|
22
|
-
"@types/node": "24.13.2",
|
|
23
|
-
"@types/react": "19.2.17",
|
|
24
|
-
"@types/react-dom": "19.2.3",
|
|
25
|
-
"@vitejs/plugin-react": "6.0.2",
|
|
26
|
-
"jsdom": "29.1.1",
|
|
27
|
-
"typescript": "6.0.3",
|
|
28
|
-
"vite": "8.0.16",
|
|
29
|
-
"vitest": "4.1.9"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import {getLoadedConfig} from '@shipfox/client-config';
|
|
2
|
-
import {QueryClient} from '@tanstack/react-query';
|
|
3
|
-
import {createMemoryHistory} from '@tanstack/react-router';
|
|
4
|
-
import {flushSync} from 'react-dom';
|
|
5
|
-
import {createRoot, type Root} from 'react-dom/client';
|
|
6
|
-
import {auth, ClientApp, workspaceSetup} from './main';
|
|
7
|
-
import {readProviderEvidence, resetProviderEvidence} from './provider';
|
|
8
|
-
import {router} from './shipfox-app.gen';
|
|
9
|
-
|
|
10
|
-
let container: HTMLDivElement;
|
|
11
|
-
let root: Root;
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
window.matchMedia = vi.fn((query: string) => ({
|
|
15
|
-
matches: false,
|
|
16
|
-
media: query,
|
|
17
|
-
onchange: null,
|
|
18
|
-
addListener: vi.fn(),
|
|
19
|
-
removeListener: vi.fn(),
|
|
20
|
-
addEventListener: vi.fn(),
|
|
21
|
-
removeEventListener: vi.fn(),
|
|
22
|
-
dispatchEvent: vi.fn(() => false),
|
|
23
|
-
}));
|
|
24
|
-
window.scrollTo = vi.fn();
|
|
25
|
-
resetProviderEvidence();
|
|
26
|
-
container = document.createElement('div');
|
|
27
|
-
document.body.append(container);
|
|
28
|
-
root = createRoot(container);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
flushSync(() => root.unmount());
|
|
33
|
-
container.remove();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
function mountClient(): void {
|
|
37
|
-
flushSync(() => root.render(<ClientApp />));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function heading(name: string): Element | undefined {
|
|
41
|
-
return [...container.querySelectorAll('h1, h2, h3')].find(
|
|
42
|
-
(element) => element.textContent?.trim() === name,
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
test('reports a missing external config fragment', async () => {
|
|
47
|
-
window.__SHIPFOX_CONFIG__ = undefined;
|
|
48
|
-
|
|
49
|
-
mountClient();
|
|
50
|
-
|
|
51
|
-
await vi.waitFor(() => expect(heading('Configuration error')).toBeDefined());
|
|
52
|
-
expect(container.textContent).toContain('externalGreeting');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('renders the explicit default-route replacement', async () => {
|
|
56
|
-
window.__SHIPFOX_CONFIG__ = {EXTERNAL_GREETING: 'Hello from the external fixture'};
|
|
57
|
-
router.update({
|
|
58
|
-
history: createMemoryHistory({initialEntries: ['/auth/login']}),
|
|
59
|
-
context: {auth: undefined, queryClient: undefined},
|
|
60
|
-
});
|
|
61
|
-
await router.load();
|
|
62
|
-
|
|
63
|
-
mountClient();
|
|
64
|
-
|
|
65
|
-
await vi.waitFor(() => expect(heading('External login')).toBeDefined());
|
|
66
|
-
expect(heading('Log in')).toBeUndefined();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('renders the external route, provider order, navigation, settings, and config', async () => {
|
|
70
|
-
window.__SHIPFOX_CONFIG__ = {EXTERNAL_GREETING: 'Hello from the external fixture'};
|
|
71
|
-
router.update({
|
|
72
|
-
history: createMemoryHistory({
|
|
73
|
-
initialEntries: ['/workspaces/workspace/settings/external'],
|
|
74
|
-
}),
|
|
75
|
-
context: {auth, queryClient: new QueryClient(), workspaceSetup},
|
|
76
|
-
});
|
|
77
|
-
await router.load();
|
|
78
|
-
mountClient();
|
|
79
|
-
|
|
80
|
-
await vi.waitFor(() => expect(heading('External settings')).toBeDefined());
|
|
81
|
-
expect(
|
|
82
|
-
[...container.querySelectorAll('[role="tab"]')].map((tab) => tab.textContent?.trim()),
|
|
83
|
-
).toEqual(['Projects', 'External', 'Settings']);
|
|
84
|
-
expect(
|
|
85
|
-
[...container.querySelectorAll('[aria-label="Workspace settings"] a')]
|
|
86
|
-
.map((link) => link.textContent?.trim())
|
|
87
|
-
.slice(0, 3),
|
|
88
|
-
).toEqual(['Members', 'External', 'Runners']);
|
|
89
|
-
expect(container.querySelector('[aria-label="External provider order"]')?.textContent).toBe(
|
|
90
|
-
'outer > inner',
|
|
91
|
-
);
|
|
92
|
-
expect(container.textContent).toContain('Hello from the external fixture');
|
|
93
|
-
await vi.waitFor(() => expect(readProviderEvidence().map(({id}) => id)).toEqual(['outer', 'inner']));
|
|
94
|
-
const providers = readProviderEvidence();
|
|
95
|
-
expect(providers[1]?.queryClient).toBe(providers[0]?.queryClient);
|
|
96
|
-
expect(providers[1]?.store).toBe(providers[0]?.store);
|
|
97
|
-
expect(providers.map(({externalGreeting}) => externalGreeting)).toEqual([
|
|
98
|
-
'Hello from the external fixture',
|
|
99
|
-
'Hello from the external fixture',
|
|
100
|
-
]);
|
|
101
|
-
expect(getLoadedConfig<{externalGreeting: string}>().externalGreeting).toBe(
|
|
102
|
-
'Hello from the external fixture',
|
|
103
|
-
);
|
|
104
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import {getLoadedConfig} from '@shipfox/client-config';
|
|
2
|
-
import {defineRoute} from '@shipfox/client-shell/runtime';
|
|
3
|
-
import {useProviderOrder} from '../provider';
|
|
4
|
-
|
|
5
|
-
function ExternalSettings() {
|
|
6
|
-
const providerOrder = useProviderOrder();
|
|
7
|
-
const config = getLoadedConfig<{externalGreeting: string}>();
|
|
8
|
-
return (
|
|
9
|
-
<section>
|
|
10
|
-
<h1>External settings</h1>
|
|
11
|
-
<p>{config.externalGreeting}</p>
|
|
12
|
-
<output aria-label="External provider order">{providerOrder.join(' > ')}</output>
|
|
13
|
-
</section>
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const route = defineRoute({component: ExternalSettings});
|
|
18
|
-
|
|
19
|
-
export default route;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import {defaultFeatures} from '@shipfox/client-features';
|
|
2
|
-
import {defineClientFeature} from '@shipfox/client-shell';
|
|
3
|
-
|
|
4
|
-
const collisionFeature = defineClientFeature({
|
|
5
|
-
id: 'fixture.unapproved-collision',
|
|
6
|
-
routes: [
|
|
7
|
-
{
|
|
8
|
-
path: '/auth/login',
|
|
9
|
-
parent: 'root',
|
|
10
|
-
impl: './features/login-override',
|
|
11
|
-
},
|
|
12
|
-
],
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
export const features = [...defaultFeatures(), collisionFeature];
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import {defaultFeatures} from '@shipfox/client-features';
|
|
2
|
-
import {defineClientFeature} from '@shipfox/client-shell';
|
|
3
|
-
import {z} from 'zod';
|
|
4
|
-
import {ExternalProviderInner, ExternalProviderOuter} from './provider';
|
|
5
|
-
|
|
6
|
-
export const externalConfigShape = {
|
|
7
|
-
externalGreeting: z.string(),
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const externalFeature = defineClientFeature({
|
|
11
|
-
id: 'fixture.external',
|
|
12
|
-
routes: [
|
|
13
|
-
{
|
|
14
|
-
path: '/auth/login',
|
|
15
|
-
parent: 'root',
|
|
16
|
-
override: true,
|
|
17
|
-
impl: './features/login-override',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
path: '/workspaces/$wid/settings/external',
|
|
21
|
-
parent: 'workspaceSettings',
|
|
22
|
-
impl: './features/external-settings',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
providers: [
|
|
26
|
-
{id: 'fixture-provider-outer', Component: ExternalProviderOuter},
|
|
27
|
-
{id: 'fixture-provider-inner', Component: ExternalProviderInner},
|
|
28
|
-
],
|
|
29
|
-
navigation: [
|
|
30
|
-
{
|
|
31
|
-
id: 'nav.external',
|
|
32
|
-
scope: 'workspace',
|
|
33
|
-
label: 'External',
|
|
34
|
-
to: '/workspaces/$wid/settings/external',
|
|
35
|
-
order: 150,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
settingsSections: [
|
|
39
|
-
{
|
|
40
|
-
id: 'settings.external',
|
|
41
|
-
pathSegment: 'external',
|
|
42
|
-
label: 'External',
|
|
43
|
-
icon: 'settings3Line',
|
|
44
|
-
order: 150,
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
configShape: externalConfigShape,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export const features = [...defaultFeatures(), externalFeature];
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import {Link, useParams} from '@tanstack/react-router';
|
|
2
|
-
|
|
3
|
-
export function ExternalSettingsLink() {
|
|
4
|
-
const params = useParams({from: '/workspaces/$wid/settings/external'});
|
|
5
|
-
return (
|
|
6
|
-
<Link to="/workspaces/$wid/settings/external" params={{wid: params.wid}}>
|
|
7
|
-
External settings
|
|
8
|
-
</Link>
|
|
9
|
-
);
|
|
10
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ConfigErrorScreen,
|
|
3
|
-
getWindowRuntimeConfig,
|
|
4
|
-
loadConfig,
|
|
5
|
-
setLoadedConfig,
|
|
6
|
-
} from '@shipfox/client-config';
|
|
7
|
-
import {
|
|
8
|
-
authStateAtom,
|
|
9
|
-
ChromeProvider,
|
|
10
|
-
type AuthState,
|
|
11
|
-
type AuthStateValue,
|
|
12
|
-
mergeConfigShapes,
|
|
13
|
-
type RouterContext,
|
|
14
|
-
} from '@shipfox/client-shell/runtime';
|
|
15
|
-
import {ShellProviders} from '@shipfox/client-shell/testing';
|
|
16
|
-
import {QueryClient} from '@tanstack/react-query';
|
|
17
|
-
import {Outlet, RouterProvider} from '@tanstack/react-router';
|
|
18
|
-
import {createStore} from 'jotai';
|
|
19
|
-
import {useState} from 'react';
|
|
20
|
-
import {createRoot} from 'react-dom/client';
|
|
21
|
-
import {features} from './features';
|
|
22
|
-
import {router} from './shipfox-app.gen';
|
|
23
|
-
|
|
24
|
-
const authState: AuthState = {
|
|
25
|
-
status: 'authenticated',
|
|
26
|
-
workspaces: [{id: 'workspace', name: 'External workspace', membershipId: 'membership'}],
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const auth: AuthStateValue = {
|
|
30
|
-
...authState,
|
|
31
|
-
isLoading: false,
|
|
32
|
-
isAuthenticated: true,
|
|
33
|
-
hasWorkspace: true,
|
|
34
|
-
workspaces: authState.workspaces ?? [],
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const workspaceSetup: NonNullable<RouterContext['workspaceSetup']> = async () => ({
|
|
38
|
-
hideProjectNavigation: false,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
function FixtureProjectBreadcrumb() {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function FixtureProjectLayoutGuard() {
|
|
46
|
-
return <Outlet />;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function ClientApp() {
|
|
50
|
-
const [queryClient] = useState(
|
|
51
|
-
() => new QueryClient({defaultOptions: {queries: {retry: false}}}),
|
|
52
|
-
);
|
|
53
|
-
const [store] = useState(() => {
|
|
54
|
-
const value = createStore();
|
|
55
|
-
// Linked mode has two Jotai type paths; Vite dedupes them to this store at runtime.
|
|
56
|
-
value.set(authStateAtom as never, authState);
|
|
57
|
-
return value;
|
|
58
|
-
});
|
|
59
|
-
const config = loadConfig(mergeConfigShapes(features), {
|
|
60
|
-
runtime: getWindowRuntimeConfig(),
|
|
61
|
-
build: import.meta.env,
|
|
62
|
-
});
|
|
63
|
-
if (!config.ok) return <ConfigErrorScreen errors={config.errors} />;
|
|
64
|
-
setLoadedConfig(config.config);
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<ChromeProvider
|
|
68
|
-
chrome={{
|
|
69
|
-
ProjectBreadcrumb: FixtureProjectBreadcrumb,
|
|
70
|
-
ProjectLayoutGuard: FixtureProjectLayoutGuard,
|
|
71
|
-
}}
|
|
72
|
-
>
|
|
73
|
-
<ShellProviders
|
|
74
|
-
features={features}
|
|
75
|
-
queryClient={queryClient}
|
|
76
|
-
store={store}
|
|
77
|
-
config={config.config}
|
|
78
|
-
>
|
|
79
|
-
<RouterProvider router={router} context={{auth, queryClient, workspaceSetup}} />
|
|
80
|
-
</ShellProviders>
|
|
81
|
-
</ChromeProvider>
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const root = document.getElementById('root');
|
|
86
|
-
if (root) createRoot(root).render(<ClientApp />);
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {getLoadedConfig} from '@shipfox/client-config';
|
|
2
|
-
import {type QueryClient, useQueryClient} from '@tanstack/react-query';
|
|
3
|
-
import {type createStore, useStore} from 'jotai';
|
|
4
|
-
import {createContext, createElement, type PropsWithChildren, useContext} from 'react';
|
|
5
|
-
|
|
6
|
-
type Store = ReturnType<typeof createStore>;
|
|
7
|
-
|
|
8
|
-
export interface ProviderEvidence {
|
|
9
|
-
id: string;
|
|
10
|
-
queryClient: QueryClient;
|
|
11
|
-
store: Store;
|
|
12
|
-
externalGreeting: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const ProviderOrderContext = createContext<readonly string[]>([]);
|
|
16
|
-
const providerEvidence = new Map<string, ProviderEvidence>();
|
|
17
|
-
|
|
18
|
-
function ExternalProvider({id, children}: PropsWithChildren<{id: string}>) {
|
|
19
|
-
const parentOrder = useContext(ProviderOrderContext);
|
|
20
|
-
const queryClient = useQueryClient();
|
|
21
|
-
const store = useStore();
|
|
22
|
-
const {externalGreeting} = getLoadedConfig<{externalGreeting: string}>();
|
|
23
|
-
providerEvidence.set(id, {id, queryClient, store, externalGreeting});
|
|
24
|
-
return createElement(ProviderOrderContext.Provider, {value: [...parentOrder, id]}, children);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function ExternalProviderOuter({children}: PropsWithChildren) {
|
|
28
|
-
return createElement(ExternalProvider, {id: 'outer'}, children);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function ExternalProviderInner({children}: PropsWithChildren) {
|
|
32
|
-
return createElement(ExternalProvider, {id: 'inner'}, children);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function useProviderOrder(): readonly string[] {
|
|
36
|
-
return useContext(ProviderOrderContext);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function readProviderEvidence(): readonly ProviderEvidence[] {
|
|
40
|
-
return [...providerEvidence.values()];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function resetProviderEvidence(): void {
|
|
44
|
-
providerEvidence.clear();
|
|
45
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"strict": true,
|
|
4
|
-
"target": "ES2022",
|
|
5
|
-
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
-
"module": "ESNext",
|
|
7
|
-
"moduleResolution": "bundler",
|
|
8
|
-
"jsx": "react-jsx",
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"verbatimModuleSyntax": true,
|
|
11
|
-
"noEmit": true,
|
|
12
|
-
"types": ["node", "vite/client", "vitest/globals"]
|
|
13
|
-
},
|
|
14
|
-
"include": ["src/**/*.ts", "src/**/*.tsx", "types.ts"]
|
|
15
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {shipfoxClientComposition} from '@shipfox/client-shell/vite';
|
|
2
|
-
import react from '@vitejs/plugin-react';
|
|
3
|
-
import {defineConfig} from 'vite';
|
|
4
|
-
|
|
5
|
-
const config = defineConfig({
|
|
6
|
-
build: {chunkSizeWarningLimit: 4_000},
|
|
7
|
-
plugins: [
|
|
8
|
-
shipfoxClientComposition({
|
|
9
|
-
features:
|
|
10
|
-
process.env.SHIPFOX_COMPOSITION_COLLISION === '1'
|
|
11
|
-
? './src/features.collision.ts'
|
|
12
|
-
: './src/features.ts',
|
|
13
|
-
}),
|
|
14
|
-
react(),
|
|
15
|
-
],
|
|
16
|
-
resolve: {
|
|
17
|
-
dedupe: ['react', 'react-dom', '@tanstack/react-query', '@tanstack/react-router', 'jotai'],
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
export default config;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import react from '@vitejs/plugin-react';
|
|
2
|
-
import {defineConfig} from 'vitest/config';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
plugins: [react()],
|
|
6
|
-
resolve: {
|
|
7
|
-
conditions: ['default'],
|
|
8
|
-
dedupe: ['react', 'react-dom', '@tanstack/react-query', '@tanstack/react-router', 'jotai'],
|
|
9
|
-
},
|
|
10
|
-
ssr: {resolve: {conditions: ['default']}},
|
|
11
|
-
test: {
|
|
12
|
-
environment: 'jsdom',
|
|
13
|
-
globals: true,
|
|
14
|
-
include: ['src/app.fixture.tsx'],
|
|
15
|
-
server: {deps: {inline: [/@shipfox/, /@radix-ui/, /framer-motion/]}},
|
|
16
|
-
},
|
|
17
|
-
});
|