@ossy/platform 3.6.2 → 3.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/platform",
3
- "version": "3.6.2",
3
+ "version": "3.7.1",
4
4
  "description": "Ossy application server runtime",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  "@aws-sdk/util-format-url": "^3.972.17",
46
46
  "@modelcontextprotocol/sdk": "^1.12.1",
47
47
  "@ossy/config": "^3.0.9",
48
- "@ossy/event-store": "^3.6.2",
48
+ "@ossy/event-store": "^3.7.0",
49
49
  "@ossy/locale": "^3.4.0",
50
50
  "@ossy/manifest": "^3.6.1",
51
51
  "@ossy/observability": "^3.0.9",
@@ -54,7 +54,7 @@
54
54
  "@ossy/sdk": "^3.5.0",
55
55
  "@ossy/tokens": "^3.5.0",
56
56
  "@ossy/users": "^3.6.1",
57
- "@ossy/workspaces": "^3.6.1",
57
+ "@ossy/workspaces": "^3.7.1",
58
58
  "cookie-parser": "^1.4.7",
59
59
  "dotenv": ">=16.0.0 <18.0.0",
60
60
  "express": ">=5.0.0 <6.0.0",
@@ -75,5 +75,5 @@
75
75
  "Dockerfile",
76
76
  "docker-healthcheck.js"
77
77
  ],
78
- "gitHead": "d81b840c5421995e8ac7550e5b37ae1145abcba9"
78
+ "gitHead": "1ee220424da6b065034a7f52f52aa4a6ce7c88d5"
79
79
  }
package/src/server.js CHANGED
@@ -495,6 +495,8 @@ export async function startServer (options = {}) {
495
495
  } = resolvePageLayoutRender(layoutsById, pageEntry)
496
496
  const { language, messages, fallbackMessages } = resolveRequestLocale(pageRouter, requestUrl, buildDir, config)
497
497
  let schemasForPage = cloneSerializable(manifest.schemas || [])
498
+ let ssrWorkspaceName
499
+ let ssrWorkspaceServices
498
500
  if (req.workspaceId && loadWorkspaceForEntitlements) {
499
501
  const workspaceTimer = createTimedOperation(`SSR loadWorkspace ${req.workspaceId}`, { log })
500
502
  try {
@@ -506,6 +508,8 @@ export async function startServer (options = {}) {
506
508
  cloneSerializable(workspace.schemas),
507
509
  )
508
510
  }
511
+ ssrWorkspaceName = workspace?.name
512
+ ssrWorkspaceServices = workspace?.services
509
513
  } catch (err) {
510
514
  workspaceTimer.finish({
511
515
  pageId: pageRoute.id,
@@ -527,6 +531,9 @@ export async function startServer (options = {}) {
527
531
  const props = {
528
532
  ...config,
529
533
  ...(req.userAppSettings || {}),
534
+ ...(req.workspaceId ? { workspaceId: req.workspaceId } : {}),
535
+ ...(ssrWorkspaceName != null ? { workspaceName: ssrWorkspaceName } : {}),
536
+ ...(ssrWorkspaceServices != null ? { workspaceServices: cloneSerializable(ssrWorkspaceServices) } : {}),
530
537
  theme: req.userAppSettings?.theme || cloneSerializable(config?.theme),
531
538
  themes: cloneSerializable(config?.themes),
532
539
  schemas: schemasForPage,
@@ -6,6 +6,24 @@
6
6
  */
7
7
 
8
8
  const KEY_PATTERN = /^[A-Za-z0-9_-]+(:[A-Za-z0-9_-]+)?$/
9
+ const RESOURCE_ID_PATTERN = /^[A-Za-z0-9_-]+$/
10
+
11
+ export function isStorageKey (key) {
12
+ return typeof key === 'string' && KEY_PATTERN.test(key)
13
+ }
14
+
15
+ /**
16
+ * Map a stored `content.Key` to a logical key for `/r/{id}` URLs.
17
+ * Legacy S3 paths (`media/{workspaceId}/{resourceId}/original.ext`) fall back
18
+ * to `resourceId` so folder list does not 500 after leftover File docs appear.
19
+ */
20
+ export function coerceStorageKey (key, fallbackResourceId) {
21
+ if (isStorageKey(key)) return key
22
+ if (typeof fallbackResourceId === 'string' && RESOURCE_ID_PATTERN.test(fallbackResourceId)) {
23
+ return fallbackResourceId
24
+ }
25
+ return null
26
+ }
9
27
 
10
28
  export function originalObjectKey (resourceId) {
11
29
  assertResourceId(resourceId)
@@ -31,7 +49,7 @@ export function assertStorageKey (key) {
31
49
  }
32
50
 
33
51
  function assertResourceId (resourceId) {
34
- if (!resourceId || typeof resourceId !== 'string' || !/^[A-Za-z0-9_-]+$/.test(resourceId)) {
52
+ if (!resourceId || typeof resourceId !== 'string' || !RESOURCE_ID_PATTERN.test(resourceId)) {
35
53
  throw new Error(`[storage-keys] invalid resourceId: ${resourceId}`)
36
54
  }
37
55
  }
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from '@jest/globals'
2
- import { originalObjectKey, derivativeObjectKey, assertStorageKey } from './storage-keys.js'
2
+ import { originalObjectKey, derivativeObjectKey, assertStorageKey, coerceStorageKey } from './storage-keys.js'
3
3
 
4
4
  describe('storage-keys', () => {
5
5
  it('originalObjectKey returns flat resourceId', () => {
@@ -13,4 +13,10 @@ describe('storage-keys', () => {
13
13
  it('rejects path-like keys', () => {
14
14
  expect(() => assertStorageKey('media/ws/file')).toThrow()
15
15
  })
16
+
17
+ it('coerces legacy media paths to the resource id', () => {
18
+ expect(coerceStorageKey('media/ws/abc123/original.pdf', 'abc123')).toBe('abc123')
19
+ expect(coerceStorageKey('abc123:galleryMedium', 'abc123')).toBe('abc123:galleryMedium')
20
+ expect(coerceStorageKey('media/ws/file', 'not valid')).toBe(null)
21
+ })
16
22
  })