vyriy 0.5.2 → 0.5.4

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 (71) hide show
  1. package/README.md +54 -36
  2. package/args.js +16 -0
  3. package/bin/vyriy.js +1 -1
  4. package/cli.js +68 -0
  5. package/package.json +52 -7
  6. package/types.d.ts +11 -0
  7. package/cli/args.js +0 -29
  8. package/cli/cli.js +0 -28
  9. package/cli/types.d.ts +0 -13
  10. package/commands/check-env.d.ts +0 -2
  11. package/commands/check-env.js +0 -120
  12. package/commands/create/index.d.ts +0 -2
  13. package/commands/create/index.js +0 -130
  14. package/commands/create/plan/index.d.ts +0 -4
  15. package/commands/create/plan/index.js +0 -3
  16. package/commands/create/plan/plan.d.ts +0 -7
  17. package/commands/create/plan/plan.js +0 -35
  18. package/commands/create/plan/question.d.ts +0 -2
  19. package/commands/create/plan/question.js +0 -25
  20. package/commands/create/plan/types.d.ts +0 -12
  21. package/commands/create/preset/api.d.ts +0 -2
  22. package/commands/create/preset/api.js +0 -63
  23. package/commands/create/preset/base.d.ts +0 -2
  24. package/commands/create/preset/base.js +0 -159
  25. package/commands/create/preset/fullstack.d.ts +0 -2
  26. package/commands/create/preset/fullstack.js +0 -158
  27. package/commands/create/preset/gql.d.ts +0 -2
  28. package/commands/create/preset/gql.js +0 -744
  29. package/commands/create/preset/index.d.ts +0 -52
  30. package/commands/create/preset/index.js +0 -62
  31. package/commands/create/preset/library.d.ts +0 -2
  32. package/commands/create/preset/library.js +0 -247
  33. package/commands/create/preset/mfe.d.ts +0 -2
  34. package/commands/create/preset/mfe.js +0 -326
  35. package/commands/create/preset/rest.d.ts +0 -2
  36. package/commands/create/preset/rest.js +0 -242
  37. package/commands/create/preset/shared.d.ts +0 -116
  38. package/commands/create/preset/shared.js +0 -245
  39. package/commands/create/preset/spa.d.ts +0 -2
  40. package/commands/create/preset/spa.js +0 -132
  41. package/commands/create/preset/ssg.d.ts +0 -2
  42. package/commands/create/preset/ssg.js +0 -171
  43. package/commands/create/preset/ssr.d.ts +0 -2
  44. package/commands/create/preset/ssr.js +0 -179
  45. package/commands/create/preset/types.d.ts +0 -9
  46. package/commands/create/prompt/conflict-strategy.d.ts +0 -5
  47. package/commands/create/prompt/conflict-strategy.js +0 -22
  48. package/commands/create/prompt/index.d.ts +0 -6
  49. package/commands/create/prompt/index.js +0 -5
  50. package/commands/create/prompt/preset.d.ts +0 -4
  51. package/commands/create/prompt/preset.js +0 -11
  52. package/commands/create/prompt/prompt.d.ts +0 -2
  53. package/commands/create/prompt/prompt.js +0 -4
  54. package/commands/create/prompt/resolve-option.d.ts +0 -6
  55. package/commands/create/prompt/resolve-option.js +0 -8
  56. package/commands/create/prompt/scope.d.ts +0 -2
  57. package/commands/create/prompt/scope.js +0 -2
  58. package/commands/create/prompt/types.d.ts +0 -4
  59. package/commands/dist.d.ts +0 -2
  60. package/commands/dist.js +0 -287
  61. package/commands/help.d.ts +0 -3
  62. package/commands/help.js +0 -24
  63. package/commands/index.d.ts +0 -5
  64. package/commands/index.js +0 -5
  65. package/commands/types.d.ts +0 -44
  66. package/commands/version.d.ts +0 -2
  67. package/commands/version.js +0 -6
  68. /package/{cli/args.d.ts → args.d.ts} +0 -0
  69. /package/{cli/cli.d.ts → cli.d.ts} +0 -0
  70. /package/{cli/index.d.ts → index.d.ts} +0 -0
  71. /package/{cli/index.js → index.js} +0 -0
