create-trokky 0.1.1
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/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +95 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +29 -0
- package/dist/emit.d.ts +21 -0
- package/dist/emit.js +489 -0
- package/dist/files-node.d.ts +8 -0
- package/dist/files-node.js +37 -0
- package/dist/files.d.ts +25 -0
- package/dist/files.js +48 -0
- package/dist/generate.d.ts +9 -0
- package/dist/generate.js +131 -0
- package/dist/generated/files-binary.d.ts +7 -0
- package/dist/generated/files-binary.js +7 -0
- package/dist/generated/files-text.d.ts +6 -0
- package/dist/generated/files-text.js +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/manifest.d.ts +89 -0
- package/dist/manifest.js +24 -0
- package/dist/node.d.ts +6 -0
- package/dist/node.js +6 -0
- package/dist/validate.d.ts +51 -0
- package/dist/validate.js +97 -0
- package/dist/write.d.ts +5 -0
- package/dist/write.js +15 -0
- package/files/base/gitignore +7 -0
- package/files/content/magazine/public/seed/README.txt +4 -0
- package/files/content/magazine/public/seed/annual-report-2026.pdf +0 -0
- package/files/content/magazine/public/seed/avatar-1.jpg +0 -0
- package/files/content/magazine/public/seed/avatar-2.jpg +0 -0
- package/files/content/magazine/public/seed/avatar-3.jpg +0 -0
- package/files/content/magazine/public/seed/cover-1.jpg +0 -0
- package/files/content/magazine/public/seed/cover-2.jpg +0 -0
- package/files/content/magazine/public/seed/cover-3.jpg +0 -0
- package/files/content/magazine/public/seed/cover-4.jpg +0 -0
- package/files/content/magazine/public/seed/cover-5.jpg +0 -0
- package/files/content/magazine/public/seed/cover-6.jpg +0 -0
- package/files/content/magazine/public/seed/editorial-guidelines.pdf +0 -0
- package/files/content/magazine/src/trokky/schemas.ts +116 -0
- package/files/content/magazine/src/trokky/seed.ts +143 -0
- package/files/content/magazine/src/trokky/structure.ts +19 -0
- package/files/site/magazine/src/layouts/Base.astro +55 -0
- package/files/site/magazine/src/pages/[slug].astro +11 -0
- package/files/site/magazine/src/pages/articles/[slug].astro +30 -0
- package/files/site/magazine/src/pages/articles/index.astro +21 -0
- package/files/site/magazine/src/pages/authors/[slug].astro +19 -0
- package/files/site/magazine/src/pages/categories/[slug].astro +19 -0
- package/files/site/magazine/src/pages/documents.astro +19 -0
- package/files/site/magazine/src/pages/index.astro +35 -0
- package/files/site/magazine/src/trokky/site.ts +81 -0
- package/files/workers/scripts/copy-studio.mjs +28 -0
- package/manifest.json +330 -0
- package/package.json +62 -0
package/dist/generate.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config → file tree. Pure: nothing here touches the disk, so it is testable, it runs in a
|
|
3
|
+
* browser as readily as in a terminal, and the same function serves the CLI, a zip download and
|
|
4
|
+
* an API install.
|
|
5
|
+
*/
|
|
6
|
+
import { hasFrontend, hasStudio } from './config.js';
|
|
7
|
+
import { validate, describe } from './validate.js';
|
|
8
|
+
import * as emit from './emit.js';
|
|
9
|
+
/**
|
|
10
|
+
* Which copied file sets a composition pulls in, in order.
|
|
11
|
+
*
|
|
12
|
+
* A content model owns two sets: `content/<id>` is its schemas, structure and seed, and
|
|
13
|
+
* `site/<id>` is the pages that render them. They are separate because a headless install wants
|
|
14
|
+
* the first without the second — and they are named after the model rather than shared, because
|
|
15
|
+
* pages are written against particular collections. Adding a content model means adding those
|
|
16
|
+
* directories; nothing here needs to learn its name.
|
|
17
|
+
*
|
|
18
|
+
* There is deliberately no `node` set: every file a Node project needs has contents that depend
|
|
19
|
+
* on the choices, so all of it is emitted. An empty directory would not survive git or npm
|
|
20
|
+
* anyway — it did not, and the failure was a scandir error on a user's machine.
|
|
21
|
+
*/
|
|
22
|
+
function sources(config) {
|
|
23
|
+
const sets = ['base'];
|
|
24
|
+
if (config.target === 'workers')
|
|
25
|
+
sets.push('workers');
|
|
26
|
+
if (config.content !== 'blank')
|
|
27
|
+
sets.push(`content/${config.content}`);
|
|
28
|
+
if (hasFrontend(config))
|
|
29
|
+
sets.push(`site/${config.content}`);
|
|
30
|
+
return sets;
|
|
31
|
+
}
|
|
32
|
+
function copyInto(tree, source, set) {
|
|
33
|
+
for (const [path, contents] of source.read(set)) {
|
|
34
|
+
// npm refuses to ship a .gitignore inside a package — it is on its always-ignored list — so
|
|
35
|
+
// the template keeps it dotless and the name is restored here. Miss this and the set it
|
|
36
|
+
// lives in arrives empty, which surfaces as an error on a user's machine, not at publish.
|
|
37
|
+
tree.set(path.replace(/(^|\/)gitignore$/, '$1.gitignore'), contents);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function generate(config, source) {
|
|
41
|
+
const result = validate(config);
|
|
42
|
+
if (!result.valid) {
|
|
43
|
+
throw new Error(`This combination cannot be built:\n${describe(result.problems)}`);
|
|
44
|
+
}
|
|
45
|
+
const tree = new Map();
|
|
46
|
+
for (const set of sources(config))
|
|
47
|
+
copyInto(tree, source, set);
|
|
48
|
+
// Files whose contents depend on the choices.
|
|
49
|
+
tree.set('package.json', emit.packageJson(config));
|
|
50
|
+
tree.set('tsconfig.json', emit.tsconfig(config));
|
|
51
|
+
tree.set('README.md', readme(config));
|
|
52
|
+
if (hasFrontend(config)) {
|
|
53
|
+
tree.set('astro.config.mjs', emit.astroConfig(config));
|
|
54
|
+
tree.set('src/trokky/page.ts', emit.pageHelper(config));
|
|
55
|
+
}
|
|
56
|
+
if (config.target === 'workers') {
|
|
57
|
+
tree.set('wrangler.jsonc', emit.wranglerConfig(config));
|
|
58
|
+
tree.set('src/worker.ts', emit.workersEntry(config));
|
|
59
|
+
tree.set('src/trokky/core.ts', emit.workersCore(config));
|
|
60
|
+
tree.set('.dev.vars.example', emit.envExample(config));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
tree.set('src/server.ts', emit.nodeEntry(config));
|
|
64
|
+
tree.set('trokky.config.ts', emit.trokkyConfig(config));
|
|
65
|
+
tree.set('.env.example', emit.envExample(config));
|
|
66
|
+
}
|
|
67
|
+
// A Studio-less project has nothing to copy Studio into.
|
|
68
|
+
if (!hasStudio(config)) {
|
|
69
|
+
tree.delete('scripts/copy-studio.mjs');
|
|
70
|
+
}
|
|
71
|
+
// Seed assets are only reachable when something serves static files.
|
|
72
|
+
if (config.content === 'blank' || (config.target === 'workers' && !hasStudio(config) && !hasFrontend(config))) {
|
|
73
|
+
for (const path of [...tree.keys()])
|
|
74
|
+
if (path.startsWith('public/seed/'))
|
|
75
|
+
tree.delete(path);
|
|
76
|
+
}
|
|
77
|
+
return tree;
|
|
78
|
+
}
|
|
79
|
+
function readme(config) {
|
|
80
|
+
const edge = config.target === 'workers';
|
|
81
|
+
const parts = hasFrontend(config) ? 'a site, the Studio and the API' : hasStudio(config) ? 'the Studio and the API' : 'the API';
|
|
82
|
+
return `# ${config.name}
|
|
83
|
+
|
|
84
|
+
A [Trokky](https://trokky.dev) project: ${parts}, on ${edge ? 'Cloudflare Workers' : 'Node'}.
|
|
85
|
+
|
|
86
|
+
Generated with \`npm create trokky@latest\`.
|
|
87
|
+
|
|
88
|
+
## What is in it
|
|
89
|
+
|
|
90
|
+
| | |
|
|
91
|
+
|---|---|
|
|
92
|
+
| Content | ${config.data} |
|
|
93
|
+
| Uploads | ${config.media} |
|
|
94
|
+
| Thumbnails | ${config.images === 'none' ? 'not generated — originals only' : config.images} |
|
|
95
|
+
| Parts | ${parts} |
|
|
96
|
+
| Starting content | ${config.content} |
|
|
97
|
+
|
|
98
|
+
## Run it
|
|
99
|
+
|
|
100
|
+
\`\`\`
|
|
101
|
+
${edge ? `cp .dev.vars.example .dev.vars # fill both secrets
|
|
102
|
+
npm install
|
|
103
|
+
npm run build && npm run preview` : `cp .env.example .env # fill both secrets
|
|
104
|
+
npm install
|
|
105
|
+
npm run dev`}
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
${edge ? `## Deploy
|
|
109
|
+
|
|
110
|
+
\`\`\`
|
|
111
|
+
npm run build && npm run deploy
|
|
112
|
+
\`\`\`
|
|
113
|
+
|
|
114
|
+
Wrangler provisions the D1 database and R2 bucket named in \`wrangler.jsonc\` on first deploy.
|
|
115
|
+
\`database_id\` is intentionally empty: it is bound by name.
|
|
116
|
+
|
|
117
|
+
` : ''}## The first minute
|
|
118
|
+
|
|
119
|
+
Open ${hasStudio(config) ? '`/studio`' : 'the API'}. Nobody owns this instance yet, so the first
|
|
120
|
+
screen asks you to **claim** it: pick a username and password, and paste \`TROKKY_CLAIM_SECRET\`.
|
|
121
|
+
${config.content === 'blank' ? '' : 'Sample content appears a moment later — edit it or delete it.'}
|
|
122
|
+
|
|
123
|
+
Without a claim secret the claim is open to whoever reaches the URL first. That is fine for the
|
|
124
|
+
minute between deploying and opening the link; it is not fine for an instance left sitting.
|
|
125
|
+
|
|
126
|
+
## Make it yours
|
|
127
|
+
|
|
128
|
+
${config.content === 'blank' ? '- `src/trokky/` — add your schemas; the Studio follows them.' : '- `src/trokky/schemas.ts` — the content model. The Studio follows it.\n- `src/trokky/structure.ts` — the Studio sidebar.'}
|
|
129
|
+
${hasFrontend(config) ? '- `src/pages/` and `src/layouts/` — the site.\n' : ''}${edge ? '- `wrangler.jsonc` — the Worker name and its resources.' : '- `trokky.config.ts` — storage, media and security.'}
|
|
130
|
+
`;
|
|
131
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED by scripts/inline-files.mjs — do not edit.
|
|
3
|
+
*
|
|
4
|
+
* The magazine's images and PDFs, base64. Imported lazily: only a composition that chooses
|
|
5
|
+
* that content model needs them, and they are most of the payload.
|
|
6
|
+
*/
|
|
7
|
+
export declare const binary: Record<string, string>;
|