@olenbetong/appframe-vite 6.8.1 → 6.9.0
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 +38 -23
- package/lib/appframeDataGlobal.d.ts +15 -0
- package/lib/appframeDataGlobal.js +2 -2
- package/lib/build.d.ts +34 -1
- package/lib/build.js +111 -4
- package/lib/index.d.ts +3 -2
- package/lib/index.js +27 -3
- package/lib/resourceGenerate.d.ts +2 -0
- package/lib/resourceGenerate.js +1 -1
- package/lib/resourcesConfig.d.ts +6 -0
- package/lib/resourcesConfig.js +1 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -68,12 +68,25 @@ This package reads `package.json.appframe` to know what to proxy and how to buil
|
|
|
68
68
|
"routes": ["^/custom/.*"], // Optional: extra proxied routes
|
|
69
69
|
},
|
|
70
70
|
"build": {
|
|
71
|
-
"
|
|
71
|
+
"platform": true, // Import React and the af packages from the site's platform bundle
|
|
72
|
+
"externals": true, // Legacy: map React and ReactDOM to globals
|
|
72
73
|
},
|
|
73
74
|
},
|
|
74
75
|
}
|
|
75
76
|
```
|
|
76
77
|
|
|
78
|
+
### `build.platform`
|
|
79
|
+
|
|
80
|
+
Apps on the 2026 site templates (`ob.2026.application`) set `"platform": true`. The production
|
|
81
|
+
build then leaves `react`, `react/jsx-runtime`, `react/jsx-dev-runtime`, `react-dom`,
|
|
82
|
+
`react-dom/client`, `@olenbetong/appframe-core` and `@olenbetong/appframe-data` as bare imports,
|
|
83
|
+
which the template's import map resolves to `@olenbetong/synergi-platform` — one cached React
|
|
84
|
+
per page, shared with the site chrome. The `af.data` global redirect (`dataGlobal`) then only
|
|
85
|
+
applies to the dev server, which has no import map. The build also writes `dist/platform.json`
|
|
86
|
+
with the versions the app compiled against; `scripts/app-deploy.ts` refuses to deploy when the
|
|
87
|
+
target article renders no import map or its platform carries other versions (override with
|
|
88
|
+
`--allow-platform-mismatch`).
|
|
89
|
+
|
|
77
90
|
## What it does (at a glance)
|
|
78
91
|
|
|
79
92
|
- Dev server
|
|
@@ -86,7 +99,7 @@ This package reads `package.json.appframe` to know what to proxy and how to buil
|
|
|
86
99
|
- Writes filenames to Appframe paths, using the article ID, e.g.:
|
|
87
100
|
- `file/article/script/<ARTICLE_ID>/main.[hash].min.js`
|
|
88
101
|
- `file/article/style/<ARTICLE_ID>/style.[hash].min.css`
|
|
89
|
-
-
|
|
102
|
+
- With `build.platform`, leaves React and the af packages as bare imports for the template's import map and writes `dist/platform.json`; the legacy `build.externals` maps `react` and `react-dom` to `React` and `ReactDOM` globals instead.
|
|
90
103
|
- Adds a Rollup visualizer report at `dist/stats.html`.
|
|
91
104
|
- Resolve
|
|
92
105
|
- Adds the alias `~/` to `/src/` so imports like `~/components/Button` resolve to `src/components/Button`.
|
|
@@ -240,27 +253,29 @@ procedures:
|
|
|
240
253
|
|
|
241
254
|
**Supported fields per entry:**
|
|
242
255
|
|
|
243
|
-
| Field | Type | Description
|
|
244
|
-
| ------------- | -------------------- |
|
|
245
|
-
| `id` | `string` | Variable name used in generated code (e.g. `dsAccountGroups`)
|
|
246
|
-
| `resource` | `string` | Database object ID (e.g. `atbv_Accounting_SubsidiaryLedgerGroups`)
|
|
247
|
-
| `output` | `string` | Output file path relative to project root
|
|
248
|
-
| `global` | `boolean` | Use `af.data.generateApiDataObject` / `new af.ProcedureAPI` globals
|
|
249
|
-
| `types` | `boolean` | Emit TypeScript type definitions
|
|
250
|
-
| `permissions` | `string` | Permissions: I = insert, U = update, D = delete (e.g. `IUD`)
|
|
251
|
-
| `maxRecords` | `number` | Max records to fetch (default `50`; `-1` for all)
|
|
252
|
-
| `sortOrder` | `string \| string[]` | Sort order, e.g. `Created:Desc` or `[Created:Desc, Name]`
|
|
253
|
-
| `master` | `string` | Master data object name (or `name:importPath`)
|
|
254
|
-
| `linkFields` | `string \| string[]` | Fields linking child to master
|
|
255
|
-
| `expose` | `boolean \| string` | Expose on `af.article.dataObjects` / `af.article.procedures`
|
|
256
|
-
| `dynamic` | `boolean` | Enable dynamic loading
|
|
257
|
-
| `unique` | `string` | Unique table name for update/delete
|
|
258
|
-
| `overrides` | `string \| string[]` | Type overrides, e.g. `MyField:string[]`
|
|
259
|
-
| `distinct` | `boolean` | Fetch distinct rows
|
|
260
|
-
| `aggregates` | `string \| string[]` | Aggregate bindings, e.g. `Qty:SUM`
|
|
261
|
-
| `groupBy` | `string \| string[]` | Group-by fields
|
|
262
|
-
| `where` | `string` | Initial where clause
|
|
263
|
-
| `fields` | `string \| string[]` | Fields to include (all if omitted)
|
|
256
|
+
| Field | Type | Description |
|
|
257
|
+
| ------------- | -------------------- | ------------------------------------------------------------------------------- |
|
|
258
|
+
| `id` | `string` | Variable name used in generated code (e.g. `dsAccountGroups`) |
|
|
259
|
+
| `resource` | `string` | Database object ID (e.g. `atbv_Accounting_SubsidiaryLedgerGroups`) |
|
|
260
|
+
| `output` | `string` | Output file path relative to project root |
|
|
261
|
+
| `global` | `boolean` | Use `af.data.generateApiDataObject` / `new af.ProcedureAPI` globals |
|
|
262
|
+
| `types` | `boolean` | Emit TypeScript type definitions |
|
|
263
|
+
| `permissions` | `string` | Permissions: I = insert, U = update, D = delete (e.g. `IUD`) |
|
|
264
|
+
| `maxRecords` | `number` | Max records to fetch (default `50`; `-1` for all) |
|
|
265
|
+
| `sortOrder` | `string \| string[]` | Sort order, e.g. `Created:Desc` or `[Created:Desc, Name]` |
|
|
266
|
+
| `master` | `string` | Master data object name (or `name:importPath`) |
|
|
267
|
+
| `linkFields` | `string \| string[]` | Fields linking child to master |
|
|
268
|
+
| `expose` | `boolean \| string` | Expose on `af.article.dataObjects` / `af.article.procedures` |
|
|
269
|
+
| `dynamic` | `boolean` | Enable dynamic loading |
|
|
270
|
+
| `unique` | `string` | Unique table name for update/delete |
|
|
271
|
+
| `overrides` | `string \| string[]` | Type overrides, e.g. `MyField:string[]` |
|
|
272
|
+
| `distinct` | `boolean` | Fetch distinct rows |
|
|
273
|
+
| `aggregates` | `string \| string[]` | Aggregate bindings, e.g. `Qty:SUM` |
|
|
274
|
+
| `groupBy` | `string \| string[]` | Group-by fields |
|
|
275
|
+
| `where` | `string` | Initial where clause |
|
|
276
|
+
| `fields` | `string \| string[]` | Fields to include (all if omitted) |
|
|
277
|
+
| `transaction` | `boolean` | Procedures only. `false` stops the framework wrapping the call in a transaction |
|
|
278
|
+
| `timeout` | `number` | Procedures only. Milliseconds before the call is abandoned (default `30000`) |
|
|
264
279
|
|
|
265
280
|
A top-level `server` key can override the hostname (defaults to `appframe.proxy.hostname` from `package.json`).
|
|
266
281
|
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
+
/**
|
|
3
|
+
* Names the framework puts on the `af.data` global. These are the exports shared by
|
|
4
|
+
* `bundle-entries/browser.esm.ts` and `bundle-entries/browser-compat.esm.ts` — which of
|
|
5
|
+
* the two a page loads depends on the user's UserMode, so only names present in *both*
|
|
6
|
+
* are safe to read off the global.
|
|
7
|
+
*/
|
|
8
|
+
export declare const GLOBAL_EXPORTS: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Helpers the `af.data` bundles do not expose, mapped to the module they live in. These
|
|
11
|
+
* are pure functions whose only dependencies on the rest of the package are types, so
|
|
12
|
+
* bundling them creates no second client, data object or event bus — the state that must
|
|
13
|
+
* stay single-instance still comes from the global. Move an entry up to GLOBAL_EXPORTS
|
|
14
|
+
* once the browser bundle entries export it and the new af.data has been deployed.
|
|
15
|
+
*/
|
|
16
|
+
export declare const LOCAL_EXPORTS: Record<string, string[]>;
|
|
2
17
|
/**
|
|
3
18
|
* Redirects imports of `@olenbetong/appframe-data` to the `af.data` global the article
|
|
4
19
|
* already loads.
|
|
@@ -7,7 +7,7 @@ const VIRTUAL_ID = "\0appframe-data-global";
|
|
|
7
7
|
* the two a page loads depends on the user's UserMode, so only names present in *both*
|
|
8
8
|
* are safe to read off the global.
|
|
9
9
|
*/
|
|
10
|
-
const GLOBAL_EXPORTS = [
|
|
10
|
+
export const GLOBAL_EXPORTS = [
|
|
11
11
|
"Client",
|
|
12
12
|
"DataHandler",
|
|
13
13
|
"DataObject",
|
|
@@ -32,7 +32,7 @@ const GLOBAL_EXPORTS = [
|
|
|
32
32
|
* stay single-instance still comes from the global. Move an entry up to GLOBAL_EXPORTS
|
|
33
33
|
* once the browser bundle entries export it and the new af.data has been deployed.
|
|
34
34
|
*/
|
|
35
|
-
const LOCAL_EXPORTS = {
|
|
35
|
+
export const LOCAL_EXPORTS = {
|
|
36
36
|
"formDataToObject.js": ["formDataToDataObjectRecord", "formDataToObject", "formDataToProcedureParameters"],
|
|
37
37
|
"exportDataObject.js": ["exportOptionsFromDataObject", "getDataObjectReportRequest", "openDataObjectReport"],
|
|
38
38
|
"DataHandler.js": ["isRequestError"],
|
package/lib/build.d.ts
CHANGED
|
@@ -1,2 +1,35 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Plugin, type UserConfig } from "vite";
|
|
2
|
+
/**
|
|
3
|
+
* The bare specifiers the 2026 site templates resolve through their import map to the
|
|
4
|
+
* `@olenbetong/synergi-platform` bundle: one React per page, and the `af` packages as
|
|
5
|
+
* shims over the globals the article loads. An app built with `appframe.build.platform`
|
|
6
|
+
* leaves these external and so must run on a template that renders the import map.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PLATFORM_EXTERNALS: string[];
|
|
9
|
+
/**
|
|
10
|
+
* The IIFE global each platform specifier is published under (`buildConfig.entries` in the
|
|
11
|
+
* platform package), for builds that cannot use the import map.
|
|
12
|
+
*/
|
|
13
|
+
export declare const PLATFORM_GLOBALS: Record<string, string>;
|
|
14
|
+
export declare function usesPlatform(appframe: {
|
|
15
|
+
build?: {
|
|
16
|
+
platform?: boolean;
|
|
17
|
+
};
|
|
18
|
+
} | undefined): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* The packages whose version the platform manifest records; an app must match the served
|
|
21
|
+
* platform on every one it has installed.
|
|
22
|
+
*/
|
|
23
|
+
export declare const PLATFORM_UPSTREAM: string[];
|
|
24
|
+
export type PlatformManifest = {
|
|
25
|
+
/** The package versions the app resolved at build time. */
|
|
26
|
+
upstream: Record<string, string>;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Writes `dist/platform.json` after a platform build: the versions of the platform packages the
|
|
30
|
+
* app was compiled against. The deploy script compares it with the manifest of the platform the
|
|
31
|
+
* target site serves, since an app compiled against one React and run on another is a runtime
|
|
32
|
+
* error, not a build error.
|
|
33
|
+
*/
|
|
34
|
+
export declare function platformManifest(): Plugin;
|
|
2
35
|
export declare function addAppframeBuildConfig(config: UserConfig): Promise<UserConfig>;
|
package/lib/build.js
CHANGED
|
@@ -1,7 +1,100 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
3
|
import { resolve } from "node:path";
|
|
3
4
|
import { visualizer } from "rollup-plugin-visualizer";
|
|
5
|
+
import { esmExternalRequirePlugin } from "vite";
|
|
4
6
|
import { importJson } from "./importJson.js";
|
|
7
|
+
/**
|
|
8
|
+
* The bare specifiers the 2026 site templates resolve through their import map to the
|
|
9
|
+
* `@olenbetong/synergi-platform` bundle: one React per page, and the `af` packages as
|
|
10
|
+
* shims over the globals the article loads. An app built with `appframe.build.platform`
|
|
11
|
+
* leaves these external and so must run on a template that renders the import map.
|
|
12
|
+
*/
|
|
13
|
+
export const PLATFORM_EXTERNALS = [
|
|
14
|
+
"react",
|
|
15
|
+
"react/jsx-runtime",
|
|
16
|
+
"react/jsx-dev-runtime",
|
|
17
|
+
"react-dom",
|
|
18
|
+
"react-dom/client",
|
|
19
|
+
"react-router",
|
|
20
|
+
"@digdir/designsystemet-web",
|
|
21
|
+
"@digdir/designsystemet-react",
|
|
22
|
+
"@olenbetong/appframe-core",
|
|
23
|
+
"@olenbetong/appframe-data",
|
|
24
|
+
"@olenbetong/appframe-react",
|
|
25
|
+
"@olenbetong/appframe-ds",
|
|
26
|
+
"@olenbetong/appframe-ds/grid",
|
|
27
|
+
"@olenbetong/appframe-ds/mdi",
|
|
28
|
+
"@olenbetong/appframe-ds/progress",
|
|
29
|
+
"@olenbetong/appframe-ds/report-downloader",
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* The IIFE global each platform specifier is published under (`buildConfig.entries` in the
|
|
33
|
+
* platform package), for builds that cannot use the import map.
|
|
34
|
+
*/
|
|
35
|
+
export const PLATFORM_GLOBALS = {
|
|
36
|
+
react: "React",
|
|
37
|
+
"react/jsx-runtime": "ReactJSXRuntime",
|
|
38
|
+
"react/jsx-dev-runtime": "ReactJSXDevRuntime",
|
|
39
|
+
"react-dom": "ReactDOM",
|
|
40
|
+
"react-dom/client": "ReactDOMClient",
|
|
41
|
+
"react-router": "ReactRouter",
|
|
42
|
+
"@digdir/designsystemet-web": "Designsystemet.web",
|
|
43
|
+
"@digdir/designsystemet-react": "Designsystemet.react",
|
|
44
|
+
"@olenbetong/appframe-core": "SynergiPlatform.appframeCore",
|
|
45
|
+
"@olenbetong/appframe-data": "SynergiPlatform.appframeData",
|
|
46
|
+
"@olenbetong/appframe-react": "SynergiPlatform.appframeReact",
|
|
47
|
+
"@olenbetong/appframe-ds": "SynergiPlatform.appframeDs",
|
|
48
|
+
"@olenbetong/appframe-ds/grid": "SynergiPlatform.appframeDsGrid",
|
|
49
|
+
"@olenbetong/appframe-ds/mdi": "SynergiPlatform.appframeDsMdi",
|
|
50
|
+
"@olenbetong/appframe-ds/progress": "SynergiPlatform.appframeDsProgress",
|
|
51
|
+
"@olenbetong/appframe-ds/report-downloader": "SynergiPlatform.appframeDsReportDownloader",
|
|
52
|
+
};
|
|
53
|
+
export function usesPlatform(appframe) {
|
|
54
|
+
return appframe?.build?.platform === true;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The packages whose version the platform manifest records; an app must match the served
|
|
58
|
+
* platform on every one it has installed.
|
|
59
|
+
*/
|
|
60
|
+
export const PLATFORM_UPSTREAM = [
|
|
61
|
+
"react",
|
|
62
|
+
"react-dom",
|
|
63
|
+
"react-router",
|
|
64
|
+
"@digdir/designsystemet-react",
|
|
65
|
+
"@digdir/designsystemet-web",
|
|
66
|
+
"@digdir/designsystemet-css",
|
|
67
|
+
"@olenbetong/appframe-core",
|
|
68
|
+
"@olenbetong/appframe-data",
|
|
69
|
+
"@olenbetong/appframe-react",
|
|
70
|
+
"@olenbetong/appframe-ds",
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* Writes `dist/platform.json` after a platform build: the versions of the platform packages the
|
|
74
|
+
* app was compiled against. The deploy script compares it with the manifest of the platform the
|
|
75
|
+
* target site serves, since an app compiled against one React and run on another is a runtime
|
|
76
|
+
* error, not a build error.
|
|
77
|
+
*/
|
|
78
|
+
export function platformManifest() {
|
|
79
|
+
return {
|
|
80
|
+
name: "appframe:platform-manifest",
|
|
81
|
+
apply: "build",
|
|
82
|
+
async writeBundle() {
|
|
83
|
+
let manifest = { upstream: {} };
|
|
84
|
+
for (let name of PLATFORM_UPSTREAM) {
|
|
85
|
+
let file = resolve(process.cwd(), "node_modules", name, "package.json");
|
|
86
|
+
try {
|
|
87
|
+
manifest.upstream[name] = JSON.parse(await readFile(file, "utf8")).version;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Not every app depends on every platform package (an app without a grid has no
|
|
91
|
+
// appframe-ds, say); only what the app resolved is recorded and checked.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
await writeFile(resolve(process.cwd(), "dist", "platform.json"), `${JSON.stringify(manifest, null, "\t")}\n`);
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
5
98
|
export async function addAppframeBuildConfig(config) {
|
|
6
99
|
let appPkg = await importJson("./package.json", true);
|
|
7
100
|
let { appframe } = appPkg;
|
|
@@ -22,9 +115,21 @@ export async function addAppframeBuildConfig(config) {
|
|
|
22
115
|
config.appType = "custom";
|
|
23
116
|
config.build.rolldownOptions = {
|
|
24
117
|
input: { main: entry },
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
118
|
+
plugins: [
|
|
119
|
+
// Cast visualizer plugin to any to avoid Rollup type version clashes
|
|
120
|
+
visualizer({ filename: "./dist/stats.html", gzipSize: true }),
|
|
121
|
+
// The platform set stays external through this plugin rather than the top-level
|
|
122
|
+
// `external`: CommonJS dependencies in the app (MUI X, exceljs) `require("react")`, and
|
|
123
|
+
// only the plugin turns those requires into imports the import map can resolve. A
|
|
124
|
+
// plain external leaves a `require` shim that throws in the browser. The plugin must
|
|
125
|
+
// own the list, so the externals are not repeated below.
|
|
126
|
+
...(usesPlatform(appframe) ? [esmExternalRequirePlugin({ external: PLATFORM_EXTERNALS })] : []),
|
|
127
|
+
],
|
|
128
|
+
external: usesPlatform(appframe)
|
|
129
|
+
? []
|
|
130
|
+
: appframe.build.externals !== false
|
|
131
|
+
? ["react", "react-dom", "react-dom/client"]
|
|
132
|
+
: [],
|
|
28
133
|
treeshake: {
|
|
29
134
|
/*
|
|
30
135
|
* `@digdir/designsystemet-react` does not declare `sideEffects: false`, so the
|
|
@@ -39,7 +144,9 @@ export async function addAppframeBuildConfig(config) {
|
|
|
39
144
|
moduleSideEffects: (id) => !/[\\/]node_modules[\\/].*designsystemet-react[\\/]/.test(id.replace(/\?.*$/, "")),
|
|
40
145
|
},
|
|
41
146
|
output: {
|
|
42
|
-
|
|
147
|
+
// Platform builds keep the bare specifiers (ESM, resolved by the import map); the old
|
|
148
|
+
// externals mode maps them to window globals instead.
|
|
149
|
+
globals: !usesPlatform(appframe) && appframe.build.externals !== false
|
|
43
150
|
? {
|
|
44
151
|
react: "React",
|
|
45
152
|
"react-dom": "ReactDOM",
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import { appframeDataGlobal } from "./appframeDataGlobal.js";
|
|
3
|
-
import { addAppframeBuildConfig } from "./build.js";
|
|
3
|
+
import { addAppframeBuildConfig, PLATFORM_EXTERNALS, PLATFORM_GLOBALS, PLATFORM_UPSTREAM, platformManifest, usesPlatform } from "./build.js";
|
|
4
4
|
import { createDevMiddleware } from "./devServer.js";
|
|
5
5
|
import { publishSafeOutput } from "./publishSafeOutput.js";
|
|
6
6
|
export interface AppframePluginOptions {
|
|
@@ -32,6 +32,7 @@ export interface AppframePluginOptions {
|
|
|
32
32
|
dataGlobal?: boolean;
|
|
33
33
|
}
|
|
34
34
|
export default function appframe(options?: AppframePluginOptions): Plugin[];
|
|
35
|
-
export { addAppframeBuildConfig, appframeDataGlobal, createDevMiddleware, publishSafeOutput };
|
|
35
|
+
export { addAppframeBuildConfig, appframeDataGlobal, createDevMiddleware, PLATFORM_EXTERNALS, PLATFORM_GLOBALS, PLATFORM_UPSTREAM, platformManifest, publishSafeOutput, usesPlatform, };
|
|
36
|
+
export type { PlatformManifest } from "./build.js";
|
|
36
37
|
export { DEVTOOLS_API_VERSION, type DevtoolsDiscovery, type DevtoolsServerInfo } from "./devtoolsServer.js";
|
|
37
38
|
export type { JobOptions, ReleaseEvent, ReleaseScriptEvent, ReleaseSnapshot, ReleaseStep } from "./releaseServer.js";
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { resolve } from "node:path";
|
|
2
3
|
import bodyParser from "body-parser";
|
|
3
4
|
import { watch } from "chokidar";
|
|
4
5
|
import { appframeDataGlobal } from "./appframeDataGlobal.js";
|
|
5
|
-
import { addAppframeBuildConfig } from "./build.js";
|
|
6
|
+
import { addAppframeBuildConfig, PLATFORM_EXTERNALS, PLATFORM_GLOBALS, PLATFORM_UPSTREAM, platformManifest, usesPlatform, } from "./build.js";
|
|
6
7
|
import { generateFromConfig } from "./cli-resources-generate.js";
|
|
7
8
|
import { createDevMiddleware, getLoginInfo, getProxyRoutes } from "./devServer.js";
|
|
8
9
|
import { createDevtoolsMiddleware } from "./devtoolsServer.js";
|
|
@@ -240,7 +241,30 @@ export default function appframe(options = {}) {
|
|
|
240
241
|
};
|
|
241
242
|
},
|
|
242
243
|
};
|
|
243
|
-
|
|
244
|
+
let plugins = [plugin, publishSafeOutput()];
|
|
245
|
+
let platform = usesPlatform(readAppframeConfig());
|
|
246
|
+
if (platform) {
|
|
247
|
+
plugins.push(platformManifest());
|
|
248
|
+
}
|
|
249
|
+
if (dataGlobal) {
|
|
250
|
+
// An app built against the platform leaves `@olenbetong/appframe-data` as a bare
|
|
251
|
+
// specifier for the import map, so the global redirect only applies to the dev server
|
|
252
|
+
// (which has no import map) and to builds that bundle their own runtime.
|
|
253
|
+
plugins.unshift({
|
|
254
|
+
...appframeDataGlobal(),
|
|
255
|
+
apply: (_config, env) => env.command === "serve" || !platform,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return plugins;
|
|
244
259
|
}
|
|
245
|
-
|
|
260
|
+
/** The `appframe` section of the app's package.json, read synchronously at plugin creation. */
|
|
261
|
+
function readAppframeConfig() {
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(readFileSync(resolve(process.cwd(), "package.json"), "utf8")).appframe;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
export { addAppframeBuildConfig, appframeDataGlobal, createDevMiddleware, PLATFORM_EXTERNALS, PLATFORM_GLOBALS, PLATFORM_UPSTREAM, platformManifest, publishSafeOutput, usesPlatform, };
|
|
246
270
|
export { DEVTOOLS_API_VERSION } from "./devtoolsServer.js";
|
|
@@ -9,6 +9,8 @@ export declare function writeGeneratedFile(filePath: string, content: string): P
|
|
|
9
9
|
export type CLIOptions = {
|
|
10
10
|
/** Procedures only. `false` stops the framework wrapping the call in a transaction. */
|
|
11
11
|
transaction?: boolean;
|
|
12
|
+
/** Procedures only. Milliseconds before the call is abandoned; the generated default is 30000. */
|
|
13
|
+
timeout?: number;
|
|
12
14
|
server: string;
|
|
13
15
|
types?: boolean;
|
|
14
16
|
global: boolean;
|
package/lib/resourceGenerate.js
CHANGED
|
@@ -305,7 +305,7 @@ export function getProcedureDefinition(name, procDefinition, options) {
|
|
|
305
305
|
output.push(`export const ${procName} = new ${options.global ? "af." : ""}ProcedureAPI${options.types ? `<${paramTypeName}, ${options.typesJsonReturnType ?? "{ Table?: unknown[] }"}>` : ""}({
|
|
306
306
|
procedureId: "${name}",
|
|
307
307
|
parameters: ${JSON.stringify(parameters, null, 2)},
|
|
308
|
-
timeout: 30000${options.transaction === false ? ",\n transaction: false" : ""}
|
|
308
|
+
timeout: ${options.timeout ?? 30000}${options.transaction === false ? ",\n transaction: false" : ""}
|
|
309
309
|
});`);
|
|
310
310
|
if (options.expose) {
|
|
311
311
|
output.push("");
|
package/lib/resourcesConfig.d.ts
CHANGED
|
@@ -37,6 +37,12 @@ export type ResourceEntry = {
|
|
|
37
37
|
* remote write a distributed one, which fails without MSDTC configured between the servers.
|
|
38
38
|
*/
|
|
39
39
|
transaction?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Procedures only. Milliseconds the call may take before it is abandoned, client and server
|
|
42
|
+
* alike (default `30000`). For a procedure that reads across a linked server or scans a large
|
|
43
|
+
* table, where a preview alone can take a minute.
|
|
44
|
+
*/
|
|
45
|
+
timeout?: number;
|
|
40
46
|
/** Permissions to set: I = insert, U = update, D = delete (e.g. `IUD`) */
|
|
41
47
|
permissions?: string;
|
|
42
48
|
/** Maximum records to fetch (default `50`; use `-1` for all) */
|
package/lib/resourcesConfig.js
CHANGED
|
@@ -98,6 +98,7 @@ export function entryToCLIOptions(entry, hostname) {
|
|
|
98
98
|
dynamic: entry.dynamic ?? false,
|
|
99
99
|
types: entry.types,
|
|
100
100
|
transaction: entry.transaction,
|
|
101
|
+
timeout: entry.timeout,
|
|
101
102
|
maxRecords: entry.maxRecords !== undefined ? String(entry.maxRecords) : "50",
|
|
102
103
|
sortOrder: sortOrderToString(entry.sortOrder),
|
|
103
104
|
permissions: entry.permissions,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-vite",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "Tools to use and deploy Vite applications to Appframe",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
"inquirer-autocomplete-standalone": "^0.8.1",
|
|
40
40
|
"jsdom": "30.0.1",
|
|
41
41
|
"rollup-plugin-visualizer": "^7.1.1",
|
|
42
|
-
"yaml": "^2.9.
|
|
43
|
-
"@olenbetong/appframe-data": "1.7.
|
|
42
|
+
"yaml": "^2.9.1",
|
|
43
|
+
"@olenbetong/appframe-data": "1.7.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/jsdom": "^30.0.0",
|
|
47
47
|
"@types/node": "26.5.1",
|
|
48
48
|
"typescript": "7.0.2",
|
|
49
|
-
"vite": "8.
|
|
49
|
+
"vite": "8.3.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"vite": ">=8.1.5"
|