@crombolo/server 0.13.1 → 0.13.2

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": "@crombolo/server",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "description": "The crombolo HTTP server: routing, configuration, media stores and background jobs.",
5
5
  "license": "MIT",
6
6
  "author": "Crombolo",
@@ -28,17 +28,17 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@crombolo/api-delivery": "0.13.1",
32
- "@crombolo/api-management": "0.13.1",
33
- "@crombolo/assistant": "0.13.1",
34
- "@crombolo/auth": "0.13.1",
35
- "@crombolo/backoffice-host": "0.13.1",
36
- "@crombolo/contracts": "0.13.1",
37
- "@crombolo/core": "0.13.1",
38
- "@crombolo/data": "0.13.1",
39
- "@crombolo/render": "0.13.1",
40
- "@crombolo/schema": "0.13.1",
41
- "@crombolo/transfer": "0.13.1",
31
+ "@crombolo/api-delivery": "0.13.2",
32
+ "@crombolo/api-management": "0.13.2",
33
+ "@crombolo/assistant": "0.13.2",
34
+ "@crombolo/auth": "0.13.2",
35
+ "@crombolo/backoffice-host": "0.13.2",
36
+ "@crombolo/contracts": "0.13.2",
37
+ "@crombolo/core": "0.13.2",
38
+ "@crombolo/data": "0.13.2",
39
+ "@crombolo/render": "0.13.2",
40
+ "@crombolo/schema": "0.13.2",
41
+ "@crombolo/transfer": "0.13.2",
42
42
  "@logtape/logtape": "^2.3.8"
43
43
  }
44
44
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The Workflow section's and the page tab's reads and actions (story 028),
2
+ * The Workflows section's and the page tab's reads and actions (story 028),
3
3
  * under `<backoffice>/crombolo/api/approvals/`, and saving a workflow drawn in
4
4
  * the designer back to `schema/workflows/`. docs/workflows.md.
5
5
  *
package/src/approvals.ts CHANGED
@@ -75,6 +75,7 @@ interface PageFacts {
75
75
  name: string
76
76
  chain: string[]
77
77
  contentTypeAlias: string | undefined
78
+ variesByCulture: boolean
78
79
  }
79
80
 
