create-sonicjs 3.0.0-beta.18 → 3.0.0-beta.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sonicjs",
3
- "version": "3.0.0-beta.18",
3
+ "version": "3.0.0-beta.19",
4
4
  "description": "Create a new SonicJS application with zero configuration",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -409,7 +409,7 @@ async function copyTemplate(templateName, targetDir, options) {
409
409
 
410
410
  // Add @sonicjs-cms/core dependency
411
411
  packageJson.dependencies = {
412
- '@sonicjs-cms/core': '^3.0.0-beta.18',
412
+ '@sonicjs-cms/core': '^3.0.0-beta.19',
413
413
  ...packageJson.dependencies
414
414
  }
415
415
 
@@ -85,7 +85,7 @@ export const examplePlugin = definePlugin({
85
85
  name: 'Example',
86
86
 
87
87
  // `version` must be valid semver (X.Y.Z). definePlugin warns if it isn't.
88
- version: '1.0.0',
88
+ version: '1.0.1',
89
89
 
90
90
  // `description` shows up in the plugin list and settings page header.
91
91
  description: 'A demo plugin that explains the SonicJS v3 plugin system.',
@@ -239,7 +239,7 @@ export const examplePlugin = definePlugin({
239
239
  displayName: 'Example',
240
240
  description: 'A demo plugin that explains the SonicJS v3 plugin system.',
241
241
  author: 'You',
242
- version: '1.0.0',
242
+ version: '1.0.1',
243
243
  })
244
244
 
245
245
  // ── Sync route metadata into plugin settings ───────────────────────
@@ -16,10 +16,26 @@
16
16
  */
17
17
 
18
18
  import { Hono } from 'hono'
19
- import { DocumentRepository } from '@sonicjs-cms/core'
19
+ import { DocumentRepository, PluginServiceClass as PluginService } from '@sonicjs-cms/core'
20
20
 
21
21
  const MOODS_TYPE_ID = 'example'
22
22
 
23
+ async function getPluginSettings(db: any): Promise<{ greeting: string; defaultName: string }> {
24
+ const defaults = { greeting: 'Hello, Cruel World!', defaultName: 'Stranger' }
25
+ if (!db) return defaults
26
+ try {
27
+ const svc = new PluginService(db)
28
+ const plugin = await svc.getPlugin('example')
29
+ const s = (plugin?.settings ?? {}) as Record<string, unknown>
30
+ return {
31
+ greeting: typeof s.greeting === 'string' ? s.greeting : defaults.greeting,
32
+ defaultName: typeof s.defaultName === 'string' ? s.defaultName : defaults.defaultName,
33
+ }
34
+ } catch {
35
+ return defaults
36
+ }
37
+ }
38
+
23
39
  /**
24
40
  * Pick a random published mood from the DB, or null if none exist yet.
25
41
  * Uses DocumentRepository (the tenant-scoped read chokepoint — R4).
@@ -40,11 +56,10 @@ async function getRandomMood(db: any): Promise<{ name: string; emoji: string; de
40
56
  /**
41
57
  * createExampleApiRoutes — factory that returns the public API router.
42
58
  *
43
- * Factory pattern (vs. a plain exported Hono instance) lets you pass config from
44
- * the plugin into the routes without module-level globals.
45
- * options is passed by reference — onBoot() mutates it so handlers see live values.
59
+ * Settings are read from the DB on each request so changes made via the admin UI
60
+ * take effect immediately without waiting for a Worker isolate restart.
46
61
  */
47
- export function createExampleApiRoutes(options: { greeting?: string; defaultName?: string } = {}): Hono {
62
+ export function createExampleApiRoutes(): Hono {
48
63
  const router = new Hono()
49
64
 
50
65
  // ── GET /example ────────────────────────────────────────────────────────────
@@ -52,11 +67,14 @@ export function createExampleApiRoutes(options: { greeting?: string; defaultName
52
67
  // c.env holds Cloudflare bindings (DB, KV, etc.) — accessed per-request, not at setup.
53
68
  router.get('/', async (c) => {
54
69
  const db = (c.env as any)?.DB
55
- const mood = db ? await getRandomMood(db) : null
56
- const name = options.defaultName ?? 'Stranger'
70
+ const [mood, settings] = await Promise.all([
71
+ db ? getRandomMood(db) : Promise.resolve(null),
72
+ getPluginSettings(db),
73
+ ])
74
+ const name = settings.defaultName
57
75
 
58
76
  return c.json({
59
- message: `Hello, ${name}! The world is still quite cruel.`,
77
+ message: `${settings.greeting} I am ${name}.`,
60
78
  mood: mood ? `${mood.emoji} ${mood.name}`.trim() : null,
61
79
  moodDescription: mood?.description ?? null,
62
80
  timestamp: new Date().toISOString(),
@@ -88,12 +106,14 @@ export function createExampleApiRoutes(options: { greeting?: string; defaultName
88
106
  // Registered AFTER /moods so the literal path wins.
89
107
  router.get('/:name', async (c) => {
90
108
  const db = (c.env as any)?.DB
91
- const mood = db ? await getRandomMood(db) : null
92
- // c.req.param() reads the :name capture from the URL path.
109
+ const [mood, settings] = await Promise.all([
110
+ db ? getRandomMood(db) : Promise.resolve(null),
111
+ getPluginSettings(db),
112
+ ])
93
113
  const name = c.req.param('name')
94
114
 
95
115
  return c.json({
96
- message: `Hello, ${name}! The world is still quite cruel.`,
116
+ message: `${settings.greeting} I am ${name}.`,
97
117
  mood: mood ? `${mood.emoji} ${mood.name}`.trim() : null,
98
118
  moodDescription: mood?.description ?? null,
99
119
  timestamp: new Date().toISOString(),