@pikku/cli 0.12.102 → 0.12.103
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/console-app/assets/{abnfDiagram-VRR7QNED-BneJZPuq.js → abnfDiagram-VRR7QNED-BLi9JHGg.js} +1 -1
- package/console-app/assets/{arc-B6oXAx95.js → arc-B3b5uYlL.js} +1 -1
- package/console-app/assets/architecture-TIHT7OUA-BYeDayHv.js +1 -0
- package/console-app/assets/{architectureDiagram-ZJ3FMSHR-Dn6JKcGL.js → architectureDiagram-ZJ3FMSHR-Dkd8kxIa.js} +1 -1
- package/console-app/assets/{blockDiagram-677ZJIJ3-CQtakjN5.js → blockDiagram-677ZJIJ3-DnH0nNlb.js} +1 -1
- package/console-app/assets/{c4Diagram-LMCZKHZV-DRBlz-sO.js → c4Diagram-LMCZKHZV-BlelCS5i.js} +1 -1
- package/console-app/assets/channel-CTa6nggO.js +1 -0
- package/console-app/assets/{chunk-32BRIVSS-DIionvWe.js → chunk-32BRIVSS-D7tMgtT1.js} +1 -1
- package/console-app/assets/{chunk-52WLFC77-DwrMMV53.js → chunk-52WLFC77-CRepS35y.js} +1 -1
- package/console-app/assets/{chunk-C7G6YPKG-C7_SHoee.js → chunk-C7G6YPKG-CUldlJz4.js} +1 -1
- package/console-app/assets/{chunk-EX3LRPZG-Brqi3de0.js → chunk-EX3LRPZG-DODbrqEj.js} +1 -1
- package/console-app/assets/{chunk-FWX5IMBZ-CGXYdLJv.js → chunk-FWX5IMBZ-nZa59wGD.js} +2 -2
- package/console-app/assets/{chunk-HOUHSVGY-C-mHnXIa.js → chunk-HOUHSVGY-BaawVZCa.js} +1 -1
- package/console-app/assets/{chunk-ICXQ74PX-x3psPzuY.js → chunk-ICXQ74PX-C86LrIRs.js} +1 -1
- package/console-app/assets/{chunk-MOJQB5TN-2uXUItkq.js → chunk-MOJQB5TN-ovUDQlyW.js} +1 -1
- package/console-app/assets/{chunk-OGEWGWER-eXRvfFkE.js → chunk-OGEWGWER-ByZKAcGu.js} +1 -1
- package/console-app/assets/{chunk-PUDLZKDR-CyN33Wwe.js → chunk-PUDLZKDR-DdeJN3wJ.js} +1 -1
- package/console-app/assets/{chunk-Q4XR5HBZ-uyzxeIyh.js → chunk-Q4XR5HBZ-Blp5W9-b.js} +1 -1
- package/console-app/assets/{chunk-RYQCIY6F-CB9wv1YB.js → chunk-RYQCIY6F-DehwjyPp.js} +1 -1
- package/console-app/assets/{chunk-V7JOEXUC-DLMzjIkb.js → chunk-V7JOEXUC-Ca1xeVdo.js} +1 -1
- package/console-app/assets/chunk-VAUOI2AC-BCngaLxk.js +1 -0
- package/console-app/assets/{chunk-VR4S4FIN-DtBvdHYI.js → chunk-VR4S4FIN-Cj7ZlsLr.js} +1 -1
- package/console-app/assets/{chunk-WYO6CB5R-B_EVxwHf.js → chunk-WYO6CB5R-CsdBQ1HS.js} +1 -1
- package/console-app/assets/chunk-XXDRQBXY-CGIlOoBU.js +1 -0
- package/console-app/assets/{chunk-ZGVPDNZ5-CGfMGxHR.js → chunk-ZGVPDNZ5-DMnFdLEO.js} +1 -1
- package/console-app/assets/classDiagram-OUVF2IWQ-Bwt1ZVOR.js +1 -0
- package/console-app/assets/classDiagram-v2-EOCWNBFH-Bwt1ZVOR.js +1 -0
- package/console-app/assets/{cose-bilkent-JH36ORCC-B_3kCkWC.js → cose-bilkent-JH36ORCC-CiYBhiBv.js} +1 -1
- package/console-app/assets/{cynefin-VYW2F7L2-Buqf60VA.js → cynefin-VYW2F7L2-BXuNC8qm.js} +1 -1
- package/console-app/assets/{cynefinDiagram-TSTJHNR4-DOjw2x6X.js → cynefinDiagram-TSTJHNR4-Ck53b-Nr.js} +1 -1
- package/console-app/assets/{dagre-VKFMJZFB-CTZTYT0b.js → dagre-VKFMJZFB-C9hZCnOv.js} +1 -1
- package/console-app/assets/{diagram-FQU43EPY-BZh4LC_G.js → diagram-FQU43EPY-DuEKSLPE.js} +1 -1
- package/console-app/assets/{diagram-G47NLZAW-DDHD69gC.js → diagram-G47NLZAW-B_yO-zKt.js} +1 -1
- package/console-app/assets/{diagram-NH7WQ7WH-YnfI_N0A.js → diagram-NH7WQ7WH-CtKFjoB4.js} +1 -1
- package/console-app/assets/{diagram-OA4YK3LP-ByfLxp7x.js → diagram-OA4YK3LP-T9eIYXYs.js} +1 -1
- package/console-app/assets/{diagram-WEI45ONY-CghNIRYp.js → diagram-WEI45ONY-BTgu-I69.js} +1 -1
- package/console-app/assets/{dist-DCLZxlZv.js → dist-DSVj7qxi.js} +1 -1
- package/console-app/assets/{ebnfDiagram-CCIWWBDH-D5_G_ZqU.js → ebnfDiagram-CCIWWBDH-BdyNRX2k.js} +1 -1
- package/console-app/assets/{erDiagram-Q63AITRT-B5ZtoDJs.js → erDiagram-Q63AITRT-B0cr0nxe.js} +1 -1
- package/console-app/assets/eventmodeling-45OFAUF4-BeHdsPzc.js +1 -0
- package/console-app/assets/flowDiagram-23GEKE2U-6N6mIkfB.js +1 -0
- package/console-app/assets/{ganttDiagram-NO4QXBWP-R-TggPMB.js → ganttDiagram-NO4QXBWP-Cr1R_nGh.js} +1 -1
- package/console-app/assets/{gitGraph-TEB2WS4Q-Cjhl-pwb.js → gitGraph-TEB2WS4Q-zcmQoWd4.js} +1 -1
- package/console-app/assets/{gitGraphDiagram-IHSO6WYX-DnQe5wWr.js → gitGraphDiagram-IHSO6WYX-CHB9Fnch.js} +1 -1
- package/console-app/assets/{index-BZTTf18Y.js → index-BbIUXgNl.js} +144 -144
- package/console-app/assets/{index-r763CZB4.css → index-C9U-Zyvx.css} +1 -1
- package/console-app/assets/{info-DKCQHKI2-DlSWT4UP.js → info-DKCQHKI2-BGPZGp_E.js} +1 -1
- package/console-app/assets/{infoDiagram-FWYZ7A6U-xqpfzGnj.js → infoDiagram-FWYZ7A6U-Br_p6SR_.js} +1 -1
- package/console-app/assets/{ishikawaDiagram-FXEZZL3T-M_pUeGWs.js → ishikawaDiagram-FXEZZL3T-Ma2d4IuN.js} +1 -1
- package/console-app/assets/{journeyDiagram-5HDEW3XC-Dm6FR2DD.js → journeyDiagram-5HDEW3XC-LdCblEX2.js} +1 -1
- package/console-app/assets/{kanban-definition-HUTT4EX6-CbhkDdQH.js → kanban-definition-HUTT4EX6-CRWetzV4.js} +1 -1
- package/console-app/assets/{line-C98Z2IVv.js → line-DrceqMYY.js} +1 -1
- package/console-app/assets/{linear-fYIkDCbB.js → linear-acWbtwAj.js} +1 -1
- package/console-app/assets/{mermaid-parser.core-Dkioi2z2.js → mermaid-parser.core-n773Jf0G.js} +3 -3
- package/console-app/assets/{mermaid.core-CeJcbw8_.js → mermaid.core-DyTRkSqH.js} +3 -3
- package/console-app/assets/{mindmap-definition-LN4V7U3C-DDitGESW.js → mindmap-definition-LN4V7U3C-CBU-ehFU.js} +1 -1
- package/console-app/assets/{packet-7NZHBO7P-DWZKJ9Us.js → packet-7NZHBO7P-DL_fgdX1.js} +1 -1
- package/console-app/assets/{pegDiagram-2B236MQR-CZGjPLXH.js → pegDiagram-2B236MQR-CrFaAHHj.js} +1 -1
- package/console-app/assets/{pie-RZYD4A2V-DT4-E-uE.js → pie-RZYD4A2V-STtzW8Tz.js} +1 -1
- package/console-app/assets/{pieDiagram-ENE6RG2P-bgr82Jyt.js → pieDiagram-ENE6RG2P-DsUOr1Ud.js} +1 -1
- package/console-app/assets/{quadrantDiagram-ABIIQ3AL-Dcw3uNG0.js → quadrantDiagram-ABIIQ3AL-DmuSe_qW.js} +1 -1
- package/console-app/assets/{radar-I7S5WNFK-CFAbRVFk.js → radar-I7S5WNFK-L8w2lEOb.js} +1 -1
- package/console-app/assets/{railroad-3IZDKUUU-CjkCoEjH.js → railroad-3IZDKUUU-CxqlE5vc.js} +1 -1
- package/console-app/assets/railroad-abnf-AHOZXSZD-CkJOR_Em.js +1 -0
- package/console-app/assets/railroad-ebnf-EBAXGLYW-BH_pRGgm.js +1 -0
- package/console-app/assets/railroad-peg-LSFZ7HO6-B50bKcii.js +1 -0
- package/console-app/assets/{railroadDiagram-RFXS5EU6-BUoL0dsw.js → railroadDiagram-RFXS5EU6-CJ8Lpbeo.js} +1 -1
- package/console-app/assets/{requirementDiagram-TGXJPOKE-C27qMKlr.js → requirementDiagram-TGXJPOKE-8OXQXUud.js} +1 -1
- package/console-app/assets/{sankeyDiagram-HTMAVEWB-BYEhrrY0.js → sankeyDiagram-HTMAVEWB-Bezd2CqZ.js} +1 -1
- package/console-app/assets/{sequenceDiagram-DBY2YBRQ-BCuL4Pl6.js → sequenceDiagram-DBY2YBRQ-DHb5js3D.js} +1 -1
- package/console-app/assets/{src-jNbD6Nj3.js → src-DfFamOl-.js} +1 -1
- package/console-app/assets/{stateDiagram-2N3HPSRC-C8Ywa3Ah.js → stateDiagram-2N3HPSRC-UpyJm2mi.js} +1 -1
- package/console-app/assets/stateDiagram-v2-6OUMAXLB-C6gAfg82.js +1 -0
- package/console-app/assets/{swimlanes-5IMT3BWC-C12iYfdp.js → swimlanes-5IMT3BWC-yUrV5f4O.js} +1 -1
- package/console-app/assets/swimlanesDiagram-G3AALYLV-Ch2_j5W5.js +8 -0
- package/console-app/assets/{timeline-definition-FHXFAJF6-BFQotHp7.js → timeline-definition-FHXFAJF6-B6w-rZeZ.js} +1 -1
- package/console-app/assets/{treeView-QDETBFTQ-CGbwDLTd.js → treeView-QDETBFTQ-0k2QpnXc.js} +1 -1
- package/console-app/assets/{treemap-6X3UGDF4-DxSGskiF.js → treemap-6X3UGDF4-ByCuDcGA.js} +1 -1
- package/console-app/assets/{vennDiagram-L72KCM5P-D4hlUYc9.js → vennDiagram-L72KCM5P-BH4374lw.js} +1 -1
- package/console-app/assets/{wardley-OPB4EBWU-XlXl32Vn.js → wardley-OPB4EBWU-DNVwuJz6.js} +1 -1
- package/console-app/assets/{wardleyDiagram-EHGQE667-ttCeFzYx.js → wardleyDiagram-EHGQE667-EXnQ6lkx.js} +1 -1
- package/console-app/assets/{xychartDiagram-FW5EYKEG-BMG4kbfv.js → xychartDiagram-FW5EYKEG-rFh-UdgH.js} +1 -1
- package/console-app/index.html +10 -3
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/agent/pikku-model-aliases.gen.js +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +1 -1
- package/dist/.pikku/function/pikku-functions.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-personas.gen.d.ts +2 -1
- package/dist/.pikku/workflow/pikku-personas.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +3 -2
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/deploy/analyzer/analyzer.js +23 -0
- package/dist/src/deploy/analyzer/manifest.d.ts +19 -0
- package/dist/src/fabric/functions/validate.function.js +2 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +1 -1
- package/dist/src/functions/commands/scenario-formatter.d.ts +1 -1
- package/dist/src/functions/commands/scenario-ladder.d.ts +1 -1
- package/dist/src/functions/commands/scenario-ladder.js +1 -1
- package/dist/src/functions/commands/scenario-plan.d.ts +2 -1
- package/dist/src/functions/commands/scenario-plan.js +1 -1
- package/dist/src/functions/commands/scenario.d.ts +1 -1
- package/dist/src/functions/commands/scenario.js +2 -2
- package/dist/src/functions/surface/collect-surface.d.ts +14 -0
- package/dist/src/functions/surface/collect-surface.js +215 -0
- package/dist/src/functions/validate/type-identity-checks.d.ts +25 -0
- package/dist/src/functions/validate/type-identity-checks.js +218 -0
- package/dist/src/functions/validate/validate-registry.js +11 -0
- package/dist/src/functions/wirings/scenarios/serialize-feature-meta.d.ts +1 -1
- package/dist/src/functions/wirings/scenarios/serialize-scenario-registration.js +6 -5
- package/dist/src/functions/wirings/workflow/serialize-personas.js +2 -5
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +2 -1
- package/dist/src/functions/workflows/all.workflow.js +5 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/console-app/assets/architecture-TIHT7OUA-BIpQbDwm.js +0 -1
- package/console-app/assets/channel-D9eZ2wja.js +0 -1
- package/console-app/assets/chunk-VAUOI2AC--YVrsYCZ.js +0 -1
- package/console-app/assets/chunk-XXDRQBXY-By-5aH9h.js +0 -1
- package/console-app/assets/classDiagram-OUVF2IWQ-Bg6U871E.js +0 -1
- package/console-app/assets/classDiagram-v2-EOCWNBFH-Bg6U871E.js +0 -1
- package/console-app/assets/eventmodeling-45OFAUF4-eU2Q2DYK.js +0 -1
- package/console-app/assets/flowDiagram-23GEKE2U-CtRJ8nYJ.js +0 -1
- package/console-app/assets/railroad-abnf-AHOZXSZD-BM21cj3I.js +0 -1
- package/console-app/assets/railroad-ebnf-EBAXGLYW-CDjo5TUI.js +0 -1
- package/console-app/assets/railroad-peg-LSFZ7HO6-CiKQmfgW.js +0 -1
- package/console-app/assets/stateDiagram-v2-6OUMAXLB-BIGwMDyj.js +0 -1
- package/console-app/assets/swimlanesDiagram-G3AALYLV-BsoUfqN-.js +0 -8
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { join, relative, resolve } from 'node:path';
|
|
4
|
+
import ts from 'typescript';
|
|
5
|
+
const SOURCE_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts'];
|
|
6
|
+
const MODULE_EXTENSIONS = [...SOURCE_EXTENSIONS, '.js', '.jsx', '.mjs', '.cjs'];
|
|
7
|
+
const wildcardStem = (fileName) => {
|
|
8
|
+
if (fileName.endsWith('.map'))
|
|
9
|
+
return null;
|
|
10
|
+
if (/\.d\.(ts|mts|cts)$/.test(fileName))
|
|
11
|
+
return null;
|
|
12
|
+
const extension = MODULE_EXTENSIONS.find((each) => fileName.endsWith(each));
|
|
13
|
+
return extension ? fileName.slice(0, -extension.length) : null;
|
|
14
|
+
};
|
|
15
|
+
const subpathMap = (exports) => {
|
|
16
|
+
if (typeof exports === 'string')
|
|
17
|
+
return { '.': exports };
|
|
18
|
+
return Object.keys(exports).some((key) => key.startsWith('.'))
|
|
19
|
+
? exports
|
|
20
|
+
: { '.': exports };
|
|
21
|
+
};
|
|
22
|
+
const publishesCode = (target) => !/\.(css|scss|json|svg|png|woff2?|txt|md)$/.test(target);
|
|
23
|
+
const sourceForTarget = (packageDir, target, outDir) => {
|
|
24
|
+
const withoutPrefix = target.replace(/^\.\//, '');
|
|
25
|
+
const isDeclaration = /\.d\.(ts|mts|cts)$/.test(withoutPrefix);
|
|
26
|
+
if (!isDeclaration &&
|
|
27
|
+
SOURCE_EXTENSIONS.some((extension) => withoutPrefix.endsWith(extension))) {
|
|
28
|
+
return existsSync(join(packageDir, withoutPrefix)) ? withoutPrefix : null;
|
|
29
|
+
}
|
|
30
|
+
const stripped = withoutPrefix.startsWith(`${outDir}/`)
|
|
31
|
+
? withoutPrefix.slice(outDir.length + 1)
|
|
32
|
+
: withoutPrefix;
|
|
33
|
+
const base = stripped
|
|
34
|
+
.replace(/\.d\.(ts|mts|cts)$/, '')
|
|
35
|
+
.replace(/\.(js|jsx|mjs|cjs)$/, '');
|
|
36
|
+
const withoutSrc = base.startsWith('src/') ? base.slice(4) : base;
|
|
37
|
+
const candidates = [];
|
|
38
|
+
for (const extension of SOURCE_EXTENSIONS) {
|
|
39
|
+
candidates.push(join('src', `${base}${extension}`), `${base}${extension}`, join('src', `${withoutSrc}${extension}`), join('src', base, `index${extension}`), join(base, `index${extension}`));
|
|
40
|
+
}
|
|
41
|
+
for (const candidate of candidates) {
|
|
42
|
+
if (existsSync(join(packageDir, candidate)))
|
|
43
|
+
return candidate;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
};
|
|
47
|
+
const expandWildcard = (packageDir, subpath, target) => {
|
|
48
|
+
const targetDir = target.replace(/^\.\//, '').split('*')[0] ?? '';
|
|
49
|
+
const suffix = target.slice(target.indexOf('*') + 1);
|
|
50
|
+
const absolute = join(packageDir, targetDir);
|
|
51
|
+
if (!existsSync(absolute))
|
|
52
|
+
return [];
|
|
53
|
+
const expanded = [];
|
|
54
|
+
const walk = (directory, prefix) => {
|
|
55
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
56
|
+
if (entry.isDirectory()) {
|
|
57
|
+
walk(join(directory, entry.name), `${prefix}${entry.name}/`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (!entry.isFile())
|
|
61
|
+
continue;
|
|
62
|
+
if (suffix && !entry.name.endsWith(suffix))
|
|
63
|
+
continue;
|
|
64
|
+
const stem = wildcardStem(entry.name);
|
|
65
|
+
if (stem === null)
|
|
66
|
+
continue;
|
|
67
|
+
expanded.push({
|
|
68
|
+
subpath: subpath.replace('*', `${prefix}${stem}`),
|
|
69
|
+
target: `${targetDir}${prefix}${entry.name}`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
walk(absolute, '');
|
|
74
|
+
return expanded;
|
|
75
|
+
};
|
|
76
|
+
const targetOf = (value) => {
|
|
77
|
+
if (typeof value === 'string')
|
|
78
|
+
return value;
|
|
79
|
+
if (!value || typeof value !== 'object')
|
|
80
|
+
return null;
|
|
81
|
+
const conditions = value;
|
|
82
|
+
for (const key of ['types', 'import', 'default', 'require']) {
|
|
83
|
+
const resolved = targetOf(conditions[key]);
|
|
84
|
+
if (resolved)
|
|
85
|
+
return resolved;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
};
|
|
89
|
+
const readJson = async (path) => {
|
|
90
|
+
try {
|
|
91
|
+
return JSON.parse(await readFile(path, 'utf8'));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const readCompilerOptions = async (packageDir) => {
|
|
98
|
+
const configPath = join(packageDir, 'tsconfig.json');
|
|
99
|
+
if (!existsSync(configPath))
|
|
100
|
+
return { outDir: 'dist', paths: {} };
|
|
101
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
102
|
+
if (configFile.error)
|
|
103
|
+
return { outDir: 'dist', paths: {} };
|
|
104
|
+
const { options } = ts.parseJsonConfigFileContent(configFile.config, ts.sys, packageDir);
|
|
105
|
+
const { baseUrl, paths, pathsBasePath } = options;
|
|
106
|
+
return {
|
|
107
|
+
outDir: options.outDir ? relative(packageDir, options.outDir) : 'dist',
|
|
108
|
+
paths: {
|
|
109
|
+
...(baseUrl !== undefined ? { baseUrl } : {}),
|
|
110
|
+
...(paths !== undefined ? { paths } : {}),
|
|
111
|
+
...(pathsBasePath !== undefined ? { pathsBasePath } : {}),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
const KIND_BY_FLAG = [
|
|
116
|
+
[ts.SymbolFlags.Class, 'class'],
|
|
117
|
+
[ts.SymbolFlags.Interface, 'interface'],
|
|
118
|
+
[ts.SymbolFlags.RegularEnum | ts.SymbolFlags.ConstEnum, 'enum'],
|
|
119
|
+
[ts.SymbolFlags.Function, 'function'],
|
|
120
|
+
[ts.SymbolFlags.TypeAlias, 'type'],
|
|
121
|
+
[ts.SymbolFlags.Namespace, 'namespace'],
|
|
122
|
+
];
|
|
123
|
+
const kindOf = (symbol, checker) => {
|
|
124
|
+
const target = symbol.flags & ts.SymbolFlags.Alias
|
|
125
|
+
? checker.getAliasedSymbol(symbol)
|
|
126
|
+
: symbol;
|
|
127
|
+
for (const [flag, kind] of KIND_BY_FLAG) {
|
|
128
|
+
if (target.flags & flag)
|
|
129
|
+
return kind;
|
|
130
|
+
}
|
|
131
|
+
if (target.flags & ts.SymbolFlags.Variable) {
|
|
132
|
+
const declaration = target.declarations?.[0];
|
|
133
|
+
if (declaration) {
|
|
134
|
+
const type = checker.getTypeOfSymbolAtLocation(target, declaration);
|
|
135
|
+
if (type.getCallSignatures().length > 0)
|
|
136
|
+
return 'function';
|
|
137
|
+
}
|
|
138
|
+
return 'const';
|
|
139
|
+
}
|
|
140
|
+
return 'const';
|
|
141
|
+
};
|
|
142
|
+
const isDeprecated = (symbol) => symbol.getJsDocTags().some((tag) => tag.name === 'deprecated');
|
|
143
|
+
const declarationFileOf = (symbol, checker) => {
|
|
144
|
+
const target = symbol.flags & ts.SymbolFlags.Alias
|
|
145
|
+
? checker.getAliasedSymbol(symbol)
|
|
146
|
+
: symbol;
|
|
147
|
+
const declaration = target.declarations?.[0] ?? symbol.declarations?.[0];
|
|
148
|
+
return declaration?.getSourceFile().fileName ?? null;
|
|
149
|
+
};
|
|
150
|
+
export const collectSurface = async (packageDir) => {
|
|
151
|
+
const root = resolve(packageDir);
|
|
152
|
+
const packageJson = await readJson(join(root, 'package.json'));
|
|
153
|
+
if (!packageJson?.exports)
|
|
154
|
+
return [];
|
|
155
|
+
const { outDir, paths } = await readCompilerOptions(root);
|
|
156
|
+
const packageName = packageJson.name ?? '';
|
|
157
|
+
const entries = [];
|
|
158
|
+
const seenEntryFiles = new Set();
|
|
159
|
+
for (const [subpath, value] of Object.entries(subpathMap(packageJson.exports))) {
|
|
160
|
+
if (!subpath.startsWith('.'))
|
|
161
|
+
continue;
|
|
162
|
+
const target = targetOf(value);
|
|
163
|
+
if (!target || !publishesCode(target))
|
|
164
|
+
continue;
|
|
165
|
+
const declared = target.includes('*')
|
|
166
|
+
? expandWildcard(root, subpath, target)
|
|
167
|
+
: [{ subpath, target }];
|
|
168
|
+
for (const each of declared) {
|
|
169
|
+
const entryFile = sourceForTarget(root, each.target, outDir);
|
|
170
|
+
if (!entryFile || seenEntryFiles.has(entryFile))
|
|
171
|
+
continue;
|
|
172
|
+
seenEntryFiles.add(entryFile);
|
|
173
|
+
entries.push({
|
|
174
|
+
subpath: each.subpath,
|
|
175
|
+
specifier: each.subpath === '.'
|
|
176
|
+
? packageName
|
|
177
|
+
: `${packageName}${each.subpath.slice(1)}`,
|
|
178
|
+
entryFile,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (entries.length === 0)
|
|
183
|
+
return [];
|
|
184
|
+
const program = ts.createProgram(entries.map((entry) => join(root, entry.entryFile)), {
|
|
185
|
+
...paths,
|
|
186
|
+
target: ts.ScriptTarget.ESNext,
|
|
187
|
+
module: ts.ModuleKind.Node16,
|
|
188
|
+
moduleResolution: ts.ModuleResolutionKind.Node16,
|
|
189
|
+
skipLibCheck: true,
|
|
190
|
+
skipDefaultLibCheck: true,
|
|
191
|
+
types: [],
|
|
192
|
+
allowJs: false,
|
|
193
|
+
checkJs: false,
|
|
194
|
+
});
|
|
195
|
+
const checker = program.getTypeChecker();
|
|
196
|
+
return entries.map((entry) => {
|
|
197
|
+
const sourceFile = program.getSourceFile(join(root, entry.entryFile));
|
|
198
|
+
const moduleSymbol = sourceFile
|
|
199
|
+
? checker.getSymbolAtLocation(sourceFile)
|
|
200
|
+
: undefined;
|
|
201
|
+
const symbols = [];
|
|
202
|
+
for (const symbol of moduleSymbol
|
|
203
|
+
? checker.getExportsOfModule(moduleSymbol)
|
|
204
|
+
: []) {
|
|
205
|
+
const file = declarationFileOf(symbol, checker);
|
|
206
|
+
symbols.push({
|
|
207
|
+
name: symbol.getName(),
|
|
208
|
+
kind: kindOf(symbol, checker),
|
|
209
|
+
declaredAt: file ? relative(root, file) : entry.entryFile,
|
|
210
|
+
deprecated: isDeprecated(symbol),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return { ...entry, symbols };
|
|
214
|
+
});
|
|
215
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ValidateFinding } from './persona-checks.js';
|
|
2
|
+
/**
|
|
3
|
+
* A linked dependency resolves its own imports from its own checkout, so it can
|
|
4
|
+
* hand the project types built against a different version of a shared package.
|
|
5
|
+
* The symptom is a typecheck that OOMs rather than one that fails, so nothing
|
|
6
|
+
* else in this validator would catch it.
|
|
7
|
+
*
|
|
8
|
+
* Runs against the workspace root only. The mismatch is a property of the
|
|
9
|
+
* install, not of any one package in it, so running per workspace package would
|
|
10
|
+
* report the same pair once per package.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runTypeIdentityChecks(root: string): Promise<ValidateFinding[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Preflight for codegen. Runs BEFORE the typecheck, because the failure it
|
|
15
|
+
* explains kills the process rather than failing it: a V8 heap OOM aborts, so
|
|
16
|
+
* nothing printed after the fact is ever seen. By the time the user has a
|
|
17
|
+
* symptom, the only thing that can help them is already on screen above it.
|
|
18
|
+
*
|
|
19
|
+
* Warns rather than throws. A skewed linked dependency is a strong signal, not
|
|
20
|
+
* a certainty — plenty of them are harmless, and refusing to build on one would
|
|
21
|
+
* break working setups over a heuristic.
|
|
22
|
+
*/
|
|
23
|
+
export declare function warnOnSplitTypeIdentity(rootDir: string, logger: {
|
|
24
|
+
warn: (message: string) => void;
|
|
25
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { lstat, readdir, realpath } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join, relative } from 'node:path';
|
|
4
|
+
import { ErrorCode } from '@pikku/inspector';
|
|
5
|
+
import { readJsonSafe } from './shared-checks.js';
|
|
6
|
+
/**
|
|
7
|
+
* Packages whose TYPE identity matters, not just their runtime identity.
|
|
8
|
+
*
|
|
9
|
+
* Two copies of one of these at different versions give TypeScript two
|
|
10
|
+
* unrelated declarations of the same interface, and every place they meet
|
|
11
|
+
* becomes a structural comparison of the full shape. Inside a generic inference
|
|
12
|
+
* chain that compounds: one project went from a 1.3GB/13s typecheck to an
|
|
13
|
+
* unbounded OOM (8GB and 12GB ceilings both died, 7.7M types, single
|
|
14
|
+
* assignability checks taking 8s) because one dependency's `dist` was symlinked
|
|
15
|
+
* into a sibling checkout that carried its own better-auth. It reads as "codegen
|
|
16
|
+
* is slow", never as a version problem, which is why it is worth a check.
|
|
17
|
+
*
|
|
18
|
+
* Distinct from the duplicate-copy check, which is two copies of the SAME
|
|
19
|
+
* version splitting module state at runtime. This is a compile-time blow-up and
|
|
20
|
+
* only fires when the versions differ.
|
|
21
|
+
*/
|
|
22
|
+
const TYPE_IDENTITY_PKGS = [
|
|
23
|
+
'better-auth',
|
|
24
|
+
'@better-auth/core',
|
|
25
|
+
'@pikku/core',
|
|
26
|
+
'kysely',
|
|
27
|
+
'zod',
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Installed version of `pkg` as seen FROM `fromDir`, walking parent
|
|
31
|
+
* node_modules the way node resolution does. Used to ask what a linked
|
|
32
|
+
* dependency resolves in its own checkout, which is not what the project
|
|
33
|
+
* resolves.
|
|
34
|
+
*/
|
|
35
|
+
async function versionResolvedFrom(fromDir, pkg) {
|
|
36
|
+
let dir = fromDir;
|
|
37
|
+
for (;;) {
|
|
38
|
+
const j = await readJsonSafe(join(dir, 'node_modules', pkg, 'package.json'));
|
|
39
|
+
if (j?.version)
|
|
40
|
+
return j.version;
|
|
41
|
+
const parent = dirname(dir);
|
|
42
|
+
if (parent === dir)
|
|
43
|
+
return null;
|
|
44
|
+
dir = parent;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Where `pkg` resolves for the project itself. The root alone is not enough:
|
|
49
|
+
* an isolated/pnpm-style install (bun's default) links dependencies under the
|
|
50
|
+
* workspace package that declares them and leaves the root node_modules
|
|
51
|
+
* without them, so probing only the root silently finds nothing.
|
|
52
|
+
*/
|
|
53
|
+
async function projectResolvedVersion(root, pkg) {
|
|
54
|
+
const bases = [root];
|
|
55
|
+
for (const group of ['packages', 'apps', 'backends']) {
|
|
56
|
+
const groupDir = join(root, group);
|
|
57
|
+
if (!existsSync(groupDir))
|
|
58
|
+
continue;
|
|
59
|
+
const entries = await readdir(groupDir, { withFileTypes: true }).catch(() => []);
|
|
60
|
+
for (const d of entries) {
|
|
61
|
+
if (d.isDirectory())
|
|
62
|
+
bases.push(join(groupDir, d.name));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const base of bases) {
|
|
66
|
+
const j = await readJsonSafe(join(base, 'node_modules', pkg, 'package.json'));
|
|
67
|
+
if (j?.version)
|
|
68
|
+
return { version: j.version, from: base };
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Dependencies whose code physically lives outside the project: a `link:` or
|
|
74
|
+
* `portal:` dep, or a hand-made symlink into a sibling checkout. Only these can
|
|
75
|
+
* introduce a second version of a type-identity package, because a normal
|
|
76
|
+
* install dedupes through the lockfile.
|
|
77
|
+
*
|
|
78
|
+
* The symlink is often NOT the package directory but a build output inside it
|
|
79
|
+
* (`node_modules/@scope/pkg/dist -> ../../../other-repo/packages/pkg/dist`),
|
|
80
|
+
* which still moves type resolution to the other tree since TypeScript resolves
|
|
81
|
+
* symlinks to their realpath. So each candidate subdir is probed too.
|
|
82
|
+
*
|
|
83
|
+
* Only symlinks are resolved. `realpath` lstats every component of the path, so
|
|
84
|
+
* running it over every installed package costs 20x more on a hoisted install
|
|
85
|
+
* (1781 packages at the root) than on an isolated one (35) — and a path that
|
|
86
|
+
* traverses no symlink cannot leave the project anyway. `readdir` already hands
|
|
87
|
+
* back the entry type, so ruling a package out is free.
|
|
88
|
+
*/
|
|
89
|
+
async function externalDependencyRoots(root) {
|
|
90
|
+
const found = new Map();
|
|
91
|
+
const nodeModules = join(root, 'node_modules');
|
|
92
|
+
if (!existsSync(nodeModules))
|
|
93
|
+
return found;
|
|
94
|
+
// Compare realpath against realpath: on macOS the temp/project path is often
|
|
95
|
+
// itself a symlink (/var -> /private/var), which would otherwise make every
|
|
96
|
+
// dependency look external.
|
|
97
|
+
const realRoot = await realpath(root).catch(() => root);
|
|
98
|
+
const topLevel = await readdir(nodeModules, { withFileTypes: true }).catch(() => []);
|
|
99
|
+
const pkgDirs = [];
|
|
100
|
+
for (const entry of topLevel) {
|
|
101
|
+
if (entry.name.startsWith('.'))
|
|
102
|
+
continue;
|
|
103
|
+
if (entry.name.startsWith('@')) {
|
|
104
|
+
const scoped = await readdir(join(nodeModules, entry.name), {
|
|
105
|
+
withFileTypes: true,
|
|
106
|
+
}).catch(() => []);
|
|
107
|
+
for (const inner of scoped) {
|
|
108
|
+
pkgDirs.push({
|
|
109
|
+
dir: join(nodeModules, entry.name, inner.name),
|
|
110
|
+
link: inner.isSymbolicLink(),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
pkgDirs.push({
|
|
116
|
+
dir: join(nodeModules, entry.name),
|
|
117
|
+
link: entry.isSymbolicLink(),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const linkTarget = async (path) => {
|
|
122
|
+
const stats = await lstat(path).catch(() => null);
|
|
123
|
+
if (!stats?.isSymbolicLink())
|
|
124
|
+
return null;
|
|
125
|
+
return realpath(path).catch(() => null);
|
|
126
|
+
};
|
|
127
|
+
const isExternal = (real) => relative(realRoot, real).startsWith('..');
|
|
128
|
+
for (const { dir: pkgDir, link } of pkgDirs) {
|
|
129
|
+
// A package linked to a path inside the project (bun's .bun store) is not
|
|
130
|
+
// external, but the build output *inside* that target still can be.
|
|
131
|
+
const target = link ? await realpath(pkgDir).catch(() => null) : null;
|
|
132
|
+
if (link && !target)
|
|
133
|
+
continue;
|
|
134
|
+
const candidates = [
|
|
135
|
+
target && isExternal(target) ? target : null,
|
|
136
|
+
await linkTarget(join(target ?? pkgDir, 'dist')),
|
|
137
|
+
];
|
|
138
|
+
for (const real of candidates) {
|
|
139
|
+
if (!real || !isExternal(real))
|
|
140
|
+
continue;
|
|
141
|
+
const name = relative(nodeModules, pkgDir);
|
|
142
|
+
// `real` may point at a build output (…/pkg/dist); report the linked
|
|
143
|
+
// package's own root so the message names something a reader can act on.
|
|
144
|
+
let owner = real;
|
|
145
|
+
while (!existsSync(join(owner, 'package.json')) &&
|
|
146
|
+
dirname(owner) !== owner) {
|
|
147
|
+
owner = dirname(owner);
|
|
148
|
+
}
|
|
149
|
+
if (!found.has(name))
|
|
150
|
+
found.set(name, owner);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return found;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* A linked dependency resolves its own imports from its own checkout, so it can
|
|
158
|
+
* hand the project types built against a different version of a shared package.
|
|
159
|
+
* The symptom is a typecheck that OOMs rather than one that fails, so nothing
|
|
160
|
+
* else in this validator would catch it.
|
|
161
|
+
*
|
|
162
|
+
* Runs against the workspace root only. The mismatch is a property of the
|
|
163
|
+
* install, not of any one package in it, so running per workspace package would
|
|
164
|
+
* report the same pair once per package.
|
|
165
|
+
*/
|
|
166
|
+
export async function runTypeIdentityChecks(root) {
|
|
167
|
+
const findings = [];
|
|
168
|
+
const external = await externalDependencyRoots(root);
|
|
169
|
+
if (external.size === 0)
|
|
170
|
+
return findings;
|
|
171
|
+
for (const pkg of TYPE_IDENTITY_PKGS) {
|
|
172
|
+
const local = await projectResolvedVersion(root, pkg);
|
|
173
|
+
if (!local)
|
|
174
|
+
continue;
|
|
175
|
+
const ours = local.version;
|
|
176
|
+
for (const [depName, depRoot] of external) {
|
|
177
|
+
const theirs = await versionResolvedFrom(depRoot, pkg);
|
|
178
|
+
if (!theirs || theirs === ours)
|
|
179
|
+
continue;
|
|
180
|
+
findings.push({
|
|
181
|
+
id: `split-type-identity-${depName.replace(/[@/]/g, '-')}-${pkg.replace(/[@/]/g, '-')}`,
|
|
182
|
+
severity: 'error',
|
|
183
|
+
message: `"${depName}" is linked to ${depRoot} and resolves ${pkg}@${theirs} there, while this project resolves ${pkg}@${ours} — two type identities for ${pkg}`,
|
|
184
|
+
path: join(root, 'node_modules', depName),
|
|
185
|
+
fixHint: [
|
|
186
|
+
`TypeScript treats the two ${pkg} declarations as unrelated types and structurally compares them wherever they meet, which can make a typecheck OOM instead of fail.`,
|
|
187
|
+
`Align the versions so both trees resolve one ${pkg}: either bump ${pkg} to ${theirs} here, or to ${ours} in ${depRoot}.`,
|
|
188
|
+
`If the link is no longer needed, remove it and reinstall so "${depName}" comes from the registry.`,
|
|
189
|
+
].join('\n'),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return findings;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Preflight for codegen. Runs BEFORE the typecheck, because the failure it
|
|
197
|
+
* explains kills the process rather than failing it: a V8 heap OOM aborts, so
|
|
198
|
+
* nothing printed after the fact is ever seen. By the time the user has a
|
|
199
|
+
* symptom, the only thing that can help them is already on screen above it.
|
|
200
|
+
*
|
|
201
|
+
* Warns rather than throws. A skewed linked dependency is a strong signal, not
|
|
202
|
+
* a certainty — plenty of them are harmless, and refusing to build on one would
|
|
203
|
+
* break working setups over a heuristic.
|
|
204
|
+
*/
|
|
205
|
+
export async function warnOnSplitTypeIdentity(rootDir, logger) {
|
|
206
|
+
if (process.env?.PIKKU_SKIP_TYPE_IDENTITY_CHECK)
|
|
207
|
+
return;
|
|
208
|
+
const findings = await runTypeIdentityChecks(rootDir).catch(() => []);
|
|
209
|
+
if (findings.length === 0)
|
|
210
|
+
return;
|
|
211
|
+
logger.warn(`[${ErrorCode.SPLIT_TYPE_IDENTITY}] ${findings.length === 1 ? 'A linked dependency resolves a shared package' : 'Linked dependencies resolve shared packages'} at a different version than this project:\n` +
|
|
212
|
+
findings.map((f) => ` ${f.message}`).join('\n') +
|
|
213
|
+
`\nTypeScript treats each pair as two unrelated types and structurally compares them\n` +
|
|
214
|
+
`wherever they meet, which inside a generic inference chain can exhaust the heap —\n` +
|
|
215
|
+
`codegen then dies of memory pressure instead of reporting an error.\n\n` +
|
|
216
|
+
`Fix: align the versions so both trees resolve one copy, or drop the link and\n` +
|
|
217
|
+
`reinstall. Set PIKKU_SKIP_TYPE_IDENTITY_CHECK=1 to silence this.`);
|
|
218
|
+
}
|
|
@@ -3,6 +3,7 @@ import { readdir } from 'node:fs/promises';
|
|
|
3
3
|
import { join, relative } from 'node:path';
|
|
4
4
|
import { isAddonPackage, runAddonPackageChecks, } from './addon-package-checks.js';
|
|
5
5
|
import { runSharedProjectChecks } from './shared-checks.js';
|
|
6
|
+
import { runTypeIdentityChecks } from './type-identity-checks.js';
|
|
6
7
|
/** A hand-written `types/application-types.d.ts` beside package.json. */
|
|
7
8
|
const ADDON_MARKER = join('types', 'application-types.d.ts');
|
|
8
9
|
const SKIP_DIRS = new Set([
|
|
@@ -68,6 +69,16 @@ export const CHECKS = [
|
|
|
68
69
|
applies: async ({ dir }) => isAddonPackage(dir),
|
|
69
70
|
run: async ({ dir }) => runAddonPackageChecks(dir),
|
|
70
71
|
},
|
|
72
|
+
{
|
|
73
|
+
id: 'type-identity',
|
|
74
|
+
subject: 'linked dependencies',
|
|
75
|
+
// Root of an installed tree only. A linked dependency is a property of the
|
|
76
|
+
// install as a whole, so running this per workspace package reports the
|
|
77
|
+
// same pair N times — and with nothing installed there is nothing to
|
|
78
|
+
// compare.
|
|
79
|
+
applies: async ({ dir, label }) => label === '.' && existsSync(join(dir, 'node_modules')),
|
|
80
|
+
run: async ({ dir }) => runTypeIdentityChecks(dir),
|
|
81
|
+
},
|
|
71
82
|
];
|
|
72
83
|
export async function planValidation(root) {
|
|
73
84
|
const plan = [];
|
|
@@ -11,11 +11,12 @@ export const serializeScenarioRegistration = (outputPath, metaImportPath, scenar
|
|
|
11
11
|
return 'export {}';
|
|
12
12
|
}
|
|
13
13
|
const lines = [];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
if (hasScenarios) {
|
|
15
|
+
lines.push(`import { addWorkflow } from '@pikku/core/workflow'`);
|
|
16
|
+
}
|
|
17
|
+
if (hasFeatures) {
|
|
18
|
+
lines.push(`import { addFeature } from '@pikku/core/scenario'`);
|
|
19
|
+
}
|
|
19
20
|
lines.push(`import '${metaImportPath}'`);
|
|
20
21
|
const sortedScenarios = Array.from(scenarioFiles.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
21
22
|
// A feature holds the very objects its scenarios were registered with, so it
|
|
@@ -9,11 +9,8 @@
|
|
|
9
9
|
export const serializePersonas = (personas, agentMapImportPath, rpcMapImportPath) => {
|
|
10
10
|
return `/** Personas declared with definePersonas() */
|
|
11
11
|
import { createHttpPersonas } from '@pikku/core/persona'
|
|
12
|
-
import type {
|
|
13
|
-
|
|
14
|
-
ScenarioPersona,
|
|
15
|
-
ResolvedPersona,
|
|
16
|
-
} from '@pikku/core/services'
|
|
12
|
+
import type { HttpPersonasConfig } from '@pikku/core/persona'
|
|
13
|
+
import type { ScenarioPersona, ResolvedPersona } from '@pikku/core/services'
|
|
17
14
|
import type { AgentMap } from '${agentMapImportPath}'
|
|
18
15
|
import type { FlattenedRPCMap } from '${rpcMapImportPath}'
|
|
19
16
|
|
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
type PikkuWorkflowGraphConfig,
|
|
7
7
|
type PikkuWorkflowGraphResult,
|
|
8
8
|
} from '@pikku/core/workflow'
|
|
9
|
-
import type { PikkuWorkflowWire,
|
|
9
|
+
import type { PikkuWorkflowWire, WorkflowStepOptions } from '@pikku/core/workflow'
|
|
10
|
+
import type { PikkuScenarioWire, ScenarioStepOptions } from '@pikku/core/scenario'
|
|
10
11
|
|
|
11
12
|
export { WorkflowCancelledException }
|
|
12
13
|
import type { PikkuFunctionSessionless, PikkuFunctionConfig, WiredServices } from '${functionTypesImportPath}'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
2
|
import { pikkuWorkflowComplexFunc } from '#pikku/workflow/pikku-workflow-types.gen.js';
|
|
3
3
|
import { assertSingleCoreVersion } from '../../utils/assert-single-core-version.js';
|
|
4
|
+
import { warnOnSplitTypeIdentity } from '../validate/type-identity-checks.js';
|
|
4
5
|
import { pruneLegacyScaffoldFiles, removeRetiredScaffoldFiles, } from '../../utils/remove-legacy-scaffold-file.js';
|
|
5
6
|
import { PikkuTypecheckFailedError, renderTscFull, renderTscSummary, runProjectTypecheck, } from '../../utils/tsc-check.js';
|
|
6
7
|
const scaffoldFiles = (config) => {
|
|
@@ -45,6 +46,10 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
|
|
|
45
46
|
// Preflight: a split @pikku/core install silently breaks wiring registration
|
|
46
47
|
// (workflows/RPCs "disappear"), so refuse to codegen against it.
|
|
47
48
|
await assertSingleCoreVersion(config.rootDir, logger);
|
|
49
|
+
// Preflight: a linked dependency at a skewed version can exhaust the heap
|
|
50
|
+
// during the typecheck below, and an OOM aborts before anything can explain
|
|
51
|
+
// it. Say it now or never.
|
|
52
|
+
await warnOnSplitTypeIdentity(config.rootDir, logger);
|
|
48
53
|
await pruneLegacyScaffoldFiles(config);
|
|
49
54
|
await removeRetiredScaffoldFiles(config);
|
|
50
55
|
const allImports = [];
|