@ossy/app 1.12.0 → 1.13.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/README.md CHANGED
@@ -1,97 +1,122 @@
1
1
  # `@ossy/app`
2
2
 
3
- Server-side rendering runtime and build tooling for Ossy apps. Use with `@ossy/cli` for the convention-based setup (`npx @ossy/cli dev`).
3
+ Server-side rendering runtime and build tooling for Ossy apps.
4
4
 
5
- For custom setups (Next.js, Vite, etc.), use `@ossy/connected-components` directly — see the [root README](../README.md#when-to-use-what).
5
+ For custom setups (Next.js, Vite, etc.), use `@ossy/connected-components` directly.
6
6
 
7
7
  ## Setup
8
8
 
9
- Create `*.page.jsx` files in `src/`:
9
+ Add `@ossy/app`, `react`, `react-dom`, and `@ossy/connected-components` (plus its peer deps) to your `package.json`, then run `app build`.
10
+
11
+ ```json
12
+ {
13
+ "scripts": {
14
+ "build": "app build",
15
+ "start": "node build/server.js"
16
+ }
17
+ }
18
+ ```
19
+
20
+ ## Pages
21
+
22
+ Create `*.page.jsx` files in `src/`. Each file becomes a route.
10
23
 
11
24
  ```jsx
12
25
  // src/home.page.jsx
13
- import React from 'react'
14
- export default () => <h1>Welcome</h1>
26
+ export const metadata = {
27
+ id: 'home',
28
+ title: 'Home',
29
+ path: '/',
30
+ }
31
+
32
+ export default function Home({ url }) {
33
+ return (
34
+ <body>
35
+ <h1>Welcome</h1>
36
+ <p>Current URL: {url}</p>
37
+ </body>
38
+ )
39
+ }
15
40
  ```
16
41
 
17
- Each file becomes a route: `home.page.jsx` → `/`, `about.page.jsx` → `/about`. Optionally export `metadata` for custom id/path or multi-language:
42
+ **File route mapping:** `home.page.jsx` → `/`, `about.page.jsx` → `/about`. The `metadata` export controls the route `id`, `path`, and page `title`. For multi-language paths:
18
43
 
19
44
  ```js
20
- export const metadata = { path: { en: '/about', sv: '/om' } }
21
- export default () => <h1>About</h1>
45
+ export const metadata = {
46
+ id: 'about',
47
+ path: { en: '/about', sv: '/om' },
48
+ }
22
49
  ```
23
50
 
24
- During `dev` / `build`, the tooling writes **JSON manifests** under **`build/.ossy/`**: **`pages.generated.json`** (after compile: route ids, paths, `sourceFile`, merged `metadata`, and **`module`** a `page-modules/<id>.mjs` path the **Node** server `import()`s per request for SSR), **`pages.bundle.json`** (compiled module index), plus the same pattern for API and tasks. **`pages.runtime.mjs`** exports the route table from **`pages.generated.json`** only.
51
+ **What the framework provides:** The build wraps every page automatically with `<html>`, `<head>` (including the page title and injected styles), and `<App>` (providers for theme, router, SDK). Your page component only needs to return the `<body>` element and its content.
52
+
53
+ **Props:** The full app config is passed as props to the page component — `url`, `theme`, `isAuthenticated`, `pages`, `workspaceId`, `apiUrl`, etc. You can also access config via `useApp()` / `useRouter()` hooks from `@ossy/connected-components` and `@ossy/router-react`.
54
+
55
+ **Build output:** Each page produces two self-contained bundles (React included):
56
+ - `build/ssr/<id>.mjs` — used by the server for SSR on each request
57
+ - `build/public/static/<id>.js` — loaded by the browser for hydration
25
58
 
26
- **Client JS (per-page):** For each `*.page.jsx`, the build emits **`build/.ossy/hydrate-<pageId>.jsx`** → **`public/static/<pageId>.js`**. Rollup bundles that entry with the page source so **`react` resolves in the browser** (unlike the Node `page-modules/*.mjs` chunks, which keep `react` external). The HTML only loads the hydrate script for the **current** route. The inline config (`window.__INITIAL_APP_CONFIG__`) keeps request-time fields (theme, `apiUrl`, etc.); `pages` in config include `id`, `path`, and `module` for consistency with the manifest.
59
+ ## Config
27
60
 
28
- Add `src/config.js` for workspace and theme:
61
+ Add `src/config.js` to set workspace, theme, and API options:
29
62
 
30
63
  ```js
31
64
  import { CloudLight } from '@ossy/themes'
32
65
 
33
66
  export default {
34
67
  workspaceId: 'your-workspace-id',
35
- theme: CloudLight, // or 'light' | 'dark' | CloudDark
36
- apiUrl: 'https://api.ossy.se/api/v0', // optional
68
+ theme: CloudLight,
69
+ apiUrl: 'https://api.ossy.se/api/v0',
37
70
  }
38
71
  ```
39
72
 
40
- Config is loaded at build time and merged with request-time settings (e.g. user theme preference from cookies). The server passes `workspaceId`, `apiUrl`, and `theme` to the App component.
41
-
42
- Run `npx @ossy/cli dev` or `npx @ossy/cli build`.
43
-
44
- If the package has **`src/resource-templates/`**, the build also writes **`.ossy-system-templates.generated.js`** there (merging `*.resource.js` into `SystemTemplates`, ordered by filename).
73
+ Config is loaded at build time and merged with request-time settings (e.g. user theme preference from cookies).
45
74
 
46
75
  ## API routes
47
76
 
48
- Define HTTP handlers as an array of `{ id, path, handle(req, res) }` objects (same shape the server passes to `@ossy/router`).
49
-
50
- Add any number of `*.api.js` (or `.api.mjs` / `.api.cjs`) files under `src/` (nested dirs allowed). Each file’s **default export** is either one route object or an array of routes. Files are merged in lexicographic path order.
51
-
52
- Build/dev writes **`build/.ossy/api.generated.json`** (discovered source paths) and **`api.bundle.json`** (Rollup outputs under **`api-modules/`**). The server imports **`api.runtime.mjs`**, which loads those modules. With no API files, both JSON files list empty arrays.
53
-
54
- Example `src/health.api.js`:
77
+ Create `*.api.js` files in `src/`. Each file exports a `metadata` object and a default handler function.
55
78
 
56
79
  ```js
57
- export default {
80
+ // src/health.api.js
81
+ export const metadata = {
58
82
  id: 'health',
59
83
  path: '/api/health',
60
- handle(req, res) {
61
- res.json({ status: 'ok' })
62
- },
63
84
  }
64
- ```
65
85
 
66
- API routes are matched before the app is rendered. The router supports dynamic segments (e.g. `path: '/api/users/:id'`); extract params from `req.originalUrl` if needed. Use paths that don't conflict with `/@ossy/*` (reserved for the internal proxy).
86
+ export default function handle(req, res) {
87
+ res.json({ status: 'ok' })
88
+ }
89
+ ```
67
90
 
68
- ## Background worker tasks (`*.task.js`)
91
+ The handler receives the raw Express `req` and `res`. API routes are matched before page rendering. The router supports dynamic segments (e.g. `path: '/api/users/:id'`).
69
92
 
70
- For long-running job processors (separate from the SSR server), use **`npx @ossy/cli build --worker`** in a package that only needs the worker. It uses the same Rollup + Babel pipeline as `ossy build`, discovers **`*.task.js`** (and `.task.mjs` / `.task.cjs`) under `src/` (or `--pages <dir>`), and writes **`tasks.generated.json`** / **`tasks.bundle.json`** plus **`tasks.runtime.mjs`**—the same metadata + per-file compile pattern as API routes.
93
+ Build output: `build/.ossy/api.generated.json` a registry of `[{ id, path, module }]` entries. Handlers are lazy-imported on first request.
71
94
 
72
- Optional legacy aggregate: **`src/tasks.js`** default export is merged **first**, then each `*.task.js` in path order.
95
+ ## Background tasks (`*.task.js`)
73
96
 
74
- Each task file’s **default export** is `{ type, handler }` where `type` matches the platform job type string, and `handler` is `async ({ sdk, job }) => { ... }` (see `@ossy/worker` for examples).
97
+ For background job processors, create `*.task.js` files in `src/`. Each file exports a `metadata` object with a `type` field and a default handler function.
75
98
 
76
- **Override:** `--task-source ./path/to/tasks.js` skips discovery and uses a single file.
99
+ ```js
100
+ // src/send-email.task.js
101
+ export const metadata = {
102
+ type: 'send-email',
103
+ }
77
104
 
78
- Output: **`build/worker.js`**. Run with `node build/worker.js` (after `import 'dotenv/config'` via the entry). Set `OSSY_WORKSPACE_ID`, `OSSY_API_URL`, and `OSSY_API_TOKEN` as before.
105
+ export default async function handle({ sdk, job }) {
106
+ // process the job
107
+ }
108
+ ```
79
109
 
80
- ## Port configuration
110
+ The worker polls the job queue every 3 seconds and lazy-imports the handler module the first time a job of that type arrives.
81
111
 
82
- By default, the server listens on port **3000**.
112
+ Build output: `build/.ossy/tasks.generated.json` — a registry of `[{ type, module }]` entries. Run the worker with `node build/worker.js`. Requires `OSSY_WORKSPACE_ID`, `OSSY_API_URL`, and `OSSY_API_TOKEN` environment variables.
83
113
 
84
- - **Environment variable**: set `PORT`
85
- - **CLI argument**: pass `--port <number>` (or `-p <number>`) when running the built server file
114
+ ## Port configuration
86
115
 
87
- Examples:
116
+ The server listens on port **3000** by default.
88
117
 
89
118
  ```bash
90
- # env var
91
119
  PORT=4000 node build/server.js
92
-
93
- # CLI arg
94
120
  node build/server.js --port 4000
95
121
  node build/server.js -p 4000
96
122
  ```
97
-
package/cli/build.js CHANGED
@@ -275,17 +275,30 @@ export function generatePageSsrModule ({ pageAbsPath, stubAbsPath }) {
275
275
  "import { createElement } from 'react'",
276
276
  "import { renderToPipeableStream } from 'react-dom/server'",
277
277
  "import { Writable } from 'node:stream'",
278
+ "import { App } from '@ossy/connected-components'",
278
279
  `import * as _page from './${rel}'`,
279
280
  '',
280
281
  'export const metadata = _page.metadata',
281
282
  '',
283
+ 'function PageShell (props) {',
284
+ " return createElement('html', { lang: props.defaultLanguage || 'en' },",
285
+ " createElement('head', null,",
286
+ " createElement('meta', { charSet: 'utf-8' }),",
287
+ " createElement('title', null, (_page.metadata && _page.metadata.title) || ''),",
288
+ ' ),',
289
+ ' createElement(App, props,',
290
+ ' createElement(_page.default, props)',
291
+ ' )',
292
+ ' )',
293
+ '}',
294
+ '',
282
295
  'export function renderPage (props, options = {}) {',
283
296
  ' return new Promise((resolve, reject) => {',
284
297
  " let html = ''",
285
298
  ' const writable = new Writable({',
286
299
  ' write (chunk, _enc, cb) { html += chunk.toString(); cb() },',
287
300
  ' })',
288
- ' const { pipe } = renderToPipeableStream(createElement(_page.default, props), {',
301
+ ' const { pipe } = renderToPipeableStream(createElement(PageShell, props), {',
289
302
  ' ...options,',
290
303
  ' onAllReady () { pipe(writable) },',
291
304
  ' onError (err) { reject(err) },',
@@ -306,6 +319,7 @@ export function writePageSsrStubs (pageFiles, srcDir, ossyDir) {
306
319
  for (const f of pageFiles) {
307
320
  const pageId = clientHydrateIdForPage(f, srcDir)
308
321
  const stubPath = path.join(entriesDir, `${pageId}.mjs`)
322
+ fs.mkdirSync(path.dirname(stubPath), { recursive: true })
309
323
  fs.writeFileSync(stubPath, generatePageSsrModule({ pageAbsPath: f, stubAbsPath: stubPath }))
310
324
  }
311
325
  }
@@ -395,13 +409,6 @@ export function copyOssyAppRuntime ({ scriptDir, buildPath }) {
395
409
  fs.copyFileSync(path.join(scriptDir, 'worker-entry.js'), path.join(buildPath, 'worker.js'))
396
410
  fs.copyFileSync(path.join(scriptDir, 'worker-runtime.js'), path.join(buildPath, 'worker-runtime.js'))
397
411
  const ossyOut = ossyGeneratedDir(buildPath)
398
- for (const name of [
399
- OSSY_PAGES_RUNTIME_BASENAME,
400
- OSSY_API_RUNTIME_BASENAME,
401
- OSSY_TASKS_RUNTIME_BASENAME,
402
- ]) {
403
- fs.copyFileSync(path.join(scriptDir, name), path.join(ossyOut, name))
404
- }
405
412
  fs.copyFileSync(
406
413
  path.join(scriptDir, OSSY_RENDER_PAGE_RUNTIME_BASENAME),
407
414
  path.join(ossyOut, OSSY_RENDER_PAGE_RUNTIME_BASENAME)
@@ -436,18 +443,12 @@ export function writeOssyJson (filePath, data) {
436
443
 
437
444
  /** JSON manifest: discovered API source paths (posix, relative to `cwd`). */
438
445
  export function buildApiManifestPayload (apiFiles, cwd = process.cwd()) {
439
- return {
440
- version: 1,
441
- files: apiFiles.map((f) => path.relative(cwd, f).replace(/\\/g, '/')),
442
- }
446
+ return apiFiles.map((f) => path.relative(cwd, f).replace(/\\/g, '/'))
443
447
  }
444
448
 
445
449
  /** JSON manifest: discovered task source paths (posix, relative to `cwd`). */
446
450
  export function buildTasksManifestPayload (taskFiles, cwd = process.cwd()) {
447
- return {
448
- version: 1,
449
- files: taskFiles.map((f) => path.relative(cwd, f).replace(/\\/g, '/')),
450
- }
451
+ return taskFiles.map((f) => path.relative(cwd, f).replace(/\\/g, '/'))
451
452
  }
452
453
 
453
454
  /**
@@ -520,7 +521,7 @@ export async function compileApiServerModules ({ apiFiles, ossyDir, nodeEnv, onW
520
521
  return []
521
522
  }
522
523
  fs.mkdirSync(modsDir, { recursive: true })
523
- const modules = []
524
+ const routes = []
524
525
  for (let i = 0; i < apiFiles.length; i++) {
525
526
  const outName = `api-${i}.mjs`
526
527
  const outFile = path.join(modsDir, outName)
@@ -530,9 +531,16 @@ export async function compileApiServerModules ({ apiFiles, ossyDir, nodeEnv, onW
530
531
  nodeEnv,
531
532
  onWarn,
532
533
  })
533
- modules.push(`${OSSY_API_MODULES_DIRNAME}/${outName}`)
534
+ let meta = {}
535
+ try {
536
+ const mod = await import(pathToFileURL(outFile).href)
537
+ meta = mod?.metadata && typeof mod.metadata === 'object' ? mod.metadata : {}
538
+ } catch {
539
+ // metadata unreadable — skip
540
+ }
541
+ routes.push({ ...meta, module: `${OSSY_API_MODULES_DIRNAME}/${outName}` })
534
542
  }
535
- return modules
543
+ return routes
536
544
  }
537
545
 
538
546
  export async function compileTaskServerModules ({ taskFiles, ossyDir, nodeEnv, onWarn }) {
@@ -542,7 +550,7 @@ export async function compileTaskServerModules ({ taskFiles, ossyDir, nodeEnv, o
542
550
  return []
543
551
  }
544
552
  fs.mkdirSync(modsDir, { recursive: true })
545
- const modules = []
553
+ const tasks = []
546
554
  for (let i = 0; i < taskFiles.length; i++) {
547
555
  const outName = `task-${i}.mjs`
548
556
  const outFile = path.join(modsDir, outName)
@@ -552,9 +560,16 @@ export async function compileTaskServerModules ({ taskFiles, ossyDir, nodeEnv, o
552
560
  nodeEnv,
553
561
  onWarn,
554
562
  })
555
- modules.push(`${OSSY_TASK_MODULES_DIRNAME}/${outName}`)
563
+ let meta = {}
564
+ try {
565
+ const mod = await import(pathToFileURL(outFile).href)
566
+ meta = mod?.metadata && typeof mod.metadata === 'object' ? mod.metadata : {}
567
+ } catch {
568
+ // metadata unreadable — skip
569
+ }
570
+ tasks.push({ ...meta, module: `${OSSY_TASK_MODULES_DIRNAME}/${outName}` })
556
571
  }
557
- return modules
572
+ return tasks
558
573
  }
559
574
 
560
575
  /**
@@ -567,8 +582,7 @@ export async function compileTaskServerModules ({ taskFiles, ossyDir, nodeEnv, o
567
582
  */
568
583
  export async function enrichPagesGeneratedManifest ({ ossyDir, pagesGeneratedPath }) {
569
584
  if (!fs.existsSync(pagesGeneratedPath)) return
570
- const raw = JSON.parse(fs.readFileSync(pagesGeneratedPath, 'utf8'))
571
- const basePages = raw?.pages
585
+ const basePages = JSON.parse(fs.readFileSync(pagesGeneratedPath, 'utf8'))
572
586
  if (!Array.isArray(basePages) || basePages.length === 0) return
573
587
 
574
588
  const pages = []
@@ -599,7 +613,7 @@ export async function enrichPagesGeneratedManifest ({ ossyDir, pagesGeneratedPat
599
613
  }
600
614
  pages.push(merged)
601
615
  }
602
- writeOssyJson(pagesGeneratedPath, { version: raw.version ?? 1, pages })
616
+ writeOssyJson(pagesGeneratedPath, pages)
603
617
  }
604
618
 
605
619
  /**
@@ -615,19 +629,13 @@ export async function compileOssyNodeArtifacts ({
615
629
  nodeEnv,
616
630
  onWarn,
617
631
  }) {
618
- const [, apiModuleList, taskModuleList] = await Promise.all([
632
+ const [, apiRouteList, taskList] = await Promise.all([
619
633
  compilePageSsrModules({ pageFiles, srcDir, ossyDir, buildPath, nodeEnv, onWarn }),
620
634
  compileApiServerModules({ apiFiles, ossyDir, nodeEnv, onWarn }),
621
635
  compileTaskServerModules({ taskFiles, ossyDir, nodeEnv, onWarn }),
622
636
  ])
623
- writeOssyJson(path.join(ossyDir, OSSY_API_BUNDLE_BASENAME), {
624
- version: 1,
625
- modules: apiModuleList,
626
- })
627
- writeOssyJson(path.join(ossyDir, OSSY_TASKS_BUNDLE_BASENAME), {
628
- version: 1,
629
- modules: taskModuleList,
630
- })
637
+ writeOssyJson(path.join(ossyDir, OSSY_GEN_API_BASENAME), apiRouteList)
638
+ writeOssyJson(path.join(ossyDir, OSSY_GEN_TASKS_BASENAME), taskList)
631
639
  await enrichPagesGeneratedManifest({
632
640
  ossyDir,
633
641
  pagesGeneratedPath: path.join(ossyDir, OSSY_GEN_PAGES_BASENAME),
@@ -710,17 +718,28 @@ export function generatePageHydrateModule ({ pageAbsPath, stubAbsPath, srcDir })
710
718
  return [
711
719
  '// Generated by @ossy/app — do not edit',
712
720
  '',
713
- "import React, { createElement } from 'react'",
721
+ "import { createElement } from 'react'",
714
722
  "import { hydrateRoot } from 'react-dom/client'",
723
+ "import { App } from '@ossy/connected-components'",
715
724
  `import * as _page from './${rel}'`,
716
725
  '',
717
726
  'export default _page.default',
718
727
  'export const metadata = _page.metadata',
719
728
  '',
720
729
  "if (typeof window !== 'undefined') {",
721
- " const Page = _page.default",
722
730
  " const config = window.__INITIAL_APP_CONFIG__ || {}",
723
- " hydrateRoot(document, createElement(Page, config))",
731
+ ' function PageShell (props) {',
732
+ " return createElement('html', { lang: props.defaultLanguage || 'en' },",
733
+ " createElement('head', null,",
734
+ " createElement('meta', { charSet: 'utf-8' }),",
735
+ " createElement('title', null, (_page.metadata && _page.metadata.title) || ''),",
736
+ ' ),',
737
+ ' createElement(App, props,',
738
+ ' createElement(_page.default, props)',
739
+ ' )',
740
+ ' )',
741
+ ' }',
742
+ ' hydrateRoot(document, createElement(PageShell, config))',
724
743
  '}',
725
744
  '',
726
745
  ].join('\n')
@@ -780,7 +799,7 @@ export function buildPagesGeneratedPayload (pageFiles, srcDir, cwd = process.cwd
780
799
  sourceFile: path.relative(cwd, f).replace(/\\/g, '/'),
781
800
  }
782
801
  })
783
- return { version: 1, pages }
802
+ return pages
784
803
  }
785
804
 
786
805
  export function writePagesManifest ({
@@ -794,11 +813,9 @@ export function writePagesManifest ({
794
813
 
795
814
  export function parsePagesFromManifestJson (manifestPath) {
796
815
  try {
797
- const raw = fs.readFileSync(manifestPath, 'utf8')
798
- const data = JSON.parse(raw)
799
- const pages = data?.pages
800
- if (!Array.isArray(pages)) return []
801
- return pages.map((p) => ({
816
+ const data = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
817
+ if (!Array.isArray(data)) return []
818
+ return data.map((p) => ({
802
819
  id: p.id,
803
820
  path: p.path,
804
821
  ...(typeof p.module === 'string' ? { module: p.module } : {}),
package/cli/server.js CHANGED
@@ -1,21 +1,25 @@
1
+ import fs from 'node:fs'
1
2
  import path from 'path';
2
3
  import url from 'url'
4
+ import { pathToFileURL } from 'node:url'
3
5
  import express from 'express'
4
6
  import morgan from 'morgan'
5
7
  import { Router as OssyRouter } from '@ossy/router'
6
8
  import { ProxyInternal } from './proxy-internal.js'
7
9
  import cookieParser from 'cookie-parser'
8
10
 
9
- import ApiRoutes from './.ossy/api.runtime.mjs'
10
- import pageRoutes from './.ossy/pages.runtime.mjs'
11
11
  import buildTimeConfig from './.ossy/server-config.runtime.mjs'
12
12
  import { BuildPage, buildPrerenderAppConfig } from './.ossy/render-page.task.js'
13
13
  import Middleware from './.ossy/middleware.runtime.js'
14
14
 
15
- /** API bundle default may be an empty array. */
16
- const apiRouteList = ApiRoutes ?? []
15
+ const __ossyDir = path.dirname(url.fileURLToPath(import.meta.url)) + '/.ossy'
17
16
 
18
- const sitePageList = Array.isArray(pageRoutes) ? pageRoutes : []
17
+ function readOssyJson (name) {
18
+ return JSON.parse(fs.readFileSync(path.join(__ossyDir, name), 'utf8'))
19
+ }
20
+
21
+ const apiRouteList = readOssyJson('api.generated.json') ?? []
22
+ const sitePageList = readOssyJson('pages.generated.json') ?? []
19
23
 
20
24
  /** When `src/config.js` is minimal, infer language list from the first multi-path page. */
21
25
  function pageRouterLanguageOptions (config, pages) {
@@ -113,9 +117,10 @@ app.all('*all', async (req, res) => {
113
117
 
114
118
  try {
115
119
  const apiRoute = apiRouter.getPageByUrl(requestUrl)
116
- if (apiRoute && typeof apiRoute.handle === 'function') {
120
+ if (apiRoute?.module) {
117
121
  console.log(`[@ossy/app][server] Handling API route: ${requestUrl}`)
118
- apiRoute.handle(req, res)
122
+ const mod = await import(pathToFileURL(path.resolve(__ossyDir, apiRoute.module)).href)
123
+ await mod.default(req, res)
119
124
  return
120
125
  }
121
126
 
@@ -1,5 +1,10 @@
1
1
  import 'dotenv/config'
2
- import taskHandlers from './.ossy/tasks.runtime.mjs'
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
3
5
  import { runWorkerScheduler } from './worker-runtime.js'
4
6
 
5
- runWorkerScheduler(taskHandlers)
7
+ const __ossyDir = path.dirname(fileURLToPath(import.meta.url)) + '/.ossy'
8
+ const tasks = JSON.parse(fs.readFileSync(path.join(__ossyDir, 'tasks.generated.json'), 'utf8')) ?? []
9
+
10
+ runWorkerScheduler(tasks, __ossyDir)
@@ -1,9 +1,12 @@
1
+ import path from 'node:path'
2
+ import { pathToFileURL } from 'node:url'
1
3
  import { SDK } from '@ossy/sdk'
2
4
 
3
5
  /**
4
- * @param {Array<{ type: string, handler: (ctx: { sdk: import('@ossy/sdk').SDK, job: Record<string, unknown> }) => Promise<void> }>} handlers
6
+ * @param {Array<{ type: string, module: string }>} tasks
7
+ * @param {string} ossyDir - absolute path to the .ossy directory
5
8
  */
6
- export function runWorkerScheduler(handlers) {
9
+ export function runWorkerScheduler(tasks, ossyDir) {
7
10
  const sdk = SDK.of({
8
11
  workspaceId: process.env.OSSY_WORKSPACE_ID,
9
12
  apiUrl: process.env.OSSY_API_URL,
@@ -93,24 +96,22 @@ export function runWorkerScheduler(handlers) {
93
96
  console.log(`Processing ${jobList.length} jobs`)
94
97
  for (const job of jobList) {
95
98
  console.log(`Processing job ${job.id}`)
96
- const handler = handlers.find((h) => h.type === job.type)
99
+ const task = tasks.find((t) => t.type === job.type)
97
100
 
98
- if (!handler) {
101
+ if (!task) {
99
102
  console.log('No handler found for job', job.id)
100
103
  continue
101
104
  }
102
105
 
103
- console.log(`Handler found for ${handler.type}`)
106
+ console.log(`Handler found for ${task.type}`)
104
107
 
105
108
  try {
106
- console.log('create sdk')
109
+ const mod = await import(pathToFileURL(path.resolve(ossyDir, task.module)).href)
107
110
  const jobSdk = SDK.of({
108
111
  workspaceId: job.belongsTo,
109
112
  authorization: process.env.OSSY_API_TOKEN,
110
113
  })
111
- console.log('created sdk')
112
-
113
- await handler.handler({ sdk: jobSdk, job }).catch(() => {})
114
+ await mod.default({ sdk: jobSdk, job }).catch(() => {})
114
115
  } catch (error) {
115
116
  console.error(error)
116
117
  console.log('Failed to processing job')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/app",
3
- "version": "1.12.0",
3
+ "version": "1.13.1",
4
4
  "description": "",
5
5
  "source": "./src/index.js",
6
6
  "main": "./src/index.js",
@@ -27,14 +27,14 @@
27
27
  "@babel/eslint-parser": "^7.15.8",
28
28
  "@babel/preset-react": "^7.26.3",
29
29
  "@babel/register": "^7.25.9",
30
- "@ossy/connected-components": "^1.12.0",
31
- "@ossy/design-system": "^1.12.0",
32
- "@ossy/pages": "^1.12.0",
33
- "@ossy/router": "^1.12.0",
34
- "@ossy/router-react": "^1.12.0",
35
- "@ossy/sdk": "^1.12.0",
36
- "@ossy/sdk-react": "^1.12.0",
37
- "@ossy/themes": "^1.12.0",
30
+ "@ossy/connected-components": "^1.13.1",
31
+ "@ossy/design-system": "^1.13.1",
32
+ "@ossy/pages": "^1.13.1",
33
+ "@ossy/router": "^1.13.1",
34
+ "@ossy/router-react": "^1.13.1",
35
+ "@ossy/sdk": "^1.13.1",
36
+ "@ossy/sdk-react": "^1.13.1",
37
+ "@ossy/themes": "^1.13.1",
38
38
  "@rollup/plugin-alias": "^6.0.0",
39
39
  "@rollup/plugin-babel": "6.1.0",
40
40
  "@rollup/plugin-commonjs": "^29.0.0",
@@ -67,5 +67,5 @@
67
67
  "README.md",
68
68
  "tsconfig.json"
69
69
  ],
70
- "gitHead": "077c0eabe8ef6b8e69e1c3cc03276209fafa76c7"
70
+ "gitHead": "3dcfb2cb94eb920a9cb90f266904bd165772269e"
71
71
  }
@@ -1,22 +0,0 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { fileURLToPath, pathToFileURL } from 'node:url'
4
-
5
- const __ossyDir = path.dirname(fileURLToPath(import.meta.url))
6
-
7
- function normalizeApiExport (mod) {
8
- const d = mod?.default
9
- if (d == null) return []
10
- return Array.isArray(d) ? d : [d]
11
- }
12
-
13
- const { modules } = JSON.parse(fs.readFileSync(path.join(__ossyDir, 'api.bundle.json'), 'utf8'))
14
-
15
- const out = []
16
- for (const rel of modules) {
17
- const abs = path.resolve(__ossyDir, rel)
18
- const mod = await import(pathToFileURL(abs).href)
19
- out.push(...normalizeApiExport(mod))
20
- }
21
-
22
- export default out
@@ -1,14 +0,0 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
-
5
- const __ossyDir = path.dirname(fileURLToPath(import.meta.url))
6
-
7
- function readJson (name) {
8
- return JSON.parse(fs.readFileSync(path.join(__ossyDir, name), 'utf8'))
9
- }
10
-
11
- /** Route list from `pages.generated.json` (includes `module` for lazy `import()` after build). */
12
- const { pages } = readJson('pages.generated.json')
13
-
14
- export default Array.isArray(pages) ? pages : []
@@ -1,22 +0,0 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { fileURLToPath, pathToFileURL } from 'node:url'
4
-
5
- const __ossyDir = path.dirname(fileURLToPath(import.meta.url))
6
-
7
- function normalizeTaskExport (mod) {
8
- const d = mod?.default
9
- if (d == null) return []
10
- return Array.isArray(d) ? d : [d]
11
- }
12
-
13
- const { modules } = JSON.parse(fs.readFileSync(path.join(__ossyDir, 'tasks.bundle.json'), 'utf8'))
14
-
15
- const out = []
16
- for (const rel of modules) {
17
- const abs = path.resolve(__ossyDir, rel)
18
- const mod = await import(pathToFileURL(abs).href)
19
- out.push(...normalizeTaskExport(mod))
20
- }
21
-
22
- export default out