@agimon-ai/doompi-build 0.0.1-alpha.2

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.
Files changed (140) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +82 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  4. package/dist/browserFile.cjs +1 -0
  5. package/dist/browserFile.d.cts +2 -0
  6. package/dist/browserFile.d.mts +2 -0
  7. package/dist/browserFile.mjs +1 -0
  8. package/dist/constants/contributions.cjs +2 -0
  9. package/dist/constants/contributions.cjs.map +1 -0
  10. package/dist/constants/contributions.mjs +2 -0
  11. package/dist/constants/contributions.mjs.map +1 -0
  12. package/dist/constants/layout.cjs +2 -0
  13. package/dist/constants/layout.cjs.map +1 -0
  14. package/dist/constants/layout.d.cts +59 -0
  15. package/dist/constants/layout.d.cts.map +1 -0
  16. package/dist/constants/layout.d.mts +59 -0
  17. package/dist/constants/layout.d.mts.map +1 -0
  18. package/dist/constants/layout.mjs +2 -0
  19. package/dist/constants/layout.mjs.map +1 -0
  20. package/dist/index.cjs +1 -0
  21. package/dist/index.d.cts +16 -0
  22. package/dist/index.d.mts +16 -0
  23. package/dist/index.mjs +1 -0
  24. package/dist/services/browserFile/index.cjs +2 -0
  25. package/dist/services/browserFile/index.cjs.map +1 -0
  26. package/dist/services/browserFile/index.d.cts +28 -0
  27. package/dist/services/browserFile/index.d.cts.map +1 -0
  28. package/dist/services/browserFile/index.d.mts +28 -0
  29. package/dist/services/browserFile/index.d.mts.map +1 -0
  30. package/dist/services/browserFile/index.mjs +2 -0
  31. package/dist/services/browserFile/index.mjs.map +1 -0
  32. package/dist/services/filename/index.cjs +2 -0
  33. package/dist/services/filename/index.cjs.map +1 -0
  34. package/dist/services/filename/index.d.cts +29 -0
  35. package/dist/services/filename/index.d.cts.map +1 -0
  36. package/dist/services/filename/index.d.mts +29 -0
  37. package/dist/services/filename/index.d.mts.map +1 -0
  38. package/dist/services/filename/index.mjs +2 -0
  39. package/dist/services/filename/index.mjs.map +1 -0
  40. package/dist/services/generate/index.cjs +2 -0
  41. package/dist/services/generate/index.cjs.map +1 -0
  42. package/dist/services/generate/index.d.cts +15 -0
  43. package/dist/services/generate/index.d.cts.map +1 -0
  44. package/dist/services/generate/index.d.mts +15 -0
  45. package/dist/services/generate/index.d.mts.map +1 -0
  46. package/dist/services/generate/index.mjs +2 -0
  47. package/dist/services/generate/index.mjs.map +1 -0
  48. package/dist/services/generate/type.d.cts +26 -0
  49. package/dist/services/generate/type.d.cts.map +1 -0
  50. package/dist/services/generate/type.d.mts +26 -0
  51. package/dist/services/generate/type.d.mts.map +1 -0
  52. package/dist/services/identity/index.cjs +2 -0
  53. package/dist/services/identity/index.cjs.map +1 -0
  54. package/dist/services/identity/index.mjs +2 -0
  55. package/dist/services/identity/index.mjs.map +1 -0
  56. package/dist/services/renderClient/index.cjs +3 -0
  57. package/dist/services/renderClient/index.cjs.map +1 -0
  58. package/dist/services/renderClient/index.mjs +3 -0
  59. package/dist/services/renderClient/index.mjs.map +1 -0
  60. package/dist/services/renderEntry/index.cjs +7 -0
  61. package/dist/services/renderEntry/index.cjs.map +1 -0
  62. package/dist/services/renderEntry/index.d.cts +24 -0
  63. package/dist/services/renderEntry/index.d.cts.map +1 -0
  64. package/dist/services/renderEntry/index.d.mts +24 -0
  65. package/dist/services/renderEntry/index.d.mts.map +1 -0
  66. package/dist/services/renderEntry/index.mjs +7 -0
  67. package/dist/services/renderEntry/index.mjs.map +1 -0
  68. package/dist/services/renderEntry/type.d.cts +14 -0
  69. package/dist/services/renderEntry/type.d.cts.map +1 -0
  70. package/dist/services/renderEntry/type.d.mts +14 -0
  71. package/dist/services/renderEntry/type.d.mts.map +1 -0
  72. package/dist/services/resolveTarget/index.cjs +2 -0
  73. package/dist/services/resolveTarget/index.cjs.map +1 -0
  74. package/dist/services/resolveTarget/index.d.cts +16 -0
  75. package/dist/services/resolveTarget/index.d.cts.map +1 -0
  76. package/dist/services/resolveTarget/index.d.mts +16 -0
  77. package/dist/services/resolveTarget/index.d.mts.map +1 -0
  78. package/dist/services/resolveTarget/index.mjs +2 -0
  79. package/dist/services/resolveTarget/index.mjs.map +1 -0
  80. package/dist/services/resolveTarget/type.d.cts +34 -0
  81. package/dist/services/resolveTarget/type.d.cts.map +1 -0
  82. package/dist/services/resolveTarget/type.d.mts +34 -0
  83. package/dist/services/resolveTarget/type.d.mts.map +1 -0
  84. package/dist/services/scan/index.cjs +2 -0
  85. package/dist/services/scan/index.cjs.map +1 -0
  86. package/dist/services/scan/index.d.cts +19 -0
  87. package/dist/services/scan/index.d.cts.map +1 -0
  88. package/dist/services/scan/index.d.mts +19 -0
  89. package/dist/services/scan/index.d.mts.map +1 -0
  90. package/dist/services/scan/index.mjs +2 -0
  91. package/dist/services/scan/index.mjs.map +1 -0
  92. package/dist/services/scan/type.d.cts +25 -0
  93. package/dist/services/scan/type.d.cts.map +1 -0
  94. package/dist/services/scan/type.d.mts +25 -0
  95. package/dist/services/scan/type.d.mts.map +1 -0
  96. package/dist/services/segments/index.cjs +2 -0
  97. package/dist/services/segments/index.cjs.map +1 -0
  98. package/dist/services/segments/index.d.cts +26 -0
  99. package/dist/services/segments/index.d.cts.map +1 -0
  100. package/dist/services/segments/index.d.mts +26 -0
  101. package/dist/services/segments/index.d.mts.map +1 -0
  102. package/dist/services/segments/index.mjs +2 -0
  103. package/dist/services/segments/index.mjs.map +1 -0
  104. package/dist/services/syncManifest/index.cjs +2 -0
  105. package/dist/services/syncManifest/index.cjs.map +1 -0
  106. package/dist/services/syncManifest/index.d.cts +21 -0
  107. package/dist/services/syncManifest/index.d.cts.map +1 -0
  108. package/dist/services/syncManifest/index.d.mts +21 -0
  109. package/dist/services/syncManifest/index.d.mts.map +1 -0
  110. package/dist/services/syncManifest/index.mjs +2 -0
  111. package/dist/services/syncManifest/index.mjs.map +1 -0
  112. package/dist/services/syncManifest/type.d.cts +15 -0
  113. package/dist/services/syncManifest/type.d.cts.map +1 -0
  114. package/dist/services/syncManifest/type.d.mts +15 -0
  115. package/dist/services/syncManifest/type.d.mts.map +1 -0
  116. package/dist/services/tsdownPreset/index.cjs +2 -0
  117. package/dist/services/tsdownPreset/index.cjs.map +1 -0
  118. package/dist/services/tsdownPreset/index.d.cts +63 -0
  119. package/dist/services/tsdownPreset/index.d.cts.map +1 -0
  120. package/dist/services/tsdownPreset/index.d.mts +63 -0
  121. package/dist/services/tsdownPreset/index.d.mts.map +1 -0
  122. package/dist/services/tsdownPreset/index.mjs +2 -0
  123. package/dist/services/tsdownPreset/index.mjs.map +1 -0
  124. package/dist/services/writeGenerated/index.cjs +2 -0
  125. package/dist/services/writeGenerated/index.cjs.map +1 -0
  126. package/dist/services/writeGenerated/index.d.cts +23 -0
  127. package/dist/services/writeGenerated/index.d.cts.map +1 -0
  128. package/dist/services/writeGenerated/index.d.mts +23 -0
  129. package/dist/services/writeGenerated/index.d.mts.map +1 -0
  130. package/dist/services/writeGenerated/index.mjs +2 -0
  131. package/dist/services/writeGenerated/index.mjs.map +1 -0
  132. package/dist/tsdown.cjs +1 -0
  133. package/dist/tsdown.d.cts +2 -0
  134. package/dist/tsdown.d.mts +2 -0
  135. package/dist/tsdown.mjs +1 -0
  136. package/dist/types/extensionGraph.d.cts +75 -0
  137. package/dist/types/extensionGraph.d.cts.map +1 -0
  138. package/dist/types/extensionGraph.d.mts +75 -0
  139. package/dist/types/extensionGraph.d.mts.map +1 -0
  140. package/package.json +72 -0
