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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/dist/cli.d.ts +8 -0
  4. package/dist/cli.js +95 -0
  5. package/dist/config.d.ts +24 -0
  6. package/dist/config.js +29 -0
  7. package/dist/emit.d.ts +21 -0
  8. package/dist/emit.js +489 -0
  9. package/dist/files-node.d.ts +8 -0
  10. package/dist/files-node.js +37 -0
  11. package/dist/files.d.ts +25 -0
  12. package/dist/files.js +48 -0
  13. package/dist/generate.d.ts +9 -0
  14. package/dist/generate.js +131 -0
  15. package/dist/generated/files-binary.d.ts +7 -0
  16. package/dist/generated/files-binary.js +7 -0
  17. package/dist/generated/files-text.d.ts +6 -0
  18. package/dist/generated/files-text.js +6 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.js +6 -0
  21. package/dist/manifest.d.ts +89 -0
  22. package/dist/manifest.js +24 -0
  23. package/dist/node.d.ts +6 -0
  24. package/dist/node.js +6 -0
  25. package/dist/validate.d.ts +51 -0
  26. package/dist/validate.js +97 -0
  27. package/dist/write.d.ts +5 -0
  28. package/dist/write.js +15 -0
  29. package/files/base/gitignore +7 -0
  30. package/files/content/magazine/public/seed/README.txt +4 -0
  31. package/files/content/magazine/public/seed/annual-report-2026.pdf +0 -0
  32. package/files/content/magazine/public/seed/avatar-1.jpg +0 -0
  33. package/files/content/magazine/public/seed/avatar-2.jpg +0 -0
  34. package/files/content/magazine/public/seed/avatar-3.jpg +0 -0
  35. package/files/content/magazine/public/seed/cover-1.jpg +0 -0
  36. package/files/content/magazine/public/seed/cover-2.jpg +0 -0
  37. package/files/content/magazine/public/seed/cover-3.jpg +0 -0
  38. package/files/content/magazine/public/seed/cover-4.jpg +0 -0
  39. package/files/content/magazine/public/seed/cover-5.jpg +0 -0
  40. package/files/content/magazine/public/seed/cover-6.jpg +0 -0
  41. package/files/content/magazine/public/seed/editorial-guidelines.pdf +0 -0
  42. package/files/content/magazine/src/trokky/schemas.ts +116 -0
  43. package/files/content/magazine/src/trokky/seed.ts +143 -0
  44. package/files/content/magazine/src/trokky/structure.ts +19 -0
  45. package/files/site/magazine/src/layouts/Base.astro +55 -0
  46. package/files/site/magazine/src/pages/[slug].astro +11 -0
  47. package/files/site/magazine/src/pages/articles/[slug].astro +30 -0
  48. package/files/site/magazine/src/pages/articles/index.astro +21 -0
  49. package/files/site/magazine/src/pages/authors/[slug].astro +19 -0
  50. package/files/site/magazine/src/pages/categories/[slug].astro +19 -0
  51. package/files/site/magazine/src/pages/documents.astro +19 -0
  52. package/files/site/magazine/src/pages/index.astro +35 -0
  53. package/files/site/magazine/src/trokky/site.ts +81 -0
  54. package/files/workers/scripts/copy-studio.mjs +28 -0
  55. package/manifest.json +330 -0
  56. package/package.json +62 -0
@@ -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>;