@ws-test-realm/admin-kit 0.1.7

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 (46) hide show
  1. package/README.md +89 -0
  2. package/bin/ws-drop-module.js +40 -0
  3. package/bin/ws-generate-module.js +37 -0
  4. package/bin/ws-init-workspace.js +190 -0
  5. package/bin/ws-modules.js +179 -0
  6. package/bin/ws-pack-remote.js +196 -0
  7. package/bin/ws-sync-paths.js +35 -0
  8. package/bin/ws-wire-host.js +67 -0
  9. package/bin/ws-wire-pom.js +132 -0
  10. package/lib/alias-discovery.js +40 -0
  11. package/lib/build-modules.js +84 -0
  12. package/lib/cli-args.js +55 -0
  13. package/lib/deploy-remotes.js +249 -0
  14. package/lib/drop-module.js +71 -0
  15. package/lib/emit-descriptor.js +31 -0
  16. package/lib/generate-module.js +105 -0
  17. package/lib/identity.js +49 -0
  18. package/lib/jar-glob.js +55 -0
  19. package/lib/pack-into-jar.js +74 -0
  20. package/lib/pom.js +84 -0
  21. package/lib/shared-deps.js +90 -0
  22. package/lib/synthetic-entry.js +27 -0
  23. package/lib/template-copy.js +136 -0
  24. package/lib/topo-sort.js +134 -0
  25. package/lib/webpack-factory.js +104 -0
  26. package/lib/wire-host.js +96 -0
  27. package/package.json +33 -0
  28. package/template/angular.json +14 -0
  29. package/template/package.json +26 -0
  30. package/template/tsconfig.json +7 -0
  31. package/template/wsconfig.json.example +4 -0
  32. package/template-module/assets/i18n/de.json +1 -0
  33. package/template-module/assets/i18n/en.json +1 -0
  34. package/template-module/assets/i18n/fr.json +1 -0
  35. package/template-module/assets/i18n/general/de.json +1 -0
  36. package/template-module/assets/i18n/general/en.json +1 -0
  37. package/template-module/assets/i18n/general/fr.json +1 -0
  38. package/template-module/ng-package.json +8 -0
  39. package/template-module/package.json +14 -0
  40. package/template-module/src/lib/__name__.module.ts +11 -0
  41. package/template-module/src/lib/components/__name__/__name__.component.html +1 -0
  42. package/template-module/src/lib/components/__name__/__name__.component.scss +0 -0
  43. package/template-module/src/lib/components/__name__/__name__.component.ts +8 -0
  44. package/template-module/src/public-api.ts +6 -0
  45. package/template-module/tsconfig.lib.json +13 -0
  46. package/template-module/tsconfig.lib.prod.json +9 -0
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @moodia/ws-schematics-remotes
2
+
3
+ Provisional Node CLI for building federated admin remotes. Wraps an
4
+ already-built lib dist into a `<id>/{federation.json, remote/*}` layout
5
+ that drops directly into the admin federation controller's serving
6
+ directory or into a jar for jar-served deployment.
7
+
8
+ ## Install (local, until published)
9
+
10
+ ```
11
+ cd /Users/ph/projects/ws-admin/ws-schematics-remotes
12
+ npm install
13
+ npm link
14
+ ```
15
+
16
+ `ws-pack-remote` is now available globally.
17
+
18
+ ## Use
19
+
20
+ ```
21
+ # from the workspace root (e.g. runtime-admin-modules)
22
+ npx ng build crm # produce dist/crm
23
+ ws-pack-remote --project projects/crm --workspace . # produce dist/admin-remotes/crm/
24
+ ```
25
+
26
+ Output:
27
+
28
+ ```
29
+ dist/admin-remotes/crm/
30
+ federation.json
31
+ remote/
32
+ remoteEntry.js
33
+ *.js
34
+ ```
35
+
36
+ Deploy with a single rsync:
37
+
38
+ ```
39
+ rsync -a --delete dist/admin-remotes/crm/ \
40
+ /Users/ph/projects/wpm/ws-fiddle/scripts/ext-admin-remotes/crm/
41
+ ```
42
+
43
+ ## Identity defaults (no config required)
44
+
45
+ | field | default |
46
+ | ------------- | -------------------------- |
47
+ | `id` | `path.basename(--project)` |
48
+ | `hostId` | `"admin"` |
49
+ | `remoteName` | `camelCase(id) + "Module"` |
50
+ | `exposes` | `"./Module"` |
51
+ | `displayName` | `id` |
52
+
53
+ Override any of these via CLI flags. For rare cases where convention
54
+ isn't enough, drop a `pack.config.json` in the project root — see below.
55
+
56
+ ## CLI
57
+
58
+ ```
59
+ ws-pack-remote
60
+ --project <path> required: lib project root
61
+ --workspace <path> required: workspace root (resolves dist/<lib>)
62
+ [--out <dir>] default: <workspace>/dist/admin-remotes
63
+ [--id <id>]
64
+ [--host <hostId>]
65
+ [--remote-name <s>]
66
+ [--exposes <key>]
67
+ [--display-name <s>]
68
+ [--config <file>] alt path to pack.config.json
69
+ ```
70
+
71
+ ## `pack.config.json` (optional escape hatch)
72
+
73
+ Used only when convention can't capture intent (id ≠ dir name, project-
74
+ specific shared overrides, non-default hostId). Every field optional:
75
+
76
+ ```json
77
+ {
78
+ "id": "crm",
79
+ "hostId": "admin",
80
+ "remoteName": "crmModule",
81
+ "exposes": "./Module",
82
+ "displayName": "crm",
83
+ "sharedExtras": {
84
+ "<package>": { "singleton": true, "requiredVersion": false }
85
+ }
86
+ }
87
+ ```
88
+
89
+ Identity precedence: CLI > pack.config.json > defaults.
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ // ws-drop-module — remove a federated admin module from the current
3
+ // workspace. Deletes projects/<name>/, the angular.json entry, rebuilds
4
+ // tsconfig.federation.json without it, plus any dist/<name> and
5
+ // dist/admin-remotes/<name> build artifacts.
6
+ //
7
+ // Usage:
8
+ // ws-drop-module <name>
9
+
10
+ const { dropModule } = require("../lib/drop-module");
11
+
12
+ function main() {
13
+ const positional = process.argv
14
+ .slice(2)
15
+ .filter((a) => !a.startsWith("--"));
16
+ const name = positional[0];
17
+ if (!name) {
18
+ console.error("Usage: ws-drop-module <name>");
19
+ process.exit(1);
20
+ }
21
+ try {
22
+ const r = dropModule({ workspaceDir: process.cwd(), name });
23
+ console.log(`Dropped module ${name}.`);
24
+ if (r.projectExisted) console.log(` - removed projects/${name}/`);
25
+ if (r.angularChanged)
26
+ console.log(` - removed projects.${name} from angular.json`);
27
+ if (r.federationTsconfigUpdated)
28
+ console.log(
29
+ ` - rebuilt tsconfig.federation.json without ${name}`
30
+ );
31
+ if (r.distCleaned) console.log(` - removed dist/${name}/`);
32
+ if (r.distRemoteCleaned)
33
+ console.log(` - removed dist/admin-remotes/${name}/`);
34
+ } catch (e) {
35
+ console.error(e.message);
36
+ process.exit(1);
37
+ }
38
+ }
39
+
40
+ main();
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ // ws-generate-module — scaffold a federated admin module project under
3
+ // projects/<name>/ in the current workspace. Updates angular.json and
4
+ // tsconfig.json paths.
5
+ //
6
+ // Usage:
7
+ // ws-generate-module <name>
8
+
9
+ const path = require("path");
10
+ const { generateModule } = require("../lib/generate-module");
11
+
12
+ function main() {
13
+ const positional = process.argv.slice(2).filter((a) => !a.startsWith("--"));
14
+ const name = positional[0];
15
+ if (!name) {
16
+ console.error("Usage: ws-generate-module <name>");
17
+ process.exit(1);
18
+ }
19
+
20
+ const workspaceDir = process.cwd();
21
+ const templateModuleDir = path.join(__dirname, "..", "template-module");
22
+
23
+ try {
24
+ const { projectDir } = generateModule({
25
+ workspaceDir,
26
+ name,
27
+ templateModuleDir,
28
+ });
29
+ console.log(`Generated ${path.relative(workspaceDir, projectDir)}/`);
30
+ console.log(`Updated angular.json + tsconfig.json with the new project.`);
31
+ } catch (e) {
32
+ console.error(e.message);
33
+ process.exit(1);
34
+ }
35
+ }
36
+
37
+ main();
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ // ws-init-workspace — initialize an admin-modules workspace in PWD.
3
+ //
4
+ // Steps:
5
+ // 1. Refuse if PWD already has angular.json (don't clobber an existing workspace).
6
+ // 2. If no package.json, run `npm init -y` to create a minimal one.
7
+ // 3. Merge template/package.json fields into PWD's package.json. Conflicts
8
+ // (existing scripts/deps/etc. with different values than the template's)
9
+ // cause the script to abort with a report — user resolves and re-runs.
10
+ // 4. Copy the rest of template/ (angular.json, tsconfig.json, etc.) — skip
11
+ // any file that already exists.
12
+ // 5. Run `npm install` to materialize the merged deps.
13
+ // 6. If --wpm-root was passed, wire wsconfig.json + tsconfig.federation.json.
14
+ //
15
+ // Usage:
16
+ // ws-init-workspace [--wpm-root <path>] [--host-id <id>]
17
+ //
18
+ // Designed to be invoked as `npx ws-init-workspace` from inside a project that
19
+ // has already `npm install --save-dev @wiresphere/admin-kit`'d (or one that
20
+ // hasn't — step 2 covers that case).
21
+
22
+ const fs = require("fs");
23
+ const path = require("path");
24
+ const { execSync } = require("child_process");
25
+ const {
26
+ copyTemplate,
27
+ mergePackageJson,
28
+ writePackageJson,
29
+ } = require("../lib/template-copy");
30
+ const { applyWpmRoot } = require("../lib/wire-host");
31
+
32
+ function parseArgs(argv) {
33
+ const aliases = { "wpm-root": "wpmRoot", "host-id": "hostId" };
34
+ const args = {};
35
+ for (let i = 2; i < argv.length; i++) {
36
+ const a = argv[i];
37
+ if (!a.startsWith("--")) continue;
38
+ const key = a.slice(2);
39
+ const mapped = aliases[key];
40
+ if (!mapped) {
41
+ console.error(`Unknown flag: --${key}`);
42
+ process.exit(1);
43
+ }
44
+ const val = argv[i + 1];
45
+ if (val === undefined || val.startsWith("--")) {
46
+ args[mapped] = true;
47
+ } else {
48
+ args[mapped] = val;
49
+ i++;
50
+ }
51
+ }
52
+ return args;
53
+ }
54
+
55
+ function ensurePackageJson(cwd) {
56
+ const pkgPath = path.join(cwd, "package.json");
57
+ if (fs.existsSync(pkgPath)) return { created: false };
58
+ console.log("No package.json found — running `npm init -y`...");
59
+ execSync("npm init -y", { cwd, stdio: "inherit" });
60
+ return { created: true };
61
+ }
62
+
63
+ function main() {
64
+ const args = parseArgs(process.argv);
65
+ const wpmRoot = args.wpmRoot && args.wpmRoot !== true ? args.wpmRoot : null;
66
+ const hostId = args.hostId && args.hostId !== true ? args.hostId : "admin";
67
+ const cwd = process.cwd();
68
+
69
+ if (fs.existsSync(path.join(cwd, "angular.json"))) {
70
+ console.error(
71
+ `angular.json already exists in ${cwd}; refusing to clobber an existing workspace.`
72
+ );
73
+ process.exit(1);
74
+ }
75
+
76
+ ensurePackageJson(cwd);
77
+
78
+ const templateDir = path.join(__dirname, "..", "template");
79
+ const templatePkg = path.join(templateDir, "package.json");
80
+ const destPkg = path.join(cwd, "package.json");
81
+
82
+ console.log(`\nMerging template package.json into ${destPkg}`);
83
+ const { conflicts, merged } = mergePackageJson(destPkg, templatePkg);
84
+ if (conflicts.length) {
85
+ console.error("Refusing to merge — conflicts:");
86
+ for (const c of conflicts) {
87
+ console.error(
88
+ ` - ${c.path}: existing=${JSON.stringify(c.existing)} incoming=${JSON.stringify(c.incoming)}`
89
+ );
90
+ }
91
+ console.error(
92
+ "Resolve these in your package.json (or remove the conflicting keys) and re-run."
93
+ );
94
+ process.exit(1);
95
+ }
96
+
97
+ // Self-inject admin-kit into devDependencies so the workspace's bins resolve
98
+ // via `node_modules/.bin/` after the post-merge `npm install`. We read our
99
+ // own version rather than hard-coding it.
100
+ const ownPkg = JSON.parse(
101
+ fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8")
102
+ );
103
+ merged.devDependencies = merged.devDependencies || {};
104
+ if (!merged.devDependencies[ownPkg.name]) {
105
+ merged.devDependencies[ownPkg.name] = `^${ownPkg.version}`;
106
+ }
107
+
108
+ // Stamp @wiresphere/shared's `getOverrides()` into the workspace's
109
+ // `overrides` block. npm's overrides field is the only mechanism that
110
+ // forces a single version across the whole dep tree (peerDeps just trigger
111
+ // conflicts, regular deps nest). Shared exports the canonical pin set so
112
+ // every workspace ends up with the same values. Re-running is idempotent —
113
+ // existing override entries are overwritten with shared's current values.
114
+ try {
115
+ const { getOverrides } = require("@ws-test-realm/shared");
116
+ const overrides = getOverrides();
117
+ merged.overrides = Object.assign({}, merged.overrides || {}, overrides);
118
+ console.log(
119
+ `\nStamped ${Object.keys(overrides).length} overrides from @wiresphere/shared`
120
+ );
121
+ } catch (e) {
122
+ console.error(
123
+ `Warning: could not stamp overrides from @wiresphere/shared (${e.message}). Workspace may have version-drift issues at install time.`
124
+ );
125
+ }
126
+
127
+ // Stamp @wiresphere/devkit's `engines` into the workspace so npm warns on
128
+ // Node/npm version drift. devkit is the toolchain BOM — it owns the answer
129
+ // to "which Node/npm does this stack work with". Also drops a .nvmrc so
130
+ // nvm users get auto-switched on cd.
131
+ try {
132
+ const devkitPkg = require("@ws-test-realm/devkit/package.json");
133
+ if (devkitPkg.engines) {
134
+ merged.engines = Object.assign({}, merged.engines || {}, devkitPkg.engines);
135
+ console.log(
136
+ `Stamped engines from @wiresphere/devkit: node=${devkitPkg.engines.node}, npm=${devkitPkg.engines.npm}`
137
+ );
138
+ if (devkitPkg.engines.node) {
139
+ const nvmrcPath = path.join(cwd, ".nvmrc");
140
+ fs.writeFileSync(nvmrcPath, `${devkitPkg.engines.node}\n`);
141
+ console.log(`Wrote ${nvmrcPath}`);
142
+ }
143
+ }
144
+ } catch (e) {
145
+ console.error(
146
+ `Warning: could not stamp engines from @wiresphere/devkit (${e.message}).`
147
+ );
148
+ }
149
+
150
+ writePackageJson(destPkg, merged);
151
+
152
+ console.log(`\nCopying other template files into ${cwd}`);
153
+ const { copied, skipped } = copyTemplate(templateDir, cwd);
154
+ if (copied.length) console.log(` copied: ${copied.join(", ")}`);
155
+ if (skipped.length) console.log(` skipped: ${skipped.join(", ")} (already exist)`);
156
+
157
+ console.log("\nRunning npm install...");
158
+ try {
159
+ execSync("npm install", { cwd, stdio: "inherit" });
160
+ } catch (e) {
161
+ console.error(`npm install failed: ${e.message}`);
162
+ process.exit(1);
163
+ }
164
+
165
+ if (wpmRoot) {
166
+ console.log("\nWiring wpm-root pointer...");
167
+ try {
168
+ const result = applyWpmRoot(cwd, wpmRoot, hostId);
169
+ console.log(
170
+ `wsconfig.json:\n wpmRoot = ${result.wpmRoot}\n hostId = ${result.hostId}`
171
+ );
172
+ console.log(
173
+ `tsconfig.federation.json:\n @ws-remote/* -> ${result.federationTarget}`
174
+ );
175
+ } catch (e) {
176
+ console.error(e.message);
177
+ process.exit(1);
178
+ }
179
+ } else {
180
+ console.log(
181
+ "\nSkipping wpm-root wire (none provided). Run `ws-wire-host <path>` later."
182
+ );
183
+ }
184
+
185
+ console.log(
186
+ `\nWorkspace ready at ${cwd}.\nTry: npm run generate-module <name>`
187
+ );
188
+ }
189
+
190
+ main();
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+ // ws-modules — unified driver for build / pack / deploy across an admin-modules
3
+ // workspace.
4
+ //
5
+ // Usage:
6
+ // ws-modules <names...|all> [--build] [--pack] [--deploy] [--with-deps]
7
+ //
8
+ // <names...> one or more project names from angular.json
9
+ // all expand to every project in angular.json
10
+ // --build ng build each lib (topo-ordered)
11
+ // --pack federation-pack each lib into dist/admin-remotes/<id>/
12
+ // --deploy push jar + types into <wpmRoot>/<modulesFolder>/<id>-*.jar
13
+ // --with-deps expand selection to include each name's in-workspace deps
14
+ //
15
+ // Behaviour:
16
+ // - No args at all → print usage, exit 1
17
+ // - Positional + step flag(s) → run exactly those steps, non-interactive
18
+ // - Positional, no step flags → prompt y/n for each of build/pack/deploy
19
+ // (and --with-deps); run the selected set
20
+ // - Step flag(s) but no positional → error (need to know what to operate on)
21
+ //
22
+ // Examples:
23
+ // ws-modules all # interactive
24
+ // ws-modules db-login # interactive, just this project
25
+ // ws-modules all --build --pack --deploy # wire the whole stack
26
+ // ws-modules db-login --build --with-deps # build db-login + its deps
27
+ // ws-modules crm shop-common --pack # pack two specific projects
28
+
29
+ const readline = require("readline");
30
+ const { buildLibs, packRemotes } = require("../lib/build-modules");
31
+ const { deployRemotes } = require("../lib/deploy-remotes");
32
+
33
+ const STEP_FLAGS = ["build", "pack", "deploy"];
34
+ const PASSIVE_FLAGS = ["with-deps"];
35
+ const KNOWN_FLAGS = new Set([...STEP_FLAGS, ...PASSIVE_FLAGS]);
36
+
37
+ const USAGE = `ws-modules <names...|all> [--build] [--pack] [--deploy] [--with-deps]
38
+
39
+ Drive build / pack / deploy across an admin-modules workspace.
40
+
41
+ Positional:
42
+ <names...> one or more project names from angular.json
43
+ all expand to every project in angular.json
44
+
45
+ Step flags (run exactly the steps you list — if none, you'll be prompted):
46
+ --build ng build each lib (topo-ordered)
47
+ --pack federation-pack each lib into dist/admin-remotes/<id>/
48
+ --deploy push jar + types into <wpmRoot>/<modulesFolder>/<id>-*.jar
49
+
50
+ Other:
51
+ --with-deps expand selection to include each name's in-workspace deps
52
+
53
+ Examples:
54
+ ws-modules all
55
+ ws-modules db-login --build
56
+ ws-modules all --build --pack --deploy
57
+ ws-modules crm shop-common --pack
58
+ `;
59
+
60
+ function parseArgv(argv) {
61
+ const positional = [];
62
+ const flags = {};
63
+ for (let i = 2; i < argv.length; i++) {
64
+ const a = argv[i];
65
+ if (a.startsWith("--")) {
66
+ const name = a.slice(2);
67
+ if (!KNOWN_FLAGS.has(name)) {
68
+ console.error(`Unknown flag: --${name}`);
69
+ console.error(USAGE);
70
+ process.exit(1);
71
+ }
72
+ flags[name] = true;
73
+ } else {
74
+ positional.push(a);
75
+ }
76
+ }
77
+ return { positional, flags };
78
+ }
79
+
80
+ function resolveSelection(positional) {
81
+ if (positional.includes("all")) {
82
+ if (positional.length > 1) {
83
+ throw new Error("`all` cannot be combined with project names");
84
+ }
85
+ return [];
86
+ }
87
+ return positional;
88
+ }
89
+
90
+ function prompt(rl, question, defaultYes = true) {
91
+ const hint = defaultYes ? "Y/n" : "y/N";
92
+ return new Promise((resolve) => {
93
+ rl.question(`${question} (${hint}) `, (raw) => {
94
+ const s = (raw || "").trim().toLowerCase();
95
+ if (!s) return resolve(defaultYes);
96
+ resolve(s === "y" || s === "yes");
97
+ });
98
+ });
99
+ }
100
+
101
+ async function promptForSteps(prefillWithDeps) {
102
+ const rl = readline.createInterface({
103
+ input: process.stdin,
104
+ output: process.stdout,
105
+ });
106
+ try {
107
+ const build = await prompt(rl, "Build?", true);
108
+ const pack = await prompt(rl, "Pack?", true);
109
+ const deploy = await prompt(rl, "Deploy?", false);
110
+ const withDeps = prefillWithDeps
111
+ ? true
112
+ : await prompt(rl, "Include workspace deps?", false);
113
+ return { build, pack, deploy, withDeps };
114
+ } finally {
115
+ rl.close();
116
+ }
117
+ }
118
+
119
+ async function main() {
120
+ const argv = parseArgv(process.argv);
121
+
122
+ if (!argv.positional.length && !Object.keys(argv.flags).length) {
123
+ process.stdout.write(USAGE);
124
+ process.exit(1);
125
+ }
126
+
127
+ if (!argv.positional.length) {
128
+ console.error("ws-modules: need module names or `all`.");
129
+ console.error(USAGE);
130
+ process.exit(1);
131
+ }
132
+
133
+ let restrictTo;
134
+ try {
135
+ restrictTo = resolveSelection(argv.positional);
136
+ } catch (e) {
137
+ console.error(e.message);
138
+ process.exit(1);
139
+ }
140
+
141
+ const stepFlagsPresent = STEP_FLAGS.some((s) => argv.flags[s]);
142
+ let steps;
143
+ let withDeps;
144
+ if (stepFlagsPresent) {
145
+ steps = {
146
+ build: !!argv.flags.build,
147
+ pack: !!argv.flags.pack,
148
+ deploy: !!argv.flags.deploy,
149
+ };
150
+ withDeps = !!argv.flags["with-deps"];
151
+ } else {
152
+ const ans = await promptForSteps(!!argv.flags["with-deps"]);
153
+ steps = { build: ans.build, pack: ans.pack, deploy: ans.deploy };
154
+ withDeps = ans.withDeps;
155
+ }
156
+
157
+ if (!steps.build && !steps.pack && !steps.deploy) {
158
+ console.log("No steps selected. Nothing to do.");
159
+ return;
160
+ }
161
+
162
+ const workspaceDir = process.cwd();
163
+ const common = { workspaceDir, restrictTo, withDeps };
164
+
165
+ console.log(
166
+ `\nws-modules: ${argv.positional.join(" ")} →` +
167
+ ` build=${steps.build} pack=${steps.pack} deploy=${steps.deploy}` +
168
+ ` with-deps=${withDeps}`
169
+ );
170
+
171
+ if (steps.build) buildLibs(common);
172
+ if (steps.pack) packRemotes(common);
173
+ if (steps.deploy) deployRemotes(common);
174
+ }
175
+
176
+ main().catch((e) => {
177
+ console.error(e.stack || e.message);
178
+ process.exit(1);
179
+ });