@@ -0,0 +1,21 @@
1
+ import { BuildTarget } from "../resolveTarget/type.mjs";
2
+ import { ManifestSync } from "./type.mjs";
3
+ //#region src/services/syncManifest/index.d.ts
4
+ /**
5
+ * Everything the manifest can say about a package that its tree already says.
6
+ *
7
+ * The three host blocks are pure restatements of the folder tree: which hosts
8
+ * the package contributes to, at which scopes, and which frame types the
9
+ * browser claims. Leaving them hand-written is what made a package declare the
10
+ * same thing in six places, so the build writes them.
11
+ *
12
+ * Returns the manifest rather than writing it, so a caller can diff it and a
13
+ * test can read it without a filesystem.
14
+ */
15
+ export declare function syncManifest(input: ManifestSync): Record<string, unknown>;
16
+ /** Writes the synced manifest when it differs, so a second build is a no-op. */
17
+ export declare function writeManifest(input: ManifestSync & {
18
+ readonly targets: readonly BuildTarget[];
19
+ }): boolean;
20
+ //#endregion
21
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/syncManifest/index.ts"],"mappings":";;;;;;;;;;;;;;wBA+FgB,aAAa,OAAO,eAAe;;wBAqDnC,cAAc,OAAO;WAA0B,kBAAkB"}
@@ -0,0 +1,2 @@
1
+ import{GENERATED_DIR as e}from"../../constants/layout.mjs";import{toSnake as t}from"../identity/index.mjs";import n from"node:fs";import r from"node:path";const i=[`global`,`workspace`,`session`],a=`src/exports/apiContracts.ts`,o=`./extensions/web`,s=`./dist/extensions/web.mjs`;function c(e){let t=e.entries.filter(e=>e.side===`backend`);if(t.length===0)return[];let n=Math.min(...t.map(e=>i.indexOf(e.scope)));return i.slice(n)}function l(e){let t=new Set(e.entries.filter(e=>e.side===`frontend`).map(e=>e.scope));return i.filter(e=>t.has(e))}function u(e,n){return[...new Set(e.entries.filter(e=>e.side===`frontend`&&e.surface===`channel`).map(e=>t(e.name)))].sort()}function d(e,t){let i={};for(let[a,o]of Object.entries(t)){if(a===`./package.json`||typeof o!=`object`||!o){i[a]=o;continue}let t=o,s=t.import??t.default,c=s?.endsWith(`.mjs`)===!0?`${s.slice(0,-4)}.d.mts`:void 0;i[a]=t.types===void 0&&c!==void 0&&n.existsSync(r.join(e,c))?{types:c,...t}:t}return i}function f(t){let{packageDir:i,graph:f,targets:p,pluginId:m}=t,h={...t.manifest};if(h.exports!==void 0&&typeof h.exports==`object`){let e=d(i,h.exports);p.includes(`web`)?e[o]={import:s}:delete e[o],h.exports=Object.fromEntries(Object.entries(e).sort(([e],[t])=>e===`./package.json`?1:t===`./package.json`?-1:e.localeCompare(t)))}if(p.includes(`cli`)?h.pi={extensions:[`./dist/extensions/pi.mjs`]}:delete h.pi,p.includes(`server`)){let t=n.existsSync(r.join(i,a))?{contracts:{entry:`./${a}`,dist:`./dist/api-contracts.mjs`}}:{};h.doompiServer={entry:`./${e}/server.ts`,dist:`./dist/extensions/server.mjs`,scopes:c(f),...t}}else delete h.doompiServer;return p.includes(`web`)?h.doompiWeb={pluginId:m,channels:u(f,h),client:s,scopes:l(f)}:delete h.doompiWeb,h}function p(e){let t=r.join(e.packageDir,`package.json`),i=`${JSON.stringify(f(e),null,2)}\n`;return n.readFileSync(t,`utf8`)!==i&&(n.writeFileSync(t,i),!0)}export{f as syncManifest,p as writeManifest};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/services/syncManifest/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { GENERATED_DIR } from '../../constants/layout';\nimport type { ExtensionGraph, ExtensionScope } from '../../types/extensionGraph';\nimport { toSnake } from '../identity';\nimport type { BuildTarget } from '../resolveTarget/type';\nimport type { ManifestSync } from './type';\n\nconst SCOPE_ORDER: readonly ExtensionScope[] = ['global', 'workspace', 'session'];\n\nconst API_CONTRACTS_SOURCE = 'src/exports/apiContracts.ts';\nconst API_CONTRACTS_DIST = './dist/api-contracts.mjs';\n\nconst WEB_EXPORT = './extensions/web';\nconst WEB_DIST = './dist/extensions/web.mjs';\n\n/**\n * Which scopes a server facet declares.\n *\n * The generated facet cascades: a contribution declared at global registers at\n * global, workspace and session alike, because the server reads exactly one\n * scope declaration and nothing above it. So the declared set runs from the\n * shallowest contribution downward.\n */\nfunction serverScopes(graph: ExtensionGraph): ExtensionScope[] {\n const declared = graph.entries.filter((entry) => entry.side === 'backend');\n if (declared.length === 0) return [];\n const shallowest = Math.min(...declared.map((entry) => SCOPE_ORDER.indexOf(entry.scope)));\n return SCOPE_ORDER.slice(shallowest);\n}\n\n/**\n * Which scopes a cockpit plugin declares.\n *\n * The cockpit does not cascade the way the server does. It merges the scopes\n * it is given, so a plugin declares exactly the ones it contributes to.\n */\nfunction webScopes(graph: ExtensionGraph): ExtensionScope[] {\n const declared = new Set(graph.entries.filter((entry) => entry.side === 'frontend').map((entry) => entry.scope));\n return SCOPE_ORDER.filter((scope) => declared.has(scope));\n}\n\n/** The frame types the browser half claims, which the cockpit reads before loading it. */\nfunction channels(graph: ExtensionGraph, _manifest: Record<string, unknown>): string[] {\n return [\n ...new Set(\n graph.entries\n .filter((entry) => entry.side === 'frontend' && entry.surface === 'channel')\n .map((entry) => toSnake(entry.name)),\n ),\n ].sort();\n}\n\n/**\n * Restores the `types` condition tsdown's exports generation omits.\n *\n * tsdown derives the map from the built chunks, which is what makes it follow\n * the folder tree. But its `genSubExport` only ever emits `import`, `require`\n * or `default`: a declaration chunk contributes nothing to a subpath, so only\n * the root gets a top-level `types`. TypeScript still resolves a sibling\n * `.d.mts` under node16 and bundler resolution, but publint and attw read the\n * condition, so it belongs in the map.\n */\nfunction withTypeConditions(packageDir: string, exportsMap: Record<string, unknown>): Record<string, unknown> {\n const next: Record<string, unknown> = {};\n for (const [subpath, target] of Object.entries(exportsMap)) {\n if (subpath === './package.json' || target === null || typeof target !== 'object') {\n next[subpath] = target;\n continue;\n }\n const conditions = target as Record<string, string>;\n const esm = conditions.import ?? conditions.default;\n const types = esm?.endsWith('.mjs') === true ? `${esm.slice(0, -'.mjs'.length)}.d.mts` : undefined;\n // Ahead of import and require: a resolver takes the first condition it\n // matches, so a types-aware one must not fall through to the runtime file.\n next[subpath] =\n conditions.types === undefined && types !== undefined && fs.existsSync(path.join(packageDir, types))\n ? { types, ...conditions }\n : conditions;\n }\n return next;\n}\n\n/**\n * Everything the manifest can say about a package that its tree already says.\n *\n * The three host blocks are pure restatements of the folder tree: which hosts\n * the package contributes to, at which scopes, and which frame types the\n * browser claims. Leaving them hand-written is what made a package declare the\n * same thing in six places, so the build writes them.\n *\n * Returns the manifest rather than writing it, so a caller can diff it and a\n * test can read it without a filesystem.\n */\nexport function syncManifest(input: ManifestSync): Record<string, unknown> {\n const { packageDir, graph, targets, pluginId } = input;\n const manifest = { ...input.manifest };\n\n if (manifest.exports !== undefined && typeof manifest.exports === 'object') {\n const exportsMap = withTypeConditions(packageDir, manifest.exports as Record<string, unknown>);\n // The browser bundle is a real entry point now that it is built rather\n // than shipped as source, so it is exported like the other two. Import\n // only: its own config emits ESM and no declarations, because nothing\n // imports it as a typed module.\n //\n // Added from the target rather than from the file existing, because this\n // runs on the node build's build:done and the browser build follows it.\n if (targets.includes('web')) exportsMap[WEB_EXPORT] = { import: WEB_DIST };\n else delete exportsMap[WEB_EXPORT];\n manifest.exports = Object.fromEntries(\n Object.entries(exportsMap).sort(([left], [right]) =>\n left === './package.json' ? 1 : right === './package.json' ? -1 : left.localeCompare(right),\n ),\n );\n }\n\n if (targets.includes('cli')) manifest.pi = { extensions: ['./dist/extensions/pi.mjs'] };\n else delete manifest.pi;\n\n if (targets.includes('server')) {\n const contracts = fs.existsSync(path.join(packageDir, API_CONTRACTS_SOURCE))\n ? { contracts: { entry: `./${API_CONTRACTS_SOURCE}`, dist: API_CONTRACTS_DIST } }\n : {};\n manifest.doompiServer = {\n entry: `./${GENERATED_DIR}/server.ts`,\n dist: './dist/extensions/server.mjs',\n scopes: serverScopes(graph),\n ...contracts,\n };\n } else delete manifest.doompiServer;\n\n if (targets.includes('web')) {\n manifest.doompiWeb = {\n pluginId,\n channels: channels(graph, manifest),\n // The built browser bundle, not the source. Its own tsdown config\n // targets a browser and leaves every bare specifier external, so the\n // cockpit resolves one React rather than bundling a copy per plugin.\n client: WEB_DIST,\n scopes: webScopes(graph),\n };\n } else delete manifest.doompiWeb;\n\n return manifest;\n}\n\n/** Writes the synced manifest when it differs, so a second build is a no-op. */\nexport function writeManifest(input: ManifestSync & { readonly targets: readonly BuildTarget[] }): boolean {\n const manifestPath = path.join(input.packageDir, 'package.json');\n const next = `${JSON.stringify(syncManifest(input), null, 2)}\\n`;\n if (fs.readFileSync(manifestPath, 'utf8') === next) return false;\n fs.writeFileSync(manifestPath, next);\n return true;\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { ExtensionGraph } from "../../types/extensionGraph.cjs";
2
+ import { BuildTarget } from "../resolveTarget/type.cjs";
3
+ //#region src/services/syncManifest/type.d.ts
4
+ /** Everything deriving a manifest needs, so nothing has to rescan. */
5
+ export interface ManifestSync {
6
+ readonly packageDir: string;
7
+ /** The manifest as read, which the sync returns a copy of. */
8
+ readonly manifest: Record<string, unknown>;
9
+ readonly graph: ExtensionGraph;
10
+ /** Hosts this package contributes to, as the generator resolved them. */
11
+ readonly targets: readonly BuildTarget[];
12
+ readonly pluginId: string;
13
+ }
14
+ //#endregion
15
+ //# sourceMappingURL=type.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type.d.cts","names":[],"sources":["../../../src/services/syncManifest/type.ts"],"mappings":";;;;iBAIiB;WACN;;WAEA,UAAU;WACV,OAAO;;WAEP,kBAAkB;WAClB"}
@@ -0,0 +1,15 @@
1
+ import { ExtensionGraph } from "../../types/extensionGraph.mjs";
2
+ import { BuildTarget } from "../resolveTarget/type.mjs";
3
+ //#region src/services/syncManifest/type.d.ts
4
+ /** Everything deriving a manifest needs, so nothing has to rescan. */
5
+ export interface ManifestSync {
6
+ readonly packageDir: string;
7
+ /** The manifest as read, which the sync returns a copy of. */
8
+ readonly manifest: Record<string, unknown>;
9
+ readonly graph: ExtensionGraph;
10
+ /** Hosts this package contributes to, as the generator resolved them. */
11
+ readonly targets: readonly BuildTarget[];
12
+ readonly pluginId: string;
13
+ }
14
+ //#endregion
15
+ //# sourceMappingURL=type.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type.d.mts","names":[],"sources":["../../../src/services/syncManifest/type.ts"],"mappings":";;;;iBAIiB;WACN;;WAEA,UAAU;WACV,OAAO;;WAEP,kBAAkB;WAClB"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../constants/layout.cjs"),n=require("../identity/index.cjs"),r=require("../generate/index.cjs"),i=require("../syncManifest/index.cjs");let a=require("node:fs");a=e.__toESM(a,1);let o=require("node:path");o=e.__toESM(o,1);function s(e,t){let r=o.default.join(e,t);if(!a.default.existsSync(r))return{};let i={};for(let e of a.default.readdirSync(r)){if(!e.endsWith(`.ts`)||e.endsWith(`.d.ts`))continue;let r=e.slice(0,-3);i[r===`index`?`index`:n.toKebab(r)]=`${t}/${e}`}return i}function c(){return{name:`doompi-query-assets`,resolveId(e,t){let n=e.indexOf(`?`);if(n<0||t===void 0||!e.startsWith(`.`))return;let r=t.split(`?`)[0];return`${o.default.resolve(o.default.dirname(r),e.slice(0,n))}${e.slice(n)}`},load(e){let t=e.indexOf(`?`);if(t<0)return;let n=e.slice(0,t),r=new URLSearchParams(e.slice(t+1));if(!r.has(`url`))return;let i=r.has(`worker`);return`export default import.meta.ROLLUP_FILE_URL_${this.emitFile(i?{type:`chunk`,id:n,name:o.default.basename(n,o.default.extname(n))}:{type:`asset`,name:o.default.basename(n),source:a.default.readFileSync(n)})};`}}}function l(){return{entry:{"extensions/web":`${t.GENERATED_DIR}/web.ts`},clean:!1,dts:!1,exports:!1,format:[`esm`],platform:`browser`,fixedExtension:!0,external:e=>!e.startsWith(`.`)&&!o.default.isAbsolute(e),plugins:[c()],sourcemap:!0,unbundle:!1}}function u(e={packageDir:process.cwd()}){let n=e.packageDir??process.cwd(),c=r.generateExtension({...e,packageDir:n,check:e.check??!1});for(let e of c.notices)process.stderr.write(`[doompi-build] ${e.path}: ${e.message}\n`);let u={entry:{...s(n,e.exportsDir??`src/exports`),...c.targets.includes(`cli`)?{"extensions/pi":`${t.GENERATED_DIR}/pi.ts`}:{},...c.targets.includes(`server`)?{"extensions/server":`${t.GENERATED_DIR}/server.ts`}:{},...e.entry},clean:!0,dts:{incremental:!0,parallel:!1,eager:!0},exports:!0,format:[`esm`,`cjs`],platform:`node`,sourcemap:!0,unbundle:!0,hooks:{"build:done":()=>void i.writeManifest({packageDir:n,manifest:JSON.parse(a.default.readFileSync(o.default.join(n,`package.json`),`utf8`)),graph:c.graph,targets:c.targets,pluginId:c.pluginId})}};return c.targets.includes(`web`)?[u,l()]:u}exports.doompiExtension=u;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["path","fs","toKebab","GENERATED_DIR","generateExtension","writeManifest"],"sources":["../../../src/services/tsdownPreset/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { GENERATED_DIR } from '../../constants/layout';\nimport { generateExtension } from '../generate';\nimport type { GenerateOptions } from '../generate/type';\nimport { toKebab } from '../identity';\nimport { writeManifest } from '../syncManifest';\n\ninterface EmittedFile {\n readonly type: 'asset' | 'chunk';\n readonly id?: string;\n readonly name: string;\n readonly source?: Buffer;\n}\n\ninterface QueryAssetPlugin {\n readonly name: string;\n resolveId(source: string, importer: string | undefined): string | undefined;\n load(this: { emitFile(file: EmittedFile): string }, id: string): string | undefined;\n}\n\n/** The shape a tsdown config needs from this preset, without importing tsdown's types. */\ninterface BrowserPresetConfig {\n entry: Record<string, string>;\n clean: boolean;\n dts: false;\n exports: boolean;\n format: 'esm'[];\n platform: 'browser';\n fixedExtension: boolean;\n external: (id: string) => boolean;\n plugins: QueryAssetPlugin[];\n sourcemap: boolean;\n unbundle: boolean;\n}\n\ninterface PresetConfig {\n entry: Record<string, string>;\n clean: boolean;\n dts: { incremental: boolean; parallel: boolean; eager: boolean };\n exports: boolean;\n format: ('esm' | 'cjs')[];\n platform: 'node';\n sourcemap: boolean;\n unbundle: boolean;\n hooks: { 'build:done': () => void };\n}\n\nconst DEFAULT_EXPORTS_DIR = 'src/exports';\n\n/** `src/exports/apiContracts.ts` becomes the `api-contracts` entry; index keeps its name. */\nfunction exportEntries(packageDir: string, exportsDir: string): Record<string, string> {\n const absolute = path.join(packageDir, exportsDir);\n if (!fs.existsSync(absolute)) return {};\n const entries: Record<string, string> = {};\n for (const file of fs.readdirSync(absolute)) {\n if (!file.endsWith('.ts') || file.endsWith('.d.ts')) continue;\n const stem = file.slice(0, -'.ts'.length);\n entries[stem === 'index' ? 'index' : toKebab(stem)] = `${exportsDir}/${file}`;\n }\n return entries;\n}\n\n/**\n * One tsdown config for a folder-routed extension.\n *\n * Entries come from the tree rather than a hand-written list, and the manifest\n * blocks that restate the tree are written after the build rather than kept in\n * step by hand. Browser contributions are emitted through a second bundled\n * config because their routed source is not published.\n */\nexport interface ExtensionPresetOptions extends GenerateOptions {\n /** Extra tsdown entries beyond the derived ones. */\n readonly entry?: Record<string, string>;\n /** Public export modules, package-relative. Defaults to `src/exports`. */\n readonly exportsDir?: string;\n}\n\n/**\n * Implements the Vite query imports extension browser code already uses.\n *\n * `?url` copies an opaque asset and `?worker&url` emits a separately bundled\n * worker chunk. Rolldown then replaces its file reference with an URL relative\n * to the extension bundle, which remains valid when the cockpit composes it.\n */\nfunction queryAssetPlugin(): QueryAssetPlugin {\n return {\n name: 'doompi-query-assets',\n resolveId(source, importer) {\n const queryAt = source.indexOf('?');\n if (queryAt < 0 || importer === undefined || !source.startsWith('.')) return undefined;\n const importerFile = importer.split('?')[0] as string;\n return `${path.resolve(path.dirname(importerFile), source.slice(0, queryAt))}${source.slice(queryAt)}`;\n },\n load(id) {\n const queryAt = id.indexOf('?');\n if (queryAt < 0) return undefined;\n const file = id.slice(0, queryAt);\n const query = new URLSearchParams(id.slice(queryAt + 1));\n if (!query.has('url')) return undefined;\n const worker = query.has('worker');\n const reference = this.emitFile(\n worker\n ? { type: 'chunk', id: file, name: path.basename(file, path.extname(file)) }\n : { type: 'asset', name: path.basename(file), source: fs.readFileSync(file) },\n );\n return `export default import.meta.ROLLUP_FILE_URL_${reference};`;\n },\n };\n}\n\n/** The separately bundled browser half of a routed extension. */\nfunction browserConfig(): BrowserPresetConfig {\n return {\n entry: { 'extensions/web': `${GENERATED_DIR}/web.ts` },\n clean: false,\n // No declarations. Nothing imports this as a typed module: it has no\n // export subpath, and the cockpit consumes it as a bundle. The browser\n // half is still typechecked, by tsconfig.web.json in the typecheck script.\n dts: false,\n exports: false,\n format: ['esm'],\n platform: 'browser',\n // platform browser turns tsdown's fixedExtension off, which would emit\n // .js. The manifest names .mjs like the other two entries, so ask for it.\n fixedExtension: true,\n // Every bare specifier stays external and the cockpit resolves it, which\n // is what keeps one React and one store in the page no matter how many\n // plugins are installed. An allowlist would have to be kept in step with\n // the cockpit's; this cannot drift.\n //\n // A predicate rather than a pattern: rolldown tests `external` against the\n // resolved id, so /^[^.]/ also matches the absolute path of this package's\n // own routed file and would leave a dangling import to unbuilt .tsx.\n external: (id: string) => !id.startsWith('.') && !path.isAbsolute(id),\n plugins: [queryAssetPlugin()],\n sourcemap: true,\n // Bundled, unlike the node half. Unbundling would emit an import to the\n // routed source file, which is not published and is .tsx besides. One\n // module with only bare specifiers external is what the cockpit wants.\n unbundle: false,\n };\n}\n\nexport function doompiExtension(\n options: ExtensionPresetOptions = { packageDir: process.cwd() },\n): PresetConfig | (PresetConfig | BrowserPresetConfig)[] {\n const packageDir = options.packageDir ?? process.cwd();\n const result = generateExtension({ ...options, packageDir, check: options.check ?? false });\n\n for (const notice of result.notices) process.stderr.write(`[doompi-build] ${notice.path}: ${notice.message}\\n`);\n\n const entry: Record<string, string> = {\n ...exportEntries(packageDir, options.exportsDir ?? DEFAULT_EXPORTS_DIR),\n ...(result.targets.includes('cli') ? { 'extensions/pi': `${GENERATED_DIR}/pi.ts` } : {}),\n ...(result.targets.includes('server') ? { 'extensions/server': `${GENERATED_DIR}/server.ts` } : {}),\n ...options.entry,\n };\n\n const node: PresetConfig = {\n entry,\n clean: true,\n dts: { incremental: true, parallel: false, eager: true },\n exports: true,\n format: ['esm', 'cjs'],\n // No minify. This is a library build, and a mangled stack trace inside a\n // published extension is far more expensive than the bytes it saves.\n // Node output uses fixed extensions, so pi.extensions and doompiServer.dist\n // both land on the .mjs filenames their hosts require.\n platform: 'node',\n sourcemap: true,\n unbundle: true,\n hooks: {\n 'build:done': () =>\n void writeManifest({\n packageDir,\n manifest: JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf8')) as Record<\n string,\n unknown\n >,\n graph: result.graph,\n targets: result.targets,\n pluginId: result.pluginId,\n }),\n },\n };\n\n return result.targets.includes('web') ? [node, browserConfig()] : node;\n}\n"],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { GenerateOptions } from "../generate/type.cjs";
2
+ //#region src/services/tsdownPreset/index.d.ts
3
+ interface EmittedFile {
4
+ readonly type: 'asset' | 'chunk';
5
+ readonly id?: string;
6
+ readonly name: string;
7
+ readonly source?: Buffer;
8
+ }
9
+ interface QueryAssetPlugin {
10
+ readonly name: string;
11
+ resolveId(source: string, importer: string | undefined): string | undefined;
12
+ load(this: {
13
+ emitFile(file: EmittedFile): string;
14
+ }, id: string): string | undefined;
15
+ }
16
+ /** The shape a tsdown config needs from this preset, without importing tsdown's types. */
17
+ interface BrowserPresetConfig {
18
+ entry: Record<string, string>;
19
+ clean: boolean;
20
+ dts: false;
21
+ exports: boolean;
22
+ format: 'esm'[];
23
+ platform: 'browser';
24
+ fixedExtension: boolean;
25
+ external: (id: string) => boolean;
26
+ plugins: QueryAssetPlugin[];
27
+ sourcemap: boolean;
28
+ unbundle: boolean;
29
+ }
30
+ interface PresetConfig {
31
+ entry: Record<string, string>;
32
+ clean: boolean;
33
+ dts: {
34
+ incremental: boolean;
35
+ parallel: boolean;
36
+ eager: boolean;
37
+ };
38
+ exports: boolean;
39
+ format: ('esm' | 'cjs')[];
40
+ platform: 'node';
41
+ sourcemap: boolean;
42
+ unbundle: boolean;
43
+ hooks: {
44
+ 'build:done': () => void;
45
+ };
46
+ }
47
+ /**
48
+ * One tsdown config for a folder-routed extension.
49
+ *
50
+ * Entries come from the tree rather than a hand-written list, and the manifest
51
+ * blocks that restate the tree are written after the build rather than kept in
52
+ * step by hand. Browser contributions are emitted through a second bundled
53
+ * config because their routed source is not published.
54
+ */
55
+ export interface ExtensionPresetOptions extends GenerateOptions {
56
+ /** Extra tsdown entries beyond the derived ones. */
57
+ readonly entry?: Record<string, string>;
58
+ /** Public export modules, package-relative. Defaults to `src/exports`. */
59
+ readonly exportsDir?: string;
60
+ }
61
+ export declare function doompiExtension(options?: ExtensionPresetOptions): PresetConfig | (PresetConfig | BrowserPresetConfig)[];
62
+ //#endregion
63
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/services/tsdownPreset/index.ts"],"mappings":";;UASU;WACC;WACA;WACA;WACA,SAAS;;UAGV;WACC;EACT,UAAU,gBAAgB;EAC1B,KAAK;IAAQ,SAAS,MAAM;KAAwB;;;UAI5C;EACR,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX,SAAS;EACT;EACA;;UAGQ;EACR,OAAO;EACP;EACA;IAAO;IAAsB;IAAmB;;EAChD;EACA;EACA;EACA;EACA;EACA;IAAS;;;;;;;;;;;iBA0BM,+BAA+B;;WAErC,QAAQ;;WAER;;wBAqEK,gBACd,UAAS,yBACR,gBAAgB,eAAe"}
@@ -0,0 +1,63 @@
1
+ import { GenerateOptions } from "../generate/type.mjs";
2
+ //#region src/services/tsdownPreset/index.d.ts
3
+ interface EmittedFile {
4
+ readonly type: 'asset' | 'chunk';
5
+ readonly id?: string;
6
+ readonly name: string;
7
+ readonly source?: Buffer;
8
+ }
9
+ interface QueryAssetPlugin {
10
+ readonly name: string;
11
+ resolveId(source: string, importer: string | undefined): string | undefined;
12
+ load(this: {
13
+ emitFile(file: EmittedFile): string;
14
+ }, id: string): string | undefined;
15
+ }
16
+ /** The shape a tsdown config needs from this preset, without importing tsdown's types. */
17
+ interface BrowserPresetConfig {
18
+ entry: Record<string, string>;
19
+ clean: boolean;
20
+ dts: false;
21
+ exports: boolean;
22
+ format: 'esm'[];
23
+ platform: 'browser';
24
+ fixedExtension: boolean;
25
+ external: (id: string) => boolean;
26
+ plugins: QueryAssetPlugin[];
27
+ sourcemap: boolean;
28
+ unbundle: boolean;
29
+ }
30
+ interface PresetConfig {
31
+ entry: Record<string, string>;
32
+ clean: boolean;
33
+ dts: {
34
+ incremental: boolean;
35
+ parallel: boolean;
36
+ eager: boolean;
37
+ };
38
+ exports: boolean;
39
+ format: ('esm' | 'cjs')[];
40
+ platform: 'node';
41
+ sourcemap: boolean;
42
+ unbundle: boolean;
43
+ hooks: {
44
+ 'build:done': () => void;
45
+ };
46
+ }
47
+ /**
48
+ * One tsdown config for a folder-routed extension.
49
+ *
50
+ * Entries come from the tree rather than a hand-written list, and the manifest
51
+ * blocks that restate the tree are written after the build rather than kept in
52
+ * step by hand. Browser contributions are emitted through a second bundled
53
+ * config because their routed source is not published.
54
+ */
55
+ export interface ExtensionPresetOptions extends GenerateOptions {
56
+ /** Extra tsdown entries beyond the derived ones. */
57
+ readonly entry?: Record<string, string>;
58
+ /** Public export modules, package-relative. Defaults to `src/exports`. */
59
+ readonly exportsDir?: string;
60
+ }
61
+ export declare function doompiExtension(options?: ExtensionPresetOptions): PresetConfig | (PresetConfig | BrowserPresetConfig)[];
62
+ //#endregion
63
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/tsdownPreset/index.ts"],"mappings":";;UASU;WACC;WACA;WACA;WACA,SAAS;;UAGV;WACC;EACT,UAAU,gBAAgB;EAC1B,KAAK;IAAQ,SAAS,MAAM;KAAwB;;;UAI5C;EACR,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX,SAAS;EACT;EACA;;UAGQ;EACR,OAAO;EACP;EACA;IAAO;IAAsB;IAAmB;;EAChD;EACA;EACA;EACA;EACA;EACA;IAAS;;;;;;;;;;;iBA0BM,+BAA+B;;WAErC,QAAQ;;WAER;;wBAqEK,gBACd,UAAS,yBACR,gBAAgB,eAAe"}
@@ -0,0 +1,2 @@
1
+ import{GENERATED_DIR as e}from"../../constants/layout.mjs";import{toKebab as t}from"../identity/index.mjs";import{generateExtension as n}from"../generate/index.mjs";import{writeManifest as r}from"../syncManifest/index.mjs";import i from"node:fs";import a from"node:path";function o(e,n){let r=a.join(e,n);if(!i.existsSync(r))return{};let o={};for(let e of i.readdirSync(r)){if(!e.endsWith(`.ts`)||e.endsWith(`.d.ts`))continue;let r=e.slice(0,-3);o[r===`index`?`index`:t(r)]=`${n}/${e}`}return o}function s(){return{name:`doompi-query-assets`,resolveId(e,t){let n=e.indexOf(`?`);if(n<0||t===void 0||!e.startsWith(`.`))return;let r=t.split(`?`)[0];return`${a.resolve(a.dirname(r),e.slice(0,n))}${e.slice(n)}`},load(e){let t=e.indexOf(`?`);if(t<0)return;let n=e.slice(0,t),r=new URLSearchParams(e.slice(t+1));if(!r.has(`url`))return;let o=r.has(`worker`);return`export default import.meta.ROLLUP_FILE_URL_${this.emitFile(o?{type:`chunk`,id:n,name:a.basename(n,a.extname(n))}:{type:`asset`,name:a.basename(n),source:i.readFileSync(n)})};`}}}function c(){return{entry:{"extensions/web":`${e}/web.ts`},clean:!1,dts:!1,exports:!1,format:[`esm`],platform:`browser`,fixedExtension:!0,external:e=>!e.startsWith(`.`)&&!a.isAbsolute(e),plugins:[s()],sourcemap:!0,unbundle:!1}}function l(t={packageDir:process.cwd()}){let s=t.packageDir??process.cwd(),l=n({...t,packageDir:s,check:t.check??!1});for(let e of l.notices)process.stderr.write(`[doompi-build] ${e.path}: ${e.message}\n`);let u={entry:{...o(s,t.exportsDir??`src/exports`),...l.targets.includes(`cli`)?{"extensions/pi":`${e}/pi.ts`}:{},...l.targets.includes(`server`)?{"extensions/server":`${e}/server.ts`}:{},...t.entry},clean:!0,dts:{incremental:!0,parallel:!1,eager:!0},exports:!0,format:[`esm`,`cjs`],platform:`node`,sourcemap:!0,unbundle:!0,hooks:{"build:done":()=>void r({packageDir:s,manifest:JSON.parse(i.readFileSync(a.join(s,`package.json`),`utf8`)),graph:l.graph,targets:l.targets,pluginId:l.pluginId})}};return l.targets.includes(`web`)?[u,c()]:u}export{l as doompiExtension};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/services/tsdownPreset/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { GENERATED_DIR } from '../../constants/layout';\nimport { generateExtension } from '../generate';\nimport type { GenerateOptions } from '../generate/type';\nimport { toKebab } from '../identity';\nimport { writeManifest } from '../syncManifest';\n\ninterface EmittedFile {\n readonly type: 'asset' | 'chunk';\n readonly id?: string;\n readonly name: string;\n readonly source?: Buffer;\n}\n\ninterface QueryAssetPlugin {\n readonly name: string;\n resolveId(source: string, importer: string | undefined): string | undefined;\n load(this: { emitFile(file: EmittedFile): string }, id: string): string | undefined;\n}\n\n/** The shape a tsdown config needs from this preset, without importing tsdown's types. */\ninterface BrowserPresetConfig {\n entry: Record<string, string>;\n clean: boolean;\n dts: false;\n exports: boolean;\n format: 'esm'[];\n platform: 'browser';\n fixedExtension: boolean;\n external: (id: string) => boolean;\n plugins: QueryAssetPlugin[];\n sourcemap: boolean;\n unbundle: boolean;\n}\n\ninterface PresetConfig {\n entry: Record<string, string>;\n clean: boolean;\n dts: { incremental: boolean; parallel: boolean; eager: boolean };\n exports: boolean;\n format: ('esm' | 'cjs')[];\n platform: 'node';\n sourcemap: boolean;\n unbundle: boolean;\n hooks: { 'build:done': () => void };\n}\n\nconst DEFAULT_EXPORTS_DIR = 'src/exports';\n\n/** `src/exports/apiContracts.ts` becomes the `api-contracts` entry; index keeps its name. */\nfunction exportEntries(packageDir: string, exportsDir: string): Record<string, string> {\n const absolute = path.join(packageDir, exportsDir);\n if (!fs.existsSync(absolute)) return {};\n const entries: Record<string, string> = {};\n for (const file of fs.readdirSync(absolute)) {\n if (!file.endsWith('.ts') || file.endsWith('.d.ts')) continue;\n const stem = file.slice(0, -'.ts'.length);\n entries[stem === 'index' ? 'index' : toKebab(stem)] = `${exportsDir}/${file}`;\n }\n return entries;\n}\n\n/**\n * One tsdown config for a folder-routed extension.\n *\n * Entries come from the tree rather than a hand-written list, and the manifest\n * blocks that restate the tree are written after the build rather than kept in\n * step by hand. Browser contributions are emitted through a second bundled\n * config because their routed source is not published.\n */\nexport interface ExtensionPresetOptions extends GenerateOptions {\n /** Extra tsdown entries beyond the derived ones. */\n readonly entry?: Record<string, string>;\n /** Public export modules, package-relative. Defaults to `src/exports`. */\n readonly exportsDir?: string;\n}\n\n/**\n * Implements the Vite query imports extension browser code already uses.\n *\n * `?url` copies an opaque asset and `?worker&url` emits a separately bundled\n * worker chunk. Rolldown then replaces its file reference with an URL relative\n * to the extension bundle, which remains valid when the cockpit composes it.\n */\nfunction queryAssetPlugin(): QueryAssetPlugin {\n return {\n name: 'doompi-query-assets',\n resolveId(source, importer) {\n const queryAt = source.indexOf('?');\n if (queryAt < 0 || importer === undefined || !source.startsWith('.')) return undefined;\n const importerFile = importer.split('?')[0] as string;\n return `${path.resolve(path.dirname(importerFile), source.slice(0, queryAt))}${source.slice(queryAt)}`;\n },\n load(id) {\n const queryAt = id.indexOf('?');\n if (queryAt < 0) return undefined;\n const file = id.slice(0, queryAt);\n const query = new URLSearchParams(id.slice(queryAt + 1));\n if (!query.has('url')) return undefined;\n const worker = query.has('worker');\n const reference = this.emitFile(\n worker\n ? { type: 'chunk', id: file, name: path.basename(file, path.extname(file)) }\n : { type: 'asset', name: path.basename(file), source: fs.readFileSync(file) },\n );\n return `export default import.meta.ROLLUP_FILE_URL_${reference};`;\n },\n };\n}\n\n/** The separately bundled browser half of a routed extension. */\nfunction browserConfig(): BrowserPresetConfig {\n return {\n entry: { 'extensions/web': `${GENERATED_DIR}/web.ts` },\n clean: false,\n // No declarations. Nothing imports this as a typed module: it has no\n // export subpath, and the cockpit consumes it as a bundle. The browser\n // half is still typechecked, by tsconfig.web.json in the typecheck script.\n dts: false,\n exports: false,\n format: ['esm'],\n platform: 'browser',\n // platform browser turns tsdown's fixedExtension off, which would emit\n // .js. The manifest names .mjs like the other two entries, so ask for it.\n fixedExtension: true,\n // Every bare specifier stays external and the cockpit resolves it, which\n // is what keeps one React and one store in the page no matter how many\n // plugins are installed. An allowlist would have to be kept in step with\n // the cockpit's; this cannot drift.\n //\n // A predicate rather than a pattern: rolldown tests `external` against the\n // resolved id, so /^[^.]/ also matches the absolute path of this package's\n // own routed file and would leave a dangling import to unbuilt .tsx.\n external: (id: string) => !id.startsWith('.') && !path.isAbsolute(id),\n plugins: [queryAssetPlugin()],\n sourcemap: true,\n // Bundled, unlike the node half. Unbundling would emit an import to the\n // routed source file, which is not published and is .tsx besides. One\n // module with only bare specifiers external is what the cockpit wants.\n unbundle: false,\n };\n}\n\nexport function doompiExtension(\n options: ExtensionPresetOptions = { packageDir: process.cwd() },\n): PresetConfig | (PresetConfig | BrowserPresetConfig)[] {\n const packageDir = options.packageDir ?? process.cwd();\n const result = generateExtension({ ...options, packageDir, check: options.check ?? false });\n\n for (const notice of result.notices) process.stderr.write(`[doompi-build] ${notice.path}: ${notice.message}\\n`);\n\n const entry: Record<string, string> = {\n ...exportEntries(packageDir, options.exportsDir ?? DEFAULT_EXPORTS_DIR),\n ...(result.targets.includes('cli') ? { 'extensions/pi': `${GENERATED_DIR}/pi.ts` } : {}),\n ...(result.targets.includes('server') ? { 'extensions/server': `${GENERATED_DIR}/server.ts` } : {}),\n ...options.entry,\n };\n\n const node: PresetConfig = {\n entry,\n clean: true,\n dts: { incremental: true, parallel: false, eager: true },\n exports: true,\n format: ['esm', 'cjs'],\n // No minify. This is a library build, and a mangled stack trace inside a\n // published extension is far more expensive than the bytes it saves.\n // Node output uses fixed extensions, so pi.extensions and doompiServer.dist\n // both land on the .mjs filenames their hosts require.\n platform: 'node',\n sourcemap: true,\n unbundle: true,\n hooks: {\n 'build:done': () =>\n void writeManifest({\n packageDir,\n manifest: JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf8')) as Record<\n string,\n unknown\n >,\n graph: result.graph,\n targets: result.targets,\n pluginId: result.pluginId,\n }),\n },\n };\n\n return result.targets.includes('web') ? [node, browserConfig()] : node;\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);var r=class extends Error{stale;constructor(e){super(`Stale generated files: ${e.join(`, `)}. Run the package's build to regenerate them.`),this.stale=e,this.name=`StaleGeneratedError`}};function i(e,i,a=!1,o=[]){let s=[];for(let[r,o]of i){let i=n.default.join(e,r);(t.default.existsSync(i)?t.default.readFileSync(i,`utf8`):void 0)!==o&&(s.push(r),!a&&(t.default.mkdirSync(n.default.dirname(i),{recursive:!0}),t.default.writeFileSync(i,o)))}for(let r of o){if(i.has(r))continue;let o=n.default.join(e,r);t.default.existsSync(o)&&(s.push(r),a||t.default.rmSync(o))}if(a&&s.length>0)throw new r(s);return{changed:s}}exports.StaleGeneratedError=r,exports.writeGenerated=i;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["path","fs"],"sources":["../../../src/services/writeGenerated/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\n/** What a sync pass did, or would have done. */\nexport interface WriteResult {\n /** Package-relative paths whose contents changed. */\n readonly changed: readonly string[];\n}\n\nexport class StaleGeneratedError extends Error {\n constructor(readonly stale: readonly string[]) {\n super(`Stale generated files: ${stale.join(', ')}. Run the package's build to regenerate them.`);\n this.name = 'StaleGeneratedError';\n }\n}\n\n/**\n * Write-if-changed locally, throw on stale under an explicit `check`.\n *\n * Generated entries are ignored build inputs, so normal and CI builds create\n * them. Explicit check mode remains available to callers that need to compare\n * an existing generated tree without changing it.\n *\n * Writing only on a real change matters for watch mode: an unconditional\n * write would retrigger the watcher that called it.\n */\nexport function writeGenerated(\n packageDir: string,\n files: ReadonlyMap<string, string>,\n check = false,\n managed: readonly string[] = [],\n): WriteResult {\n const changed: string[] = [];\n\n for (const [relative, contents] of files) {\n const absolute = path.join(packageDir, relative);\n const existing = fs.existsSync(absolute) ? fs.readFileSync(absolute, 'utf8') : undefined;\n if (existing === contents) continue;\n changed.push(relative);\n if (check) continue;\n fs.mkdirSync(path.dirname(absolute), { recursive: true });\n fs.writeFileSync(absolute, contents);\n }\n\n for (const relative of managed) {\n if (files.has(relative)) continue;\n const absolute = path.join(packageDir, relative);\n if (!fs.existsSync(absolute)) continue;\n changed.push(relative);\n if (!check) fs.rmSync(absolute);\n }\n\n if (check && changed.length > 0) throw new StaleGeneratedError(changed);\n return { changed };\n}\n"],"mappings":"8IASA,IAAa,EAAb,cAAyC,KAAM,CACxB,MAArB,YAAY,EAAmC,CAC7C,MAAM,0BAA0B,EAAM,KAAK,IAAI,EAAE,8CAA8C,EAD5E,KAAA,MAAA,EAEnB,KAAK,KAAO,qBACd,CACF,EAYA,SAAgB,EACd,EACA,EACA,EAAQ,GACR,EAA6B,CAAC,EACjB,CACb,IAAM,EAAoB,CAAC,EAE3B,IAAK,GAAM,CAAC,EAAU,KAAa,EAAO,CACxC,IAAM,EAAWA,EAAAA,QAAK,KAAK,EAAY,CAAQ,GAC9BC,EAAAA,QAAG,WAAW,CAAQ,EAAIA,EAAAA,QAAG,aAAa,EAAU,MAAM,EAAI,IAAA,MAC9D,IACjB,EAAQ,KAAK,CAAQ,EACjB,KACJ,EAAA,QAAG,UAAUD,EAAAA,QAAK,QAAQ,CAAQ,EAAG,CAAE,UAAW,EAAK,CAAC,EACxD,EAAA,QAAG,cAAc,EAAU,CAAQ,GACrC,CAEA,IAAK,IAAM,KAAY,EAAS,CAC9B,GAAI,EAAM,IAAI,CAAQ,EAAG,SACzB,IAAM,EAAWA,EAAAA,QAAK,KAAK,EAAY,CAAQ,EAC1CC,EAAAA,QAAG,WAAW,CAAQ,IAC3B,EAAQ,KAAK,CAAQ,EAChB,GAAO,EAAA,QAAG,OAAO,CAAQ,EAChC,CAEA,GAAI,GAAS,EAAQ,OAAS,EAAG,MAAM,IAAI,EAAoB,CAAO,EACtE,MAAO,CAAE,SAAQ,CACnB"}
@@ -0,0 +1,23 @@
1
+ //#region src/services/writeGenerated/index.d.ts
2
+ /** What a sync pass did, or would have done. */
3
+ export interface WriteResult {
4
+ /** Package-relative paths whose contents changed. */
5
+ readonly changed: readonly string[];
6
+ }
7
+ export declare class StaleGeneratedError extends Error {
8
+ readonly stale: readonly string[];
9
+ constructor(stale: readonly string[]);
10
+ }
11
+ /**
12
+ * Write-if-changed locally, throw on stale under an explicit `check`.
13
+ *
14
+ * Generated entries are ignored build inputs, so normal and CI builds create
15
+ * them. Explicit check mode remains available to callers that need to compare
16
+ * an existing generated tree without changing it.
17
+ *
18
+ * Writing only on a real change matters for watch mode: an unconditional
19
+ * write would retrigger the watcher that called it.
20
+ */
21
+ export declare function writeGenerated(packageDir: string, files: ReadonlyMap<string, string>, check?: boolean, managed?: readonly string[]): WriteResult;
22
+ //#endregion
23
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/services/writeGenerated/index.ts"],"mappings":";;iBAIiB;;WAEN;;qBAGE,4BAA4B;WAClB;EAArB,YAAqB;;;;;;;;;;;;wBAgBP,eACd,oBACA,OAAO,6BACP,iBACA,8BACC"}
@@ -0,0 +1,23 @@
1
+ //#region src/services/writeGenerated/index.d.ts
2
+ /** What a sync pass did, or would have done. */
3
+ export interface WriteResult {
4
+ /** Package-relative paths whose contents changed. */
5
+ readonly changed: readonly string[];
6
+ }
7
+ export declare class StaleGeneratedError extends Error {
8
+ readonly stale: readonly string[];
9
+ constructor(stale: readonly string[]);
10
+ }
11
+ /**
12
+ * Write-if-changed locally, throw on stale under an explicit `check`.
13
+ *
14
+ * Generated entries are ignored build inputs, so normal and CI builds create
15
+ * them. Explicit check mode remains available to callers that need to compare
16
+ * an existing generated tree without changing it.
17
+ *
18
+ * Writing only on a real change matters for watch mode: an unconditional
19
+ * write would retrigger the watcher that called it.
20
+ */
21
+ export declare function writeGenerated(packageDir: string, files: ReadonlyMap<string, string>, check?: boolean, managed?: readonly string[]): WriteResult;
22
+ //#endregion
23
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/services/writeGenerated/index.ts"],"mappings":";;iBAIiB;;WAEN;;qBAGE,4BAA4B;WAClB;EAArB,YAAqB;;;;;;;;;;;;wBAgBP,eACd,oBACA,OAAO,6BACP,iBACA,8BACC"}
@@ -0,0 +1,2 @@
1
+ import e from"node:fs";import t from"node:path";var n=class extends Error{stale;constructor(e){super(`Stale generated files: ${e.join(`, `)}. Run the package's build to regenerate them.`),this.stale=e,this.name=`StaleGeneratedError`}};function r(r,i,a=!1,o=[]){let s=[];for(let[n,o]of i){let i=t.join(r,n);(e.existsSync(i)?e.readFileSync(i,`utf8`):void 0)!==o&&(s.push(n),!a&&(e.mkdirSync(t.dirname(i),{recursive:!0}),e.writeFileSync(i,o)))}for(let n of o){if(i.has(n))continue;let o=t.join(r,n);e.existsSync(o)&&(s.push(n),a||e.rmSync(o))}if(a&&s.length>0)throw new n(s);return{changed:s}}export{n as StaleGeneratedError,r as writeGenerated};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/services/writeGenerated/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\n/** What a sync pass did, or would have done. */\nexport interface WriteResult {\n /** Package-relative paths whose contents changed. */\n readonly changed: readonly string[];\n}\n\nexport class StaleGeneratedError extends Error {\n constructor(readonly stale: readonly string[]) {\n super(`Stale generated files: ${stale.join(', ')}. Run the package's build to regenerate them.`);\n this.name = 'StaleGeneratedError';\n }\n}\n\n/**\n * Write-if-changed locally, throw on stale under an explicit `check`.\n *\n * Generated entries are ignored build inputs, so normal and CI builds create\n * them. Explicit check mode remains available to callers that need to compare\n * an existing generated tree without changing it.\n *\n * Writing only on a real change matters for watch mode: an unconditional\n * write would retrigger the watcher that called it.\n */\nexport function writeGenerated(\n packageDir: string,\n files: ReadonlyMap<string, string>,\n check = false,\n managed: readonly string[] = [],\n): WriteResult {\n const changed: string[] = [];\n\n for (const [relative, contents] of files) {\n const absolute = path.join(packageDir, relative);\n const existing = fs.existsSync(absolute) ? fs.readFileSync(absolute, 'utf8') : undefined;\n if (existing === contents) continue;\n changed.push(relative);\n if (check) continue;\n fs.mkdirSync(path.dirname(absolute), { recursive: true });\n fs.writeFileSync(absolute, contents);\n }\n\n for (const relative of managed) {\n if (files.has(relative)) continue;\n const absolute = path.join(packageDir, relative);\n if (!fs.existsSync(absolute)) continue;\n changed.push(relative);\n if (!check) fs.rmSync(absolute);\n }\n\n if (check && changed.length > 0) throw new StaleGeneratedError(changed);\n return { changed };\n}\n"],"mappings":"gDASA,IAAa,EAAb,cAAyC,KAAM,CACxB,MAArB,YAAY,EAAmC,CAC7C,MAAM,0BAA0B,EAAM,KAAK,IAAI,EAAE,8CAA8C,EAD5E,KAAA,MAAA,EAEnB,KAAK,KAAO,qBACd,CACF,EAYA,SAAgB,EACd,EACA,EACA,EAAQ,GACR,EAA6B,CAAC,EACjB,CACb,IAAM,EAAoB,CAAC,EAE3B,IAAK,GAAM,CAAC,EAAU,KAAa,EAAO,CACxC,IAAM,EAAW,EAAK,KAAK,EAAY,CAAQ,GAC9B,EAAG,WAAW,CAAQ,EAAI,EAAG,aAAa,EAAU,MAAM,EAAI,IAAA,MAC9D,IACjB,EAAQ,KAAK,CAAQ,EACjB,KACJ,EAAG,UAAU,EAAK,QAAQ,CAAQ,EAAG,CAAE,UAAW,EAAK,CAAC,EACxD,EAAG,cAAc,EAAU,CAAQ,GACrC,CAEA,IAAK,IAAM,KAAY,EAAS,CAC9B,GAAI,EAAM,IAAI,CAAQ,EAAG,SACzB,IAAM,EAAW,EAAK,KAAK,EAAY,CAAQ,EAC1C,EAAG,WAAW,CAAQ,IAC3B,EAAQ,KAAK,CAAQ,EAChB,GAAO,EAAG,OAAO,CAAQ,EAChC,CAEA,GAAI,GAAS,EAAQ,OAAS,EAAG,MAAM,IAAI,EAAoB,CAAO,EACtE,MAAO,CAAE,SAAQ,CACnB"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/tsdownPreset/index.cjs");exports.doompiExtension=e.doompiExtension;
@@ -0,0 +1,2 @@
1
+ import { ExtensionPresetOptions, doompiExtension } from "./services/tsdownPreset/index.cjs";
2
+ export { type ExtensionPresetOptions, doompiExtension };
@@ -0,0 +1,2 @@
1
+ import { ExtensionPresetOptions, doompiExtension } from "./services/tsdownPreset/index.mjs";
2
+ export { type ExtensionPresetOptions, doompiExtension };
@@ -0,0 +1 @@
1
+ import{doompiExtension as e}from"./services/tsdownPreset/index.mjs";export{e as doompiExtension};
@@ -0,0 +1,75 @@
1
+ //#region src/types/extensionGraph.d.ts
2
+ /** The scopes a contribution can mount at, in nesting order. */
3
+ export type ExtensionScope = 'global' | 'workspace' | 'session';
4
+ /** Which half of the package a contribution belongs to. */
5
+ export type ExtensionSide = 'backend' | 'frontend';
6
+ /**
7
+ * What a scanned file is, beyond which surface it feeds.
8
+ *
9
+ * `root` is the scope's constructor, as Next.js spells a layout: it runs
10
+ * before anything below it, builds whatever that subtree shares, and every
11
+ * routed file under it receives the result as part of its mount context. It is
12
+ * also where a scope's teardown goes, because it is the only file that can see
13
+ * the whole lifetime.
14
+ */
15
+ export type EntryRole = 'contribution' | 'escape-hatch' | 'root';
16
+ /** One gate folder and the id it names. */
17
+ export interface ExtensionGate {
18
+ readonly kind: string;
19
+ readonly id: string;
20
+ }
21
+ /** One dynamic route segment, as Next.js spells it. */
22
+ export interface RouteParam {
23
+ readonly name: string;
24
+ readonly catchAll: boolean;
25
+ }
26
+ /** One route segment below a routed surface: a literal, or a parameter. */
27
+ export type RouteSegment = {
28
+ readonly literal: string;
29
+ } | {
30
+ readonly param: RouteParam;
31
+ };
32
+ /**
33
+ * One scanned file and everything its path declares about it.
34
+ *
35
+ * The scan produces these and nothing else. Turning them into host
36
+ * contributions is the generator's job, so this stays a description of the
37
+ * tree rather than of any one host.
38
+ */
39
+ export interface ExtensionEntry {
40
+ /** Package-relative POSIX path. */
41
+ readonly file: string;
42
+ readonly scope: ExtensionScope;
43
+ readonly side: ExtensionSide;
44
+ /** Gates wrapping this contribution, outermost first. */
45
+ readonly gates: readonly ExtensionGate[];
46
+ /** Surface folder, such as `tool`. Absent for the escape hatch. */
47
+ readonly surface: string | undefined;
48
+ /** Route path below a routed surface. Empty for every other surface. */
49
+ readonly route: readonly RouteSegment[];
50
+ /** Contribution identity, from the filename. */
51
+ readonly name: string;
52
+ /** Relationship target, such as the slot a fill names. */
53
+ readonly target: string | undefined;
54
+ /** Platform this file serves. Undefined only for a file the scan has already reported. */
55
+ readonly platform: string | undefined;
56
+ /** Helper-declared cardinality. Omitted means exactly one contribution. */
57
+ readonly cardinality?: 'optional' | 'many' | 'collection';
58
+ /** Whether this declares a contribution, a scope root, or the escape hatch. */
59
+ readonly role: EntryRole;
60
+ }
61
+ /** Something the scan skipped, and why. Never fatal. */
62
+ export interface ExtensionNotice {
63
+ /** Package-relative POSIX path of the file or folder skipped. */
64
+ readonly path: string;
65
+ readonly message: string;
66
+ }
67
+ /** Everything one package's routing root declares. */
68
+ export interface ExtensionGraph {
69
+ /** Package-relative POSIX path of the routing root that was scanned. */
70
+ readonly root: string;
71
+ readonly entries: readonly ExtensionEntry[];
72
+ readonly notices: readonly ExtensionNotice[];
73
+ }
74
+ //#endregion
75
+ //# sourceMappingURL=extensionGraph.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensionGraph.d.cts","names":[],"sources":["../../src/types/extensionGraph.ts"],"mappings":";;YACY;;YAGA;;;;;;;;;;YAWA;;iBAGK;WACN;WACA;;;iBAIM;WACN;WACA;;;YAIC;WAA0B;;WAA+B,OAAO;;;;;;;;;iBAS3D;;WAEN;WACA,OAAO;WACP,MAAM;;WAEN,gBAAgB;;WAEhB;;WAEA,gBAAgB;;WAEhB;;WAEA;;WAEA;;WAEA;;WAEA,MAAM;;;iBAIA;;WAEN;WACA;;;iBAIM;;WAEN;WACA,kBAAkB;WAClB,kBAAkB"}
@@ -0,0 +1,75 @@
1
+ //#region src/types/extensionGraph.d.ts
2
+ /** The scopes a contribution can mount at, in nesting order. */
3
+ export type ExtensionScope = 'global' | 'workspace' | 'session';
4
+ /** Which half of the package a contribution belongs to. */
5
+ export type ExtensionSide = 'backend' | 'frontend';
6
+ /**
7
+ * What a scanned file is, beyond which surface it feeds.
8
+ *
9
+ * `root` is the scope's constructor, as Next.js spells a layout: it runs
10
+ * before anything below it, builds whatever that subtree shares, and every
11
+ * routed file under it receives the result as part of its mount context. It is
12
+ * also where a scope's teardown goes, because it is the only file that can see
13
+ * the whole lifetime.
14
+ */
15
+ export type EntryRole = 'contribution' | 'escape-hatch' | 'root';
16
+ /** One gate folder and the id it names. */
17
+ export interface ExtensionGate {
18
+ readonly kind: string;
19
+ readonly id: string;
20
+ }
21
+ /** One dynamic route segment, as Next.js spells it. */
22
+ export interface RouteParam {
23
+ readonly name: string;
24
+ readonly catchAll: boolean;
25
+ }
26
+ /** One route segment below a routed surface: a literal, or a parameter. */
27
+ export type RouteSegment = {
28
+ readonly literal: string;
29
+ } | {
30
+ readonly param: RouteParam;
31
+ };
32
+ /**
33
+ * One scanned file and everything its path declares about it.
34
+ *
35
+ * The scan produces these and nothing else. Turning them into host
36
+ * contributions is the generator's job, so this stays a description of the
37
+ * tree rather than of any one host.
38
+ */
39
+ export interface ExtensionEntry {
40
+ /** Package-relative POSIX path. */
41
+ readonly file: string;
42
+ readonly scope: ExtensionScope;
43
+ readonly side: ExtensionSide;
44
+ /** Gates wrapping this contribution, outermost first. */
45
+ readonly gates: readonly ExtensionGate[];
46
+ /** Surface folder, such as `tool`. Absent for the escape hatch. */
47
+ readonly surface: string | undefined;
48
+ /** Route path below a routed surface. Empty for every other surface. */
49
+ readonly route: readonly RouteSegment[];
50
+ /** Contribution identity, from the filename. */
51
+ readonly name: string;
52
+ /** Relationship target, such as the slot a fill names. */
53
+ readonly target: string | undefined;
54
+ /** Platform this file serves. Undefined only for a file the scan has already reported. */
55
+ readonly platform: string | undefined;
56
+ /** Helper-declared cardinality. Omitted means exactly one contribution. */
57
+ readonly cardinality?: 'optional' | 'many' | 'collection';
58
+ /** Whether this declares a contribution, a scope root, or the escape hatch. */
59
+ readonly role: EntryRole;
60
+ }
61
+ /** Something the scan skipped, and why. Never fatal. */
62
+ export interface ExtensionNotice {
63
+ /** Package-relative POSIX path of the file or folder skipped. */
64
+ readonly path: string;
65
+ readonly message: string;
66
+ }
67
+ /** Everything one package's routing root declares. */
68
+ export interface ExtensionGraph {
69
+ /** Package-relative POSIX path of the routing root that was scanned. */
70
+ readonly root: string;
71
+ readonly entries: readonly ExtensionEntry[];
72
+ readonly notices: readonly ExtensionNotice[];
73
+ }
74
+ //#endregion
75
+ //# sourceMappingURL=extensionGraph.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensionGraph.d.mts","names":[],"sources":["../../src/types/extensionGraph.ts"],"mappings":";;YACY;;YAGA;;;;;;;;;;YAWA;;iBAGK;WACN;WACA;;;iBAIM;WACN;WACA;;;YAIC;WAA0B;;WAA+B,OAAO;;;;;;;;;iBAS3D;;WAEN;WACA,OAAO;WACP,MAAM;;WAEN,gBAAgB;;WAEhB;;WAEA,gBAAgB;;WAEhB;;WAEA;;WAEA;;WAEA;;WAEA,MAAM;;;iBAIA;;WAEN;WACA;;;iBAIM;;WAEN;WACA,kBAAkB;WAClB,kBAAkB"}