80
81
  export interface PageApproval {
@@ -90,6 +91,8 @@ export interface RequestView {
90
91
  key: string
91
92
  nodeKey: string
92
93
  nodeName: string
94
+ /** The editor's variant segment for the page: `invariant`, or the culture to open. */
95
+ variant: string
93
96
  action: ApprovalAction
94
97
  cultures: string[] | null
95
98
  state: ApprovalRequest['state']
@@ -181,8 +184,8 @@ export function createApprovals(options: ApprovalsOptions): Approvals {
181
184
  .filter((id) => id > 0)
182
185
  const rows = await nodes.byIds(ids)
183
186
  const keyOf = new Map(rows.map((r) => [r.id, r.key]))
184
- const type = await db.query<{ alias: string }>(
185
- `SELECT ct.alias FROM content c JOIN content_type ct ON ct.node_id = c.content_type_id WHERE c.node_id = ?`,
187
+ const type = await db.query<{ alias: string; variations: number }>(
188
+ `SELECT ct.alias, ct.variations FROM content c JOIN content_type ct ON ct.node_id = c.content_type_id WHERE c.node_id = ?`,
186
189
  [node.id],
187
190
  )
188
191
  return {
@@ -190,6 +193,8 @@ export function createApprovals(options: ApprovalsOptions): Approvals {
190
193
  name: node.text ?? node.key,
191
194
  chain: ids.flatMap((id) => keyOf.get(id) ?? []),
192
195
  contentTypeAlias: type[0]?.alias,
196
+ // Umbraco's flags: 1 is culture, 2 is segment.
197
+ variesByCulture: (Number(type[0]?.variations ?? 0) & 1) === 1,
193
198
  }
194
199
  }
195
200
 
@@ -470,10 +475,19 @@ export function createApprovals(options: ApprovalsOptions): Approvals {
470
475
  h.userKey === normaliseUuid(principal.id),
471
476
  )
472
477
  const ownChange = normaliseUuid(principal.id) === request.requestedBy
478
+ let variant = 'invariant'
479
+ if (facts?.variesByCulture) {
480
+ const fallback = await db.query<{ iso_code: string }>(
481
+ 'SELECT iso_code FROM language WHERE is_default = ?',
482
+ [db.dialect.boolValue(true)],
483
+ )
484
+ variant = request.cultures?.[0] ?? fallback[0]?.iso_code ?? 'invariant'
485
+ }
473
486
  return {
474
487
  key: request.key,
475
488
  nodeKey: request.nodeKey,
476
489
  nodeName: facts?.name ?? request.nodeKey,
490
+ variant,
477
491
  action: request.action,
478
492
  cultures: request.cultures,
479
493
  state: request.state,
@@ -563,6 +577,7 @@ export function createApprovals(options: ApprovalsOptions): Approvals {
563
577
  name: 'This page',
564
578
  chain: parent?.chain ?? [],
565
579
  contentTypeAlias: type[0]?.alias,
580
+ variesByCulture: false,
566
581
  }
567
582
  return refusalFor(principal, facts, await covering(facts), 'publish')
568
583
  },
package/src/config.ts CHANGED
@@ -618,4 +618,4 @@ export function describeDatabase(
618
618
  }
619
619
  }
620
620
 
621
- export const VERSION = '0.13.1'
621
+ export const VERSION = '0.13.2'
@@ -17,6 +17,7 @@
17
17
  * browser cannot reach npm, and the backoffice keeps making same-origin
18
18
  * requests only.
19
19
  */
20
+ import { readFileSync } from 'node:fs'
20
21
  import { join } from 'node:path'
21
22
  import {
22
23
  type BundlePackage,
@@ -57,6 +58,10 @@ export interface InstalledListing {
57
58
  wired: boolean
58
59
  /** The version whose content was applied here, or null when none has been. */
59
60
  contentApplied: string | null
61
+ /** What the package says it is, from its `package.json`; empty when it says nothing. */
62
+ description: string
63
+ /** The crombolo releases it is written for. */
64
+ peerRange: string
60
65
  }
61
66
 
62
67
  /** What became of the content half of an install. */
@@ -308,6 +313,8 @@ export function createMarketplace(options: MarketplaceOptions): Marketplace {
308
313
  carries: bundle.carries,
309
314
  wired: wired.has(bundle.id),
310
315
  contentApplied: (await options.contentApplied?.(bundle.packageName)) ?? null,
316
+ description: descriptionOf(bundle.directory),
317
+ peerRange: bundle.peerRange,
311
318
  })),
312
319
  )
313
320
  },
@@ -386,6 +393,18 @@ export function createMarketplace(options: MarketplaceOptions): Marketplace {
386
393
  }
387
394
  }
388
395
 
396
+ /** A package's own description, read leniently: anything unreadable is none. */
397
+ function descriptionOf(directory: string): string {
398
+ try {
399
+ const json = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8')) as {
400
+ description?: unknown
401
+ }
402
+ return typeof json.description === 'string' ? json.description : ''
403
+ } catch {
404
+ return ''
405
+ }
406
+ }
407
+
389
408
  /** What a site that does not install at runtime says instead, with what to do. */
390
409
  function refusedHere(name: string, verb: 'add' | 'remove'): InstallOutcome {
391
410
  return {
package/src/server.ts CHANGED
@@ -1467,7 +1467,7 @@ export async function createServer(config: CromboloConfig = loadConfig()): Promi
1467
1467
  }
1468
1468
 
1469
1469
  // Non-contract: approval workflows (story 028) — the page's Workflow tab, the
1470
- // Workflow section and its designer. Content or Workflow, as either screen is.
1470
+ // Workflows section and its designer. Content or Workflows, as either screen is.
1471
1471
  if (pathname.startsWith(`${paths.pluginPath}/api/approvals/`)) {
1472
1472
  const principal = await authenticate(request)
1473
1473
  if (!principal) return new Response('Unauthorized', { status: 401 })