@stackwright-pro/launch-stackwright-pro 0.4.0-alpha.15 → 0.4.0-alpha.151

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.
@@ -0,0 +1,103 @@
1
+ // packages/launch-stackwright-pro/templates/pro/scripts/pro-content-plugin.js
2
+ //
3
+ // Pro content type plugin for @stackwright/build-scripts.
4
+ //
5
+ // CONFIRMED CASE B (@stackwright/build-scripts@0.5.0-alpha.0 / types@1.2.0-alpha.0):
6
+ // The currently shipped version of build-scripts does NOT read
7
+ // `contentItemSchemas` or `knownContentTypeKeys` from plugin objects.
8
+ // Those fields first appear in @stackwright/types@1.4.0+ and will be
9
+ // consumed by build-scripts@0.7.0 when that release ships.
10
+ //
11
+ // CURRENT BEHAVIOUR (pre-0.7.0):
12
+ // `unknownContentTypes: 'warn'` in prebuild.js already prevents hard failures
13
+ // for unrecognised content types. The `beforeBuild` stub below ensures this
14
+ // plugin is a syntactically valid, callable plugin (not silently ignored by
15
+ // the plugin runner) even though there is no side-effect to execute yet.
16
+ //
17
+ // TODO(@stackwright/build-scripts@0.7.0): Once 0.7.0 is the resolved floor,
18
+ // remove the `beforeBuild` stub — `contentItemSchemas` and
19
+ // `knownContentTypeKeys` will be consumed natively by the runtime and the
20
+ // plugin will suppress "unknown content type" warnings automatically.
21
+
22
+ 'use strict';
23
+
24
+ const { z } = require('zod');
25
+
26
+ const PRO_CONTENT_TYPE_KEYS = [
27
+ // @stackwright-pro/display-components
28
+ 'metric_card',
29
+ 'status_badge',
30
+ 'stat_bar',
31
+ 'sparkline',
32
+ 'activity_feed',
33
+ 'dashboard_grid',
34
+ 'data_table',
35
+ 'json_viewer',
36
+ 'action_bar',
37
+ 'section',
38
+ 'collection_listing',
39
+ 'detail_field',
40
+ 'detail_view',
41
+ // @stackwright-pro/pulse
42
+ 'pulse_provider',
43
+ 'metric_card_pulse',
44
+ 'data_table_pulse',
45
+ 'status_badge_pulse',
46
+ 'detail_card_pulse',
47
+ 'stats_grid',
48
+ 'map_pulse',
49
+ 'alert_banner',
50
+ // @stackwright-pro/workflow-components
51
+ 'workflow_mount',
52
+ // @stackwright-pro/display-components — navigation
53
+ 'breadcrumb',
54
+ 'page_header_bar',
55
+ ];
56
+
57
+ // OSS content types that Pro otters augment with extra fields (e.g. `theme:`,
58
+ // `auth:`). The strict OSS Zod schemas reject unknown properties, so we
59
+ // register passthrough variants here. When build-scripts@0.7.0+ evaluates
60
+ // the union [contentItemSchema, ...extraSchemas], the strict OSS schema
61
+ // fails on the extra field and falls through to our passthrough version.
62
+ const OSS_TYPES_WITH_PRO_EXTENSIONS = [
63
+ 'text_block',
64
+ 'alert',
65
+ 'grid',
66
+ 'main',
67
+ 'collection_list',
68
+ ];
69
+
70
+ const proContentPlugin = {
71
+ name: 'pro-content',
72
+
73
+ // --- Fields read by build-scripts@0.7.0+ (types@1.4.0+) ---
74
+ // Passthrough schemas — let each component handle its own prop validation
75
+ // at runtime. Registered here so the prebuild content-item validator
76
+ // accepts pro types without errors.
77
+ contentItemSchemas: [
78
+ // Pro-only types — fully passthrough (no OSS schema exists)
79
+ ...PRO_CONTENT_TYPE_KEYS.map((type) =>
80
+ z.object({ type: z.literal(type) }).passthrough()
81
+ ),
82
+ // OSS types with Pro extensions (theme:, auth:, etc.) — passthrough
83
+ // variants so the extra fields don't fail strict OSS validation.
84
+ ...OSS_TYPES_WITH_PRO_EXTENSIONS.map((type) =>
85
+ z.object({ type: z.literal(type) }).passthrough()
86
+ ),
87
+ ],
88
+ // String keys so the prebuild skips "unknown content type" warnings.
89
+ knownContentTypeKeys: [...PRO_CONTENT_TYPE_KEYS, ...OSS_TYPES_WITH_PRO_EXTENSIONS],
90
+
91
+ // --- Stub lifecycle hook (required for build-scripts@0.5.x / types@1.2.x) ---
92
+ // build-scripts@0.5.x only calls plugins that have beforeBuild or afterBuild.
93
+ // Without this stub the plugin object is accepted but never invoked, making
94
+ // the whole registration a silent no-op. The stub has no side-effects; its
95
+ // only purpose is to keep the plugin in the active lifecycle.
96
+ //
97
+ // Remove this stub when build-scripts@0.7.0 is the resolved floor (the
98
+ // 0.7.x runner calls plugins purely for their schema/key registration,
99
+ // not via beforeBuild/afterBuild).
100
+ beforeBuild: () => {},
101
+ };
102
+
103
+ module.exports = { proContentPlugin };
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stackwright Pro — Mock backend launcher.
4
+ *
5
+ * Reads public/stackwright-content/_integrations.json and spawns one Prism
6
+ * mock process per integration that has both `spec` and `mockUrl`.
7
+ *
8
+ * Invoked by the `pnpm mock` script, which `pnpm dev:<role>` runs in parallel
9
+ * with `next dev` via `concurrently`.
10
+ *
11
+ * Process management:
12
+ * - SIGINT/SIGTERM cleanly shuts down all child Prism processes
13
+ * - If a single child exits unexpectedly, it is marked disabled and logged —
14
+ * the supervisor keeps running so healthy mocks keep serving (swp-m8et)
15
+ * - Only when ALL children have died does the supervisor shut down
16
+ * - If no integrations have mockable specs, parent idles (concurrently keeps
17
+ * next dev alive while this script waits forever)
18
+ */
19
+ 'use strict';
20
+
21
+ const { spawn } = require('child_process');
22
+ const fs = require('fs');
23
+ const path = require('path');
24
+
25
+ const INTEGRATIONS_PATH = path.join(
26
+ process.cwd(),
27
+ 'public',
28
+ 'stackwright-content',
29
+ '_integrations.json'
30
+ );
31
+
32
+ function readIntegrations() {
33
+ if (!fs.existsSync(INTEGRATIONS_PATH)) {
34
+ console.error(`[mock] ${INTEGRATIONS_PATH} not found. Run prebuild first.`);
35
+ return [];
36
+ }
37
+ try {
38
+ const raw = fs.readFileSync(INTEGRATIONS_PATH, 'utf-8');
39
+ const parsed = JSON.parse(raw);
40
+ return Array.isArray(parsed.integrations) ? parsed.integrations : [];
41
+ } catch (err) {
42
+ console.error('[mock] Failed to parse _integrations.json:', err.message);
43
+ return [];
44
+ }
45
+ }
46
+
47
+ function parsePort(mockUrl) {
48
+ try {
49
+ const url = new URL(mockUrl);
50
+ if (url.port) return url.port;
51
+ return url.protocol === 'https:' ? '443' : '80';
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+
57
+ function startPrism(integration) {
58
+ const { name, spec, mockUrl } = integration;
59
+ if (!spec || !mockUrl) {
60
+ console.log(`[mock] Skipping ${name}: no spec or mockUrl in _integrations.json`);
61
+ return null;
62
+ }
63
+ const port = parsePort(mockUrl);
64
+ if (!port) {
65
+ console.error(`[mock] ${name}: invalid mockUrl ${mockUrl}`);
66
+ return null;
67
+ }
68
+ const specPath = path.resolve(process.cwd(), spec);
69
+ if (!fs.existsSync(specPath)) {
70
+ console.error(`[mock] ${name}: spec file ${specPath} not found`);
71
+ return null;
72
+ }
73
+ console.log(`[mock] Starting ${name} on port ${port} from ${spec}`);
74
+ // STACKWRIGHT_TEST_MOCK_CMD: test-only override so CI can exercise supervisor
75
+ // resilience without a working Prism installation (e.g. space-separated args).
76
+ const spawnArgs = process.env.STACKWRIGHT_TEST_MOCK_CMD
77
+ ? process.env.STACKWRIGHT_TEST_MOCK_CMD.split(' ')
78
+ : ['npx', 'prism', 'mock', specPath, '-p', port, '--cors'];
79
+ const child = spawn(spawnArgs[0], spawnArgs.slice(1), {
80
+ stdio: ['ignore', 'pipe', 'pipe'],
81
+ env: process.env,
82
+ });
83
+ child.stdout.on('data', (data) => {
84
+ process.stdout.write(`[${name}] ${data}`);
85
+ });
86
+ child.stderr.on('data', (data) => {
87
+ process.stderr.write(`[${name}] ${data}`);
88
+ });
89
+ child.on('exit', (code, signal) => {
90
+ if (signal === 'SIGTERM' || signal === 'SIGINT') return;
91
+ console.error(
92
+ `[mock] WARNING: ${name} died (code=${code}, signal=${signal}) — port ${port} is now unavailable`
93
+ );
94
+ deadMocks.add(name);
95
+ deathToll += 1;
96
+ if (deathToll >= expectedChildren) {
97
+ console.error('[mock] All mock children have died — shutting down supervisor.');
98
+ shutdown(1);
99
+ }
100
+ });
101
+ return child;
102
+ }
103
+
104
+ const children = [];
105
+ // Tracks names of integrations whose Prism child has died unexpectedly.
106
+ const deadMocks = new Set();
107
+ // Number of Prism children that have died non-signal deaths.
108
+ let deathToll = 0;
109
+ // Set after main() spawns all children so the exit handler knows when everyone is gone.
110
+ let expectedChildren = 0;
111
+
112
+ function shutdown(exitCode) {
113
+ console.log('[mock] Shutting down...');
114
+ for (const child of children) {
115
+ if (child && !child.killed) {
116
+ child.kill('SIGTERM');
117
+ }
118
+ }
119
+ setTimeout(() => process.exit(exitCode ?? 0), 500);
120
+ }
121
+
122
+ process.on('SIGINT', () => shutdown(0));
123
+ process.on('SIGTERM', () => shutdown(0));
124
+
125
+ function main() {
126
+ const integrations = readIntegrations();
127
+ if (integrations.length === 0) {
128
+ console.log('[mock] No integrations found — idling (concurrently will keep next dev running).');
129
+ // Keep alive so `concurrently` doesn't treat us as exited
130
+ setInterval(() => {}, 1 << 30);
131
+ return;
132
+ }
133
+ for (const integration of integrations) {
134
+ const child = startPrism(integration);
135
+ if (child) children.push(child);
136
+ }
137
+ expectedChildren = children.length;
138
+ console.log(`[mock] Started ${expectedChildren} mock backend(s).`);
139
+ if (children.length === 0) {
140
+ console.log('[mock] No mockable integrations — idling.');
141
+ setInterval(() => {}, 1 << 30);
142
+ }
143
+ }
144
+
145
+ main();