@@ -1,35 +0,0 @@
1
- import { stdin, stdout } from 'node:process';
2
- import { dirname, resolve } from 'node:path';
3
- import { createInterface } from 'node:readline';
4
- import { prompt, preset as promptPreset, scope as promptScope } from '../prompt/index.js';
5
- import { question as createQuestion } from './question.js';
6
- const toDirectoryName = (name, fallback) => {
7
- const directoryName = name.trim().replaceAll(/[\s\\/]+/g, '_');
8
- return directoryName || fallback;
9
- };
10
- const getTargetDefault = (name, dirName, appPath) => name === dirName ? appPath : resolve(dirname(appPath), toDirectoryName(name, dirName));
11
- export const plan = async (dirName, appPath) => {
12
- const readline = createInterface({ input: stdin, output: stdout });
13
- const question = createQuestion(readline, stdout);
14
- try {
15
- stdout.write('\nVyriy Project Master\n\n');
16
- const name = await prompt(question, 'Project name', dirName);
17
- const description = await prompt(question, 'Project description', 'Calm cloud-ready application');
18
- const target = await prompt(question, 'Target directory', getTargetDefault(name, dirName, appPath));
19
- const preset = await promptPreset(question, stdout);
20
- const scope = await promptScope(question, preset, name);
21
- const confirmation = (await prompt(question, 'Use this project plan?', 'y')).toLowerCase();
22
- return confirmation === 'y'
23
- ? {
24
- name,
25
- description,
26
- target,
27
- preset,
28
- scope,
29
- }
30
- : undefined;
31
- }
32
- finally {
33
- readline.close();
34
- }
35
- };
@@ -1,2 +0,0 @@
1
- import { Question } from './types.js';
2
- export declare const question: Question;
@@ -1,25 +0,0 @@
1
- export const question = (readline, output) => {
2
- const queuedLines = [];
3
- const pendingQuestions = [];
4
- readline.on('line', (line) => {
5
- const resolve = pendingQuestions.shift();
6
- if (resolve) {
7
- resolve(line);
8
- return;
9
- }
10
- queuedLines.push(line);
11
- });
12
- readline.on('close', () => {
13
- for (const resolve of pendingQuestions.splice(0)) {
14
- resolve('');
15
- }
16
- });
17
- return (query) => {
18
- output.write(query);
19
- const queuedLine = queuedLines.shift();
20
- if (queuedLine !== undefined) {
21
- return Promise.resolve(queuedLine);
22
- }
23
- return new Promise((resolve) => pendingQuestions.push(resolve));
24
- };
25
- };
@@ -1,12 +0,0 @@
1
- import type { Interface } from 'node:readline';
2
- import type { Writable } from 'node:stream';
3
- export type Question = (readline: Interface, output: Writable) => (query: string) => Promise<string>;
4
- export type Prompt = (question: (query: string) => Promise<string>, label: string, defaultValue: string) => Promise<string>;
5
- export type PlanResult = {
6
- name: string;
7
- description: string;
8
- target: string;
9
- preset: string;
10
- scope?: string;
11
- };
12
- export type Plan = (dirName: string, appPath: string) => Promise<PlanResult | undefined>;
@@ -1,2 +0,0 @@
1
- import { Preset } from './types.js';
2
- export declare const api: Preset;
@@ -1,63 +0,0 @@
1
- import { base } from './base.js';
2
- import { apiWorkspaceBaseFiles, baseToolingDeps, buildPackageJson, serverDeps, webpackDeps, workspaceScripts, } from './shared.js';
3
- export const api = (options) => ({
4
- ...base(options),
5
- ...apiWorkspaceBaseFiles(options.name, options.description),
6
- 'package.json': buildPackageJson(options, [
7
- 'workspaces/*',
8
- ], workspaceScripts('api'), {
9
- ...baseToolingDeps(),
10
- ...webpackDeps(),
11
- ...serverDeps(),
12
- }),
13
- 'workspaces/api/index.ts': `import { server } from '@vyriy/server';
14
- import { api } from '@vyriy/handler';
15
-
16
- server(
17
- api(async (event) =>
18
- Promise.resolve({
19
- statusCode: 200,
20
- body: JSON.stringify({
21
- path: event.path,
22
- }),
23
- }),
24
- ),
25
- );
26
- `,
27
- 'workspaces/api/index.test.ts': `import { describe, expect, it, jest } from '@jest/globals';
28
-
29
- const apiMock = jest.fn((handler) => ({
30
- handler,
31
- }));
32
- const serverMock = jest.fn();
33
-
34
- jest.mock('@vyriy/handler', () => ({
35
- api: apiMock,
36
- }));
37
-
38
- jest.mock('@vyriy/server', () => ({
39
- server: serverMock,
40
- }));
41
-
42
- describe('workspaces/api/index.ts', () => {
43
- it('starts the server with a handler that returns the request path', async () => {
44
- await import('./index.js');
45
-
46
- expect(apiMock).toHaveBeenCalledTimes(1);
47
- expect(serverMock).toHaveBeenCalledTimes(1);
48
- expect(serverMock).toHaveBeenCalledWith(apiMock.mock.results[0]?.value);
49
-
50
- const handler = apiMock.mock.calls[0]?.[0] as (event: {
51
- path: string;
52
- }) => Promise<{ statusCode: number; body: string }>;
53
-
54
- await expect(handler({ path: '/healthcheck' })).resolves.toEqual({
55
- statusCode: 200,
56
- body: JSON.stringify({
57
- path: '/healthcheck',
58
- }),
59
- });
60
- });
61
- });
62
- `,
63
- });
@@ -1,2 +0,0 @@
1
- import { Preset } from './types.js';
2
- export declare const base: Preset;
@@ -1,159 +0,0 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import packageJson from '../../../package.json' with { type: 'json' };
5
- const presetDir = dirname(fileURLToPath(import.meta.url));
6
- const agentsPath = [
7
- resolve(presetDir, '../../../AGENTS.md'),
8
- resolve(presetDir, '../../../../AGENTS.md'),
9
- ].find(existsSync) ?? '';
10
- const agentsContent = agentsPath ? readFileSync(agentsPath, 'utf8') : '';
11
- export const base = ({ name, description }) => ({
12
- 'package.json': JSON.stringify({
13
- name,
14
- version: '0.0.0',
15
- description,
16
- private: true,
17
- type: 'module',
18
- agents: './AGENTS.md',
19
- packageManager: packageJson.packageManager,
20
- engines: {
21
- node: packageJson.engines.node,
22
- },
23
- scripts: {
24
- storybook: 'cross-env STORYBOOK_DISABLE_TELEMETRY=1 storybook dev -p 6006 --disable-telemetry',
25
- check: 'run-s lint build test',
26
- fix: "run-s 'fix:*'",
27
- lint: "run-s 'lint:*'",
28
- build: "run-s 'build:*'",
29
- test: "run-s 'test:*'",
30
- 'fix:prettier': 'prettier . --write',
31
- 'fix:eslint': 'eslint . --fix',
32
- 'lint:ts': 'tsc',
33
- 'lint:prettier': 'prettier . --check',
34
- 'lint:eslint': 'eslint .',
35
- 'build:storybook': 'cross-env STORYBOOK_DISABLE_TELEMETRY=1 storybook build --quiet --disable-telemetry',
36
- 'test:jest': 'jest --passWithNoTests',
37
- postinstall: 'husky',
38
- },
39
- dependencies: {
40
- '@vyriy/typescript-config': `^${packageJson.version}`,
41
- typescript: packageJson.peerDependencies.typescript,
42
- '@vyriy/prettier-config': `^${packageJson.version}`,
43
- prettier: packageJson.peerDependencies.prettier,
44
- '@vyriy/eslint-config': `^${packageJson.version}`,
45
- eslint: packageJson.peerDependencies.eslint,
46
- '@vyriy/jest-config': `^${packageJson.version}`,
47
- jest: packageJson.peerDependencies.jest,
48
- '@vyriy/storybook-config': `^${packageJson.version}`,
49
- storybook: packageJson.peerDependencies.storybook,
50
- '@vyriy/path': `^${packageJson.version}`,
51
- husky: packageJson.peerDependencies.husky,
52
- 'npm-run-all2': packageJson.peerDependencies['npm-run-all2'],
53
- 'cross-env': packageJson.peerDependencies['cross-env'],
54
- },
55
- }, null, 2) + '\n',
56
- 'README.md': `# ${name}\n\n${description}\n`,
57
- 'doc.mdx': `import { Meta, Markdown } from '@storybook/addon-docs/blocks';
58
- import ReadMe from './README.md?raw';
59
-
60
- <Meta title="${name}" />
61
-
62
- <Markdown>{ReadMe}</Markdown>
63
- `,
64
- 'AGENTS.md': agentsContent,
65
- '.editorconfig': `# https://editorconfig.org
66
- root = true
67
-
68
- [*]
69
- charset = utf-8
70
- end_of_line = lf
71
- insert_final_newline = true
72
- trim_trailing_whitespace = true
73
-
74
- indent_style = space
75
- indent_size = 2
76
-
77
- max_line_length = 100
78
-
79
- # Markdown
80
- [*.md]
81
- trim_trailing_whitespace = false
82
- max_line_length = off
83
-
84
- # YAML / YML
85
- [*.{yml,yaml}]
86
- indent_size = 2
87
-
88
- # JSON
89
- [*.json]
90
- indent_size = 2
91
-
92
- # TypeScript / JavaScript
93
- [*.{ts,tsx,js,jsx}]
94
- indent_size = 2
95
-
96
- # Shell / Bash
97
- [*.sh]
98
- indent_size = 2
99
- `,
100
- '.gitignore': `.yarn/*
101
- !.yarn/cache
102
- !.yarn/patches
103
- !.yarn/plugins
104
- !.yarn/releases
105
- !.yarn/sdks
106
- !.yarn/versions
107
-
108
- .DS_Store
109
- .idea
110
- node_modules
111
- coverage
112
- dist
113
- storybook-static
114
- *storybook.log
115
- consumer
116
-
117
- cdk.out
118
- cdk.context.json
119
-
120
- !/**/.gitkeep
121
- `,
122
- '.npmrc': 'engine-strict=true\n',
123
- '.nvmrc': 'lts/krypton\n',
124
- '.yarnrc.yml': 'nodeLinker: node-modules\nnpmMinimalAgeGate: 0\n',
125
- '.husky/commit-msg': '#!/bin/sh\n',
126
- '.husky/post-checkout': '#!/bin/sh\n\nyarn\n',
127
- '.husky/post-merge': '#!/bin/sh\n\nyarn\n',
128
- '.husky/pre-commit': '#!/bin/sh\n\nyarn check\n',
129
- '.husky/pre-push': '#!/bin/sh\n\nyarn check\n',
130
- '.storybook/main.ts': `import config from '@vyriy/storybook-config';
131
- import { path } from '@vyriy/path';
132
-
133
- export default {
134
- ...config,
135
- stories: [
136
- path('**/*.mdx'),
137
- path('**/*.stories.@(js|jsx|mjs|ts|tsx)'),
138
- ],
139
- };
140
- `,
141
- '.storybook/preview.tsx': "export { default } from '@vyriy/storybook-config/preview';\n",
142
- 'yarn.lock': '',
143
- 'tsconfig.json': JSON.stringify({
144
- extends: '@vyriy/typescript-config/index.json',
145
- include: [
146
- '.storybook/**/*.ts',
147
- '.storybook/**/*.tsx',
148
- 'packages/**/*.ts',
149
- 'packages/**/*.tsx',
150
- 'workspaces/**/*.ts',
151
- 'workspaces/**/*.tsx',
152
- '*.ts',
153
- ],
154
- }, null, 2) + '\n',
155
- 'prettier.config.ts': "export { default } from '@vyriy/prettier-config';\n",
156
- '.prettierignore': 'node_modules\ndist\ncoverage\nstorybook-static\nconsumer\n',
157
- 'eslint.config.ts': "export { default } from '@vyriy/eslint-config';\n",
158
- 'jest.config.ts': "export { default } from '@vyriy/jest-config';\n",
159
- });
@@ -1,2 +0,0 @@
1
- import type { Preset } from './types.js';
2
- export declare const fullstack: Preset;
@@ -1,158 +0,0 @@
1
- import packageJson from '../../../package.json' with { type: 'json' };
2
- import { mfe } from './mfe.js';
3
- const mfeOnlyPaths = [
4
- 'packages/api/',
5
- 'packages/event/',
6
- 'packages/query/',
7
- 'workspaces/api/index.ts',
8
- 'workspaces/api/index.test.ts',
9
- 'workspaces/static/public/icon.svg',
10
- 'workspaces/static/public/screenshots/',
11
- ];
12
- const getSharedFiles = (options) => Object.fromEntries(Object.entries(mfe(options)).filter(([file]) => !mfeOnlyPaths.some((path) => file.startsWith(path))));
13
- const projectFiles = {
14
- '.browserslistrc': '[development]\nextends @vyriy/browserslist-config\n\n[ssr]\nextends @vyriy/browserslist-config\n\n[production]\nextends @vyriy/browserslist-config\n\n[modern]\nextends @vyriy/browserslist-config\n',
15
- '.storybook/preview.tsx': "import '../packages/components/styles.scss';\n\nexport { default } from '@vyriy/storybook-config/preview';\n",
16
- 'packages/env/env.test.ts': "import { afterEach, describe, expect, it } from '@jest/globals';\n\nimport { getApi, getCdn, getUi } from './env.js';\n\ndescribe('env getters', () => {\n afterEach(() => {\n delete process.env.API;\n delete process.env.CDN;\n delete process.env.UI;\n });\n\n it('reads required environment values', () => {\n process.env.API = 'http://localhost:3000';\n process.env.CDN = 'http://localhost:3001';\n process.env.UI = 'http://localhost:3002';\n\n expect(getApi()).toBe('http://localhost:3000');\n expect(getCdn()).toBe('http://localhost:3001');\n expect(getUi()).toBe('http://localhost:3002');\n });\n\n it('throws when a required environment value is missing', () => {\n expect(() => getUi()).toThrow('Environment variable UI is not defined!');\n });\n});\n",
17
- 'packages/env/env.ts': "import { getEnv } from '@vyriy/env';\n\n/** Reads the API origin used for server endpoints. */\nexport const getApi = () => getEnv('API');\n\n/** Reads the CDN origin used for static assets. */\nexport const getCdn = () => getEnv('CDN');\n\n/** Reads the UI origin used for browser assets. */\nexport const getUi = () => getEnv('UI');\n",
18
- 'packages/env/index.test.ts': "import { afterEach, describe, expect, it } from '@jest/globals';\n\nimport * as publicApi from './index.js';\n\nconst ENV_NAMES = [\n 'API',\n 'CDN',\n 'UI',\n] as const;\n\nconst clearEnv = () => {\n for (const name of ENV_NAMES) {\n delete process.env[name];\n }\n};\n\ndescribe('env public API', () => {\n afterEach(() => {\n clearEnv();\n });\n\n it('exports env getters', () => {\n expect(publicApi.getApi).toBeDefined();\n expect(publicApi.getCdn).toBeDefined();\n expect(publicApi.getUi).toBeDefined();\n });\n\n it('reads environment variables by public getter name', () => {\n process.env.API = 'http://localhost:3000';\n process.env.CDN = 'http://localhost:3001';\n process.env.UI = 'http://localhost:3002';\n\n expect(publicApi.getApi()).toBe('http://localhost:3000');\n expect(publicApi.getCdn()).toBe('http://localhost:3001');\n expect(publicApi.getUi()).toBe('http://localhost:3002');\n });\n\n it('throws when a required environment variable is missing', () => {\n clearEnv();\n\n expect(() => publicApi.getApi()).toThrow('Environment variable API is not defined!');\n });\n});\n",
19
- 'packages/env/README.md': '# @p/env\n\nRequired environment readers shared by API and UI workspaces.\n\n## Exports\n\n- `getApi()` reads `API`.\n- `getCdn()` reads `CDN`.\n- `getUi()` reads `UI`.\n\nEach getter throws when its environment variable is missing.\n',
20
- 'workspaces/api/index.test.tsx': "import { describe, expect, it, jest } from '@jest/globals';\nimport type { APIGatewayProxyEvent } from '@vyriy/router';\n\nconst apiMock = jest.fn((handler) => ({ handler }));\nconst serverMock = jest.fn();\n\njest.mock('@vyriy/handler', () => ({\n api: apiMock,\n}));\n\njest.mock('@vyriy/server', () => ({\n server: serverMock,\n}));\n\njest.mock('@p/env', () => ({\n getUi: () => 'http://localhost:3002',\n}));\n\ndescribe('workspaces/api/index.tsx', () => {\n type ApiHandler = (event: APIGatewayProxyEvent) => Promise<{\n body: string;\n headers?: Record<string, string>;\n statusCode: number;\n }>;\n\n const getEvent = (path: string): APIGatewayProxyEvent =>\n ({\n body: null,\n headers: {},\n httpMethod: 'GET',\n path,\n pathParameters: null,\n queryStringParameters: null,\n }) as APIGatewayProxyEvent;\n\n const loadHandler = async (): Promise<ApiHandler> => {\n await jest.isolateModulesAsync(async () => {\n await import('./index.js');\n });\n\n expect(apiMock).toHaveBeenCalledTimes(1);\n expect(serverMock).toHaveBeenCalledTimes(1);\n expect(serverMock).toHaveBeenCalledWith(apiMock.mock.results[0]?.value);\n\n return apiMock.mock.calls[0]?.[0] as ApiHandler;\n };\n\n it('starts the server with the API handler', async () => {\n await loadHandler();\n\n expect(apiMock).toHaveBeenCalledTimes(1);\n });\n\n it('renders the demo page for the root route', async () => {\n const handler = await loadHandler();\n const response = await handler(getEvent('/'));\n\n expect(response).toEqual({\n body: expect.any(String),\n headers: {\n 'access-control-allow-origin': '*',\n 'cache-control': 'public, max-age=300, s-maxage=3600, stale-while-revalidate=86400',\n 'content-type': 'text/html; charset=utf-8',\n 'x-content-type-options': 'nosniff',\n },\n isBase64Encoded: undefined,\n multiValueHeaders: undefined,\n statusCode: 200,\n });\n expect(response.body).toContain('<title>Demo</title>');\n expect(response.body).toContain('href=\"http://localhost:3002/main.css\"');\n expect(response.body).toContain('<div id=\"root\" rendered>');\n expect(response.body).toContain('Developer');\n expect(response.body).toContain('Senior IT Professional');\n expect(response.body).toContain('http://localhost:3001/avatar.svg');\n expect(response.body).toContain('src=\"http://localhost:3002/index.js\"');\n });\n\n it('returns not found for unknown routes', async () => {\n const handler = await loadHandler();\n\n await expect(handler(getEvent('/missing'))).resolves.toEqual({\n body: JSON.stringify({\n message: 'Not Found',\n }),\n statusCode: 404,\n });\n });\n});\n",
21
- 'workspaces/api/index.tsx': "import { server } from '@vyriy/server';\nimport { api } from '@vyriy/handler';\nimport { createRouter } from '@vyriy/router';\nimport { minify, html } from '@vyriy/html';\nimport { html as react } from '@vyriy/render';\n\nimport { ProfileCard } from '@p/components/profile-card';\nimport { getUi } from '@p/env';\n\nserver(\n api(async (event) =>\n createRouter()\n .get('/', () => ({\n body: minify(\n html({\n htmlAttributes: 'lang=\"en\"',\n title: '<title>Demo</title>',\n meta: '<meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n link: `<link rel=\"stylesheet\" type=\"text/css\" href=\"${getUi()}/main.css\" />`,\n body: `<div id=\"root\" rendered>${react(\n <ProfileCard\n name=\"Developer\"\n title=\"Senior IT Professional\"\n avatarUrl=\"http://localhost:3001/avatar.svg\"\n />,\n )}</div>`,\n script: `<script defer=\"defer\" src=\"${getUi()}/index.js\"></script>`,\n }),\n ),\n headers: {\n 'content-type': 'text/html; charset=utf-8',\n 'cache-control': 'public, max-age=300, s-maxage=3600, stale-while-revalidate=86400',\n 'access-control-allow-origin': '*',\n 'x-content-type-options': 'nosniff',\n },\n }))\n .route(event),\n ),\n);\n",
22
- 'workspaces/api/webpack.config.ts': "import { EnvironmentPlugin } from 'webpack';\nimport { path } from '@vyriy/path';\nimport { ssr, external } from '@vyriy/webpack-config';\n\nexport default ssr(\n '@w/api',\n {\n path: path('dist', 'api'),\n filename: 'index.js',\n library: { type: 'commonjs2' },\n },\n (config) => ({\n ...config,\n externals: [external({ allowlist: [/^@p/, /^@w/, /^@vyriy/] })],\n plugins: [\n ...(config.plugins ?? []),\n new EnvironmentPlugin([\n 'API',\n 'CDN',\n 'UI',\n ]),\n ],\n }),\n);\n",
23
- 'workspaces/env.sh': '#!/usr/bin/env sh\n\n: "${API_PORT:=3000}"\n: "${CDN_PORT:=3001}"\n: "${UI_PORT:=3002}"\n: "${API:=http://localhost:$API_PORT}"\n: "${CDN:=http://localhost:$CDN_PORT}"\n: "${UI:=http://localhost:$UI_PORT}"\n\nexport API_PORT\nexport CDN_PORT\nexport UI_PORT\nexport API\nexport CDN\nexport UI\n',
24
- 'workspaces/static/README.md': '# @w/static\n\nStatic asset workspace for the profile-card UI.\n\n## Assets\n\n- `avatar.svg` is the default demo avatar.\n\nThe workspace is served as the CDN origin during local development.\n',
25
- 'workspaces/ui/index.test.tsx': "import { describe, expect, it, jest } from '@jest/globals';\nimport { isValidElement } from 'react';\nimport type { ReactElement } from 'react';\n\nconst elementMock = jest.fn();\n\njest.mock('@vyriy/render/element', () => ({\n element: elementMock,\n}));\n\ntype ProfileCardProps = {\n avatarUrl: string;\n name: string;\n title: string;\n};\n\ndescribe('workspaces/ui/index.tsx', () => {\n const loadEntry = async () => {\n const root = document.createElement('div');\n root.id = 'root';\n document.body.replaceChildren();\n document.body.append(root);\n\n await jest.isolateModulesAsync(async () => {\n await import('./index.js');\n });\n\n const [{ component }] = elementMock.mock.calls[0] as [{ component: ReactElement<ProfileCardProps> }];\n\n return {\n root,\n component,\n };\n };\n\n it('mounts the UI into the root element', async () => {\n const { root, component } = await loadEntry();\n\n expect(elementMock).toHaveBeenCalledTimes(1);\n expect(elementMock).toHaveBeenCalledWith({\n root,\n component,\n });\n });\n\n it('renders the profile card demo component', async () => {\n const { component } = await loadEntry();\n\n expect(isValidElement(component)).toBe(true);\n expect(typeof component.type).toBe('function');\n expect((component.type as { name?: string }).name).toBe('ProfileCard');\n expect(component.props).toEqual({\n avatarUrl: 'http://localhost:3001/avatar.svg',\n name: 'Developer',\n title: 'Senior IT Professional',\n });\n });\n});\n",
26
- 'workspaces/ui/index.tsx': "import { element } from '@vyriy/render/element';\n\nimport { ProfileCard } from '@p/components/profile-card';\nimport '@p/components/styles.scss';\n\nelement({\n root: document.getElementById('root'),\n component: (\n <ProfileCard name=\"Developer\" title=\"Senior IT Professional\" avatarUrl=\"http://localhost:3001/avatar.svg\" />\n ),\n});\n",
27
- 'workspaces/ui/webpack.config.ts': "import { EnvironmentPlugin } from 'webpack';\n\nimport { csr, html } from '@vyriy/webpack-config';\nimport { path } from '@vyriy/path';\n\nexport default csr(\n '@w/ui',\n {\n path: path('dist', 'cdn'),\n filename: 'index.js',\n },\n (config) => ({\n ...config,\n plugins: [\n ...(config.plugins ?? []),\n new EnvironmentPlugin(['API', 'CDN', 'UI']),\n html({\n htmlAttributes: 'lang=\"en\"',\n title: '<title>Demo</title>',\n meta: '<meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n body: '<div id=\"root\"></div>',\n }),\n ],\n }),\n);\n",
28
- };
29
- export const fullstack = (options) => ({
30
- ...getSharedFiles(options),
31
- ...projectFiles,
32
- 'package.json': JSON.stringify({
33
- name: options.name,
34
- version: '0.0.0',
35
- description: options.description,
36
- private: true,
37
- type: 'module',
38
- agents: './AGENTS.md',
39
- packageManager: packageJson.packageManager,
40
- engines: {
41
- node: packageJson.engines.node,
42
- },
43
- workspaces: [
44
- 'packages/*',
45
- 'workspaces/*',
46
- ],
47
- scripts: {
48
- storybook: 'cross-env STORYBOOK_DISABLE_TELEMETRY=1 storybook dev -p 6006 --disable-telemetry',
49
- check: 'run-s lint build test',
50
- fix: "run-s 'fix:*'",
51
- start: "run-p 'start:*'",
52
- lint: "run-s 'lint:*'",
53
- build: "run-s 'build:*'",
54
- test: "run-s 'test:*'",
55
- 'fix:prettier': 'prettier . --write',
56
- 'fix:eslint': 'eslint . --fix',
57
- 'fix:stylelint': "stylelint '**/*.{css,scss}' --fix",
58
- 'start:api': 'sh workspaces/api/bin/start.sh',
59
- 'start:static': 'sh workspaces/static/bin/start.sh',
60
- 'start:ui': 'sh workspaces/ui/bin/start.sh',
61
- 'lint:ts': 'tsc',
62
- 'lint:prettier': 'prettier . --check',
63
- 'lint:eslint': 'eslint .',
64
- 'lint:stylelint': "stylelint '**/*.{css,scss}'",
65
- 'build:api': 'sh workspaces/api/bin/build.sh',
66
- 'build:ui': 'sh workspaces/ui/bin/build.sh',
67
- 'build:static': 'sh workspaces/static/bin/build.sh',
68
- 'build:storybook': 'cross-env STORYBOOK_DISABLE_TELEMETRY=1 storybook build --quiet --disable-telemetry',
69
- 'test:jest': 'jest',
70
- prebuild: 'rimraf dist',
71
- postinstall: 'husky',
72
- },
73
- dependencies: {
74
- '@testing-library/dom': packageJson.peerDependencies['@testing-library/dom'],
75
- '@testing-library/react': packageJson.peerDependencies['@testing-library/react'],
76
- '@types/jest': packageJson.peerDependencies['@types/jest'],
77
- '@vyriy/browserslist-config': `^${packageJson.version}`,
78
- '@vyriy/cn': `^${packageJson.version}`,
79
- '@vyriy/env': `^${packageJson.version}`,
80
- '@vyriy/eslint-config': `^${packageJson.version}`,
81
- '@vyriy/handler': `^${packageJson.version}`,
82
- '@vyriy/html': `^${packageJson.version}`,
83
- '@vyriy/jest-config': `^${packageJson.version}`,
84
- '@vyriy/path': `^${packageJson.version}`,
85
- '@vyriy/prettier-config': `^${packageJson.version}`,
86
- '@vyriy/render': `^${packageJson.version}`,
87
- '@vyriy/router': `^${packageJson.version}`,
88
- '@vyriy/server': `^${packageJson.version}`,
89
- '@vyriy/storybook-config': `^${packageJson.version}`,
90
- '@vyriy/stylelint-config': `^${packageJson.version}`,
91
- '@vyriy/typescript-config': `^${packageJson.version}`,
92
- '@vyriy/webpack-config': `^${packageJson.version}`,
93
- 'cross-env': packageJson.peerDependencies['cross-env'],
94
- eslint: packageJson.peerDependencies.eslint,
95
- husky: packageJson.peerDependencies.husky,
96
- jest: packageJson.peerDependencies.jest,
97
- 'npm-run-all2': packageJson.peerDependencies['npm-run-all2'],
98
- prettier: packageJson.peerDependencies.prettier,
99
- rimraf: packageJson.peerDependencies.rimraf,
100
- serve: packageJson.peerDependencies.serve,
101
- storybook: packageJson.peerDependencies.storybook,
102
- stylelint: packageJson.peerDependencies.stylelint,
103
- tsx: packageJson.peerDependencies.tsx,
104
- typescript: packageJson.peerDependencies.typescript,
105
- webpack: packageJson.peerDependencies.webpack,
106
- 'webpack-cli': packageJson.peerDependencies['webpack-cli'],
107
- },
108
- }, null, 2) + '\n',
109
- 'README.md': `# ${options.name}
110
-
111
- ${options.description}
112
-
113
- ## Setup
114
-
115
- \`\`\`bash
116
- yarn install
117
- \`\`\`
118
-
119
- ## Start
120
-
121
- Start the API, static asset server, and UI dev server together:
122
-
123
- \`\`\`bash
124
- yarn start
125
- \`\`\`
126
-
127
- Start individual workspaces:
128
-
129
- \`\`\`bash
130
- yarn start:api
131
- yarn start:static
132
- yarn start:ui
133
- \`\`\`
134
-
135
- ## Local URLs
136
-
137
- Default ports are defined in \`workspaces/env.sh\`:
138
-
139
- - API: \`http://localhost:3000\`
140
- - Static/CDN assets: \`http://localhost:3001\`
141
- - UI dev server: \`http://localhost:3002\`
142
-
143
- ## Validation
144
-
145
- \`\`\`bash
146
- yarn lint
147
- yarn test
148
- yarn build
149
- \`\`\`
150
- `,
151
- 'doc.mdx': `import { Meta, Markdown } from '@storybook/addon-docs/blocks';
152
- import ReadMe from './README.md?raw';
153
-
154
- <Meta title="${options.name}" />
155
-
156
- <Markdown>{ReadMe}</Markdown>
157
- `,
158
- });
@@ -1,2 +0,0 @@
1
- import { Preset } from './types.js';
2
- export declare const gql: Preset;