everything-dev 0.1.4 → 0.1.5

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/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "everything-dev",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
7
7
  ".": "./src/index.ts",
8
- "./types": "./src/types.ts"
8
+ "./types": "./src/types.ts",
9
+ "./ui": "./src/ui/index.ts",
10
+ "./ui/types": "./src/ui/types.ts",
11
+ "./ui/runtime": "./src/ui/runtime.ts",
12
+ "./ui/head": "./src/ui/head.ts"
9
13
  },
10
14
  "files": [
11
15
  "src"
@@ -50,6 +54,8 @@
50
54
  "zod": "4.3.5"
51
55
  },
52
56
  "devDependencies": {
57
+ "@tanstack/react-query": "^5.0.0",
58
+ "@tanstack/react-router": "^1.0.0",
53
59
  "@types/bun": "^1.3.8",
54
60
  "@types/gradient-string": "^1.1.6",
55
61
  "@types/react": "^18.3.0",
@@ -57,5 +63,17 @@
57
63
  "playwright": "^1.58.1",
58
64
  "typescript": "^5.9.3",
59
65
  "vitest": "^4.0.18"
66
+ },
67
+ "peerDependencies": {
68
+ "@tanstack/react-query": ">=5.0.0",
69
+ "@tanstack/react-router": ">=1.0.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "@tanstack/react-query": {
73
+ "optional": true
74
+ },
75
+ "@tanstack/react-router": {
76
+ "optional": true
77
+ }
60
78
  }
61
79
  }
@@ -1,8 +1,8 @@
1
1
  import { Command } from "@effect/platform";
2
2
  import { Deferred, Effect, Fiber, Ref, Stream } from "every-plugin/effect";
3
- import { type BosConfig, getConfigDir, getPortsFromConfig, type SourceMode } from "../config";
4
3
  import type { ProcessStatus } from "../components/dev-view";
5
- import { loadSecretsFor } from "./secrets";
4
+ import { type BosConfig, getConfigDir, getPortsFromConfig, type RemoteConfig, type SourceMode } from "../config";
5
+ import type { RuntimeConfig } from "../types";
6
6
 
7
7
  export interface DevProcess {
8
8
  name: string;
@@ -68,7 +68,7 @@ export const getProcessConfig = (
68
68
  if (!base) return null;
69
69
 
70
70
  const ports = getPortsFromConfig();
71
-
71
+
72
72
  let port: number;
73
73
  if (pkg === "host") {
74
74
  port = portOverride ?? ports.host;
@@ -157,9 +157,47 @@ const killProcessTree = (pid: number) =>
157
157
  }
158
158
  });
159
159
 
160
+ export function buildRuntimeConfig(
161
+ bosConfig: BosConfig,
162
+ options: {
163
+ uiSource: SourceMode;
164
+ apiSource: SourceMode;
165
+ hostUrl: string;
166
+ proxy?: string;
167
+ env?: "development" | "production";
168
+ }
169
+ ): RuntimeConfig {
170
+ const uiConfig = bosConfig.app.ui as RemoteConfig;
171
+ const apiConfig = bosConfig.app.api as RemoteConfig;
172
+
173
+ return {
174
+ env: options.env ?? "development",
175
+ account: bosConfig.account,
176
+ title: bosConfig.app.host.title,
177
+ hostUrl: options.hostUrl,
178
+ shared: (bosConfig as { shared?: { ui?: Record<string, unknown> } }).shared as RuntimeConfig["shared"],
179
+ ui: {
180
+ name: uiConfig.name,
181
+ url: options.uiSource === "remote" ? uiConfig.production : uiConfig.development,
182
+ ssrUrl: options.uiSource === "remote" ? uiConfig.ssr : undefined,
183
+ source: options.uiSource,
184
+ exposes: uiConfig.exposes || {},
185
+ },
186
+ api: {
187
+ name: apiConfig.name,
188
+ url: options.apiSource === "remote" ? apiConfig.production : apiConfig.development,
189
+ source: options.apiSource,
190
+ proxy: options.proxy,
191
+ variables: apiConfig.variables,
192
+ secrets: apiConfig.secrets,
193
+ },
194
+ };
195
+ }
196
+
160
197
  export const spawnDevProcess = (
161
198
  config: DevProcess,
162
- callbacks: ProcessCallbacks
199
+ callbacks: ProcessCallbacks,
200
+ runtimeConfig?: RuntimeConfig
163
201
  ) =>
164
202
  Effect.gen(function* () {
165
203
  const configDir = getConfigDir();
@@ -169,15 +207,20 @@ export const spawnDevProcess = (
169
207
 
170
208
  callbacks.onStatus(config.name, "starting");
171
209
 
210
+ const envVars: Record<string, string> = {
211
+ ...process.env as Record<string, string>,
212
+ ...config.env,
213
+ FORCE_COLOR: "1",
214
+ ...(config.port > 0 ? { PORT: String(config.port) } : {}),
215
+ };
216
+
217
+ if (runtimeConfig && config.name === "host") {
218
+ envVars.BOS_RUNTIME_CONFIG = JSON.stringify(runtimeConfig);
219
+ }
220
+
172
221
  const cmd = Command.make(config.command, ...config.args).pipe(
173
222
  Command.workingDirectory(fullCwd),
174
- Command.env({
175
- ...process.env,
176
- ...config.env,
177
- BOS_CONFIG_PATH: "../bos.config.json",
178
- FORCE_COLOR: "1",
179
- ...(config.port > 0 ? { PORT: String(config.port) } : {}),
180
- })
223
+ Command.env(envVars)
181
224
  );
182
225
 
183
226
  const proc = yield* Command.start(cmd);
@@ -247,13 +290,8 @@ interface ServerHandle {
247
290
  shutdown: () => Promise<void>;
248
291
  }
249
292
 
250
- interface BootstrapConfig {
251
- config?: BosConfig;
252
- secrets?: Record<string, string>;
253
- host?: { url?: string };
254
- ui?: { source?: SourceMode };
255
- api?: { source?: SourceMode; proxy?: string };
256
- database?: { url?: string };
293
+ interface ServerInput {
294
+ config: RuntimeConfig;
257
295
  }
258
296
 
259
297
  const patchConsole = (
@@ -300,7 +338,7 @@ const patchConsole = (
300
338
  export const spawnRemoteHost = (
301
339
  config: DevProcess,
302
340
  callbacks: ProcessCallbacks,
303
- bosConfig?: BosConfig
341
+ runtimeConfig: RuntimeConfig
304
342
  ) =>
305
343
  Effect.gen(function* () {
306
344
  const remoteUrl = config.env?.HOST_REMOTE_URL;
@@ -317,27 +355,6 @@ export const spawnRemoteHost = (
317
355
 
318
356
  callbacks.onStatus(config.name, "starting");
319
357
 
320
- let hostUrl = `http://localhost:${config.port}`;
321
- if (process.env.HOST_URL) {
322
- hostUrl = process.env.HOST_URL;
323
- }
324
-
325
- const hostSecrets = loadSecretsFor("host");
326
- const apiSecrets = loadSecretsFor("api");
327
- const allSecrets = { ...hostSecrets, ...apiSecrets };
328
-
329
- const uiSource = (config.env?.UI_SOURCE as SourceMode) ?? "local";
330
- const apiSource = (config.env?.API_SOURCE as SourceMode) ?? "local";
331
- const apiProxy = config.env?.API_PROXY;
332
-
333
- const bootstrap: BootstrapConfig = {
334
- config: bosConfig,
335
- secrets: allSecrets,
336
- host: { url: hostUrl },
337
- ui: { source: uiSource },
338
- api: { source: apiSource, proxy: apiProxy },
339
- };
340
-
341
358
  callbacks.onLog(config.name, `Remote: ${remoteUrl}`);
342
359
 
343
360
  const restoreConsole = patchConsole(config.name, callbacks);
@@ -369,7 +386,7 @@ export const spawnRemoteHost = (
369
386
  callbacks.onLog(config.name, `Loading host from ${remoteEntryUrl}...`);
370
387
 
371
388
  const hostModule = yield* Effect.tryPromise({
372
- try: () => mf.loadRemote<{ runServer: (bootstrap?: BootstrapConfig) => ServerHandle }>("host/Server"),
389
+ try: () => mf.loadRemote<{ runServer: (input: ServerInput) => ServerHandle }>("host/Server"),
373
390
  catch: (e) => new Error(`Failed to load host module: ${e}`),
374
391
  });
375
392
 
@@ -378,7 +395,7 @@ export const spawnRemoteHost = (
378
395
  }
379
396
 
380
397
  callbacks.onLog(config.name, "Starting server...");
381
- const serverHandle = hostModule.runServer(bootstrap);
398
+ const serverHandle = hostModule.runServer({ config: runtimeConfig });
382
399
 
383
400
  yield* Effect.tryPromise({
384
401
  try: () => serverHandle.ready,
@@ -415,8 +432,29 @@ export const makeDevProcess = (
415
432
  return yield* Effect.fail(new Error(`Unknown package: ${pkg}`));
416
433
  }
417
434
 
418
- if (pkg === "host" && env?.HOST_SOURCE === "remote") {
419
- return yield* spawnRemoteHost(config, callbacks, bosConfig);
435
+ if (pkg === "host" && bosConfig) {
436
+ const uiSource = (env?.UI_SOURCE as SourceMode) ?? "local";
437
+ const apiSource = (env?.API_SOURCE as SourceMode) ?? "local";
438
+ const apiProxy = env?.API_PROXY;
439
+
440
+ let hostUrl = `http://localhost:${config.port}`;
441
+ if (process.env.HOST_URL) {
442
+ hostUrl = process.env.HOST_URL;
443
+ }
444
+
445
+ const runtimeConfig = buildRuntimeConfig(bosConfig, {
446
+ uiSource,
447
+ apiSource,
448
+ hostUrl,
449
+ proxy: apiProxy,
450
+ env: "development",
451
+ });
452
+
453
+ if (env?.HOST_SOURCE === "remote") {
454
+ return yield* spawnRemoteHost(config, callbacks, runtimeConfig);
455
+ }
456
+
457
+ return yield* spawnDevProcess(config, callbacks, runtimeConfig);
420
458
  }
421
459
 
422
460
  return yield* spawnDevProcess(config, callbacks);
package/src/types.ts CHANGED
@@ -88,3 +88,54 @@ export const PortConfigSchema = z.object({
88
88
  api: z.number(),
89
89
  });
90
90
  export type PortConfig = z.infer<typeof PortConfigSchema>;
91
+
92
+ export const SharedConfigSchema = z.object({
93
+ requiredVersion: z.string().optional(),
94
+ singleton: z.boolean().optional(),
95
+ eager: z.boolean().optional(),
96
+ strictVersion: z.boolean().optional(),
97
+ shareScope: z.string().optional(),
98
+ });
99
+ export type SharedConfig = z.infer<typeof SharedConfigSchema>;
100
+
101
+ export const RuntimeConfigSchema = z.object({
102
+ env: z.enum(["development", "production"]),
103
+ account: z.string(),
104
+ title: z.string(),
105
+ hostUrl: z.string(),
106
+ shared: z.object({
107
+ ui: z.record(z.string(), SharedConfigSchema).optional(),
108
+ }).optional(),
109
+ ui: z.object({
110
+ name: z.string(),
111
+ url: z.string(),
112
+ ssrUrl: z.string().optional(),
113
+ source: SourceModeSchema,
114
+ exposes: z.record(z.string(), z.string()),
115
+ }),
116
+ api: z.object({
117
+ name: z.string(),
118
+ url: z.string(),
119
+ source: SourceModeSchema,
120
+ proxy: z.string().optional(),
121
+ variables: z.record(z.string(), z.string()).optional(),
122
+ secrets: z.array(z.string()).optional(),
123
+ }),
124
+ });
125
+ export type RuntimeConfig = z.infer<typeof RuntimeConfigSchema>;
126
+
127
+ export const ClientRuntimeConfigSchema = z.object({
128
+ env: z.enum(["development", "production"]),
129
+ account: z.string(),
130
+ title: z.string(),
131
+ hostUrl: z.string().optional(),
132
+ assetsUrl: z.string(),
133
+ apiBase: z.string(),
134
+ rpcBase: z.string(),
135
+ ui: z.object({
136
+ name: z.string(),
137
+ url: z.string(),
138
+ exposes: z.record(z.string(), z.string()).optional(),
139
+ }).optional(),
140
+ });
141
+ export type ClientRuntimeConfig = z.infer<typeof ClientRuntimeConfigSchema>;
package/src/ui/head.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { ClientRuntimeConfig } from "../types";
2
+ import type { HeadScript } from "./types";
3
+
4
+ export interface RemoteScriptsOptions {
5
+ assetsUrl: string;
6
+ runtimeConfig?: ClientRuntimeConfig;
7
+ containerName?: string;
8
+ hydratePath?: string;
9
+ }
10
+
11
+ export function getRemoteEntryScript(assetsUrl: string): HeadScript {
12
+ return {
13
+ src: `${assetsUrl}/remoteEntry.js`,
14
+ };
15
+ }
16
+
17
+ export function getThemeInitScript(): HeadScript {
18
+ return {
19
+ children: `(function(){var t=localStorage.getItem('theme');if(t==='dark'||(!t&&window.matchMedia('(prefers-color-scheme: dark)').matches)){document.documentElement.classList.add('dark');}})();`,
20
+ };
21
+ }
22
+
23
+ export function getHydrateScript(
24
+ runtimeConfig: ClientRuntimeConfig | undefined,
25
+ containerName = "ui",
26
+ hydratePath = "./Hydrate"
27
+ ): HeadScript {
28
+ return {
29
+ children: `
30
+ window.__RUNTIME_CONFIG__=${JSON.stringify(runtimeConfig)};
31
+ function __hydrate(){
32
+ var container = window['${containerName}'];
33
+ if (!container) { console.error('[Hydrate] Container not found'); return; }
34
+ container.init({}).then(function(){
35
+ return container.get('${hydratePath}');
36
+ }).then(function(mod){
37
+ return mod().hydrate();
38
+ }).catch(function(e){
39
+ console.error('[Hydrate] Failed:', e);
40
+ });
41
+ }
42
+ if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',__hydrate);}else{__hydrate();}
43
+ `.trim(),
44
+ };
45
+ }
46
+
47
+ export function getRemoteScripts(options: RemoteScriptsOptions): HeadScript[] {
48
+ const { assetsUrl, runtimeConfig, containerName, hydratePath } = options;
49
+
50
+ return [
51
+ getRemoteEntryScript(assetsUrl),
52
+ getThemeInitScript(),
53
+ getHydrateScript(runtimeConfig, containerName, hydratePath),
54
+ ];
55
+ }
56
+
57
+ export function getBaseStyles(): string {
58
+ return `
59
+ *, *::before, *::after { box-sizing: border-box; }
60
+ html { height: 100%; height: 100dvh; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; color-scheme: light dark; }
61
+ body { min-height: 100%; min-height: 100dvh; margin: 0; background-color: var(--background); color: var(--foreground); -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
62
+ #root { min-height: 100vh; }
63
+ @supports (min-height: 100dvh) { #root { min-height: 100dvh; } }
64
+ `.trim();
65
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./types";
2
+ export * from "./runtime";
3
+ export * from "./head";
@@ -0,0 +1,35 @@
1
+ import type { ClientRuntimeConfig } from "../types";
2
+
3
+ declare global {
4
+ interface Window {
5
+ __RUNTIME_CONFIG__?: ClientRuntimeConfig;
6
+ }
7
+ }
8
+
9
+ export function getRuntimeConfig(): ClientRuntimeConfig | undefined {
10
+ if (typeof window === "undefined") return undefined;
11
+ return window.__RUNTIME_CONFIG__;
12
+ }
13
+
14
+ export function getAssetsUrl(config?: ClientRuntimeConfig): string {
15
+ const cfg = config ?? getRuntimeConfig();
16
+ return cfg?.assetsUrl ?? "";
17
+ }
18
+
19
+ export function getHostUrl(config?: ClientRuntimeConfig): string {
20
+ const cfg = config ?? getRuntimeConfig();
21
+ if (typeof window === "undefined") return "";
22
+ return cfg?.hostUrl ?? window.location.origin;
23
+ }
24
+
25
+ export function getApiBaseUrl(config?: ClientRuntimeConfig): string {
26
+ const cfg = config ?? getRuntimeConfig();
27
+ const base = cfg?.rpcBase;
28
+ if (typeof window === "undefined") return "/api/rpc";
29
+ return base ? `${window.location.origin}${base}` : `${window.location.origin}/api/rpc`;
30
+ }
31
+
32
+ export function getAccount(config?: ClientRuntimeConfig): string {
33
+ const cfg = config ?? getRuntimeConfig();
34
+ return cfg?.account ?? "every.near";
35
+ }
@@ -0,0 +1,51 @@
1
+ import type { QueryClient } from "@tanstack/react-query";
2
+ import type { AnyRouteMatch, AnyRouter, RouterHistory } from "@tanstack/react-router";
3
+ import type { ClientRuntimeConfig } from "../types";
4
+
5
+ export interface RouterContext {
6
+ queryClient: QueryClient;
7
+ assetsUrl: string;
8
+ runtimeConfig?: ClientRuntimeConfig;
9
+ }
10
+
11
+ export interface CreateRouterOptions {
12
+ history?: RouterHistory;
13
+ context?: Partial<RouterContext>;
14
+ }
15
+
16
+ export type HeadMeta = NonNullable<AnyRouteMatch["meta"]>[number];
17
+ export type HeadLink = NonNullable<AnyRouteMatch["links"]>[number];
18
+ export type HeadScript = NonNullable<AnyRouteMatch["headScripts"]>[number];
19
+
20
+ export interface HeadData {
21
+ meta: HeadMeta[];
22
+ links: HeadLink[];
23
+ scripts: HeadScript[];
24
+ }
25
+
26
+ export interface RenderOptions {
27
+ assetsUrl: string;
28
+ runtimeConfig: ClientRuntimeConfig;
29
+ }
30
+
31
+ export interface RenderResult {
32
+ stream: ReadableStream;
33
+ statusCode: number;
34
+ headers: Headers;
35
+ }
36
+
37
+ export interface RouterModule {
38
+ createRouter: (opts?: CreateRouterOptions) => {
39
+ router: AnyRouter;
40
+ queryClient: QueryClient;
41
+ };
42
+ getRouteHead: (
43
+ pathname: string,
44
+ context?: Partial<RouterContext>
45
+ ) => Promise<HeadData>;
46
+ renderToStream: (
47
+ request: Request,
48
+ options: RenderOptions
49
+ ) => Promise<RenderResult>;
50
+ routeTree: AnyRouter["routeTree"];
51
+ }