@ossy/app 1.32.1 → 1.32.3
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/cli/build.task.js +31 -1
- package/cli/get-platform-files.task.js +19 -9
- package/cli/manifest-plugin.js +73 -4
- package/package.json +9 -9
package/cli/build.task.js
CHANGED
|
@@ -16,10 +16,12 @@ import getPlatformFiles, {
|
|
|
16
16
|
RESOURCE_FILE_PATTERN,
|
|
17
17
|
COMPONENT_FILE_PATTERN,
|
|
18
18
|
AGGREGATE_FILE_PATTERN,
|
|
19
|
+
INTEGRATION_FILE_PATTERN,
|
|
20
|
+
STARTUP_FILE_PATTERN,
|
|
19
21
|
} from './get-platform-files.task.js'
|
|
20
22
|
import { manifestPlugin } from './manifest-plugin.js'
|
|
21
23
|
|
|
22
|
-
export { PAGE_FILE_PATTERN, API_FILE_PATTERN, TASK_FILE_PATTERN, RESOURCE_FILE_PATTERN, COMPONENT_FILE_PATTERN, AGGREGATE_FILE_PATTERN }
|
|
24
|
+
export { PAGE_FILE_PATTERN, API_FILE_PATTERN, TASK_FILE_PATTERN, RESOURCE_FILE_PATTERN, COMPONENT_FILE_PATTERN, AGGREGATE_FILE_PATTERN, INTEGRATION_FILE_PATTERN, STARTUP_FILE_PATTERN }
|
|
23
25
|
|
|
24
26
|
// Generated entry stubs live under `build/.ossy/entries/`. Putting them
|
|
25
27
|
// inside `build/` means they're cleaned automatically with every build,
|
|
@@ -156,12 +158,38 @@ function generateAggregateStub ({ stubAbs, sourceAbs }) {
|
|
|
156
158
|
].join('\n')
|
|
157
159
|
}
|
|
158
160
|
|
|
161
|
+
// Integrations are server-side only. The stub re-exports `id`, `credentials`,
|
|
162
|
+
// and `connect` so the manifest plugin can validate them and the platform
|
|
163
|
+
// server can call `connect({ env })` at startup.
|
|
164
|
+
function generateIntegrationStub ({ stubAbs, sourceAbs }) {
|
|
165
|
+
const importPath = relImport(stubAbs, sourceAbs)
|
|
166
|
+
return [
|
|
167
|
+
'// Generated by @ossy/app — do not edit',
|
|
168
|
+
`export * from '${importPath}'`,
|
|
169
|
+
'',
|
|
170
|
+
].join('\n')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Startups are server-side one-shot hooks. The stub re-exports `id` and `run`
|
|
174
|
+
// so the manifest plugin can validate them and the platform server can call
|
|
175
|
+
// `run({ env })` at boot time.
|
|
176
|
+
function generateStartupStub ({ stubAbs, sourceAbs }) {
|
|
177
|
+
const importPath = relImport(stubAbs, sourceAbs)
|
|
178
|
+
return [
|
|
179
|
+
'// Generated by @ossy/app — do not edit',
|
|
180
|
+
`export * from '${importPath}'`,
|
|
181
|
+
'',
|
|
182
|
+
].join('\n')
|
|
183
|
+
}
|
|
184
|
+
|
|
159
185
|
function stubFor (kind, args) {
|
|
160
186
|
if (kind === 'page') return generatePageStub(args)
|
|
161
187
|
if (kind === 'api') return generateApiStub(args)
|
|
162
188
|
if (kind === 'resource') return generateResourceStub(args)
|
|
163
189
|
if (kind === 'component') return generateComponentStub(args)
|
|
164
190
|
if (kind === 'aggregate') return generateAggregateStub(args)
|
|
191
|
+
if (kind === 'integration') return generateIntegrationStub(args)
|
|
192
|
+
if (kind === 'startup') return generateStartupStub(args)
|
|
165
193
|
return generateTaskStub(args)
|
|
166
194
|
}
|
|
167
195
|
|
|
@@ -204,6 +232,8 @@ export async function build (cliArgs = []) {
|
|
|
204
232
|
...platformFiles.resources,
|
|
205
233
|
...platformFiles.components,
|
|
206
234
|
...platformFiles.aggregates,
|
|
235
|
+
...platformFiles.integrations,
|
|
236
|
+
...platformFiles.startups,
|
|
207
237
|
]
|
|
208
238
|
|
|
209
239
|
const entriesByStub = new Map()
|
|
@@ -7,9 +7,11 @@ export const TASK_FILE_PATTERN = /\.task\.(mjs|cjs|js)$/
|
|
|
7
7
|
export const RESOURCE_FILE_PATTERN = /\.resource\.(mjs|cjs|js)$/
|
|
8
8
|
export const COMPONENT_FILE_PATTERN = /\.component\.(jsx?|tsx?)$/
|
|
9
9
|
export const AGGREGATE_FILE_PATTERN = /\.aggregate\.(mjs|cjs|js)$/
|
|
10
|
+
export const INTEGRATION_FILE_PATTERN = /\.integration\.(mjs|cjs|js)$/
|
|
11
|
+
export const STARTUP_FILE_PATTERN = /\.startup\.(mjs|cjs|js)$/
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
|
-
* @typedef {'page' | 'api' | 'task' | 'resource' | 'component' | 'aggregate'} EntryKind
|
|
14
|
+
* @typedef {'page' | 'api' | 'task' | 'resource' | 'component' | 'aggregate' | 'integration' | 'startup'} EntryKind
|
|
13
15
|
*
|
|
14
16
|
* @typedef {object} PlatformEntry
|
|
15
17
|
* @property {EntryKind} kind Which bucket this entry lives in.
|
|
@@ -18,12 +20,14 @@ export const AGGREGATE_FILE_PATTERN = /\.aggregate\.(mjs|cjs|js)$/
|
|
|
18
20
|
* @property {string} [packageSrcDir] Absolute path to the package's `src/` dir, set only for installed-package entries.
|
|
19
21
|
*
|
|
20
22
|
* @typedef {object} PlatformFiles
|
|
21
|
-
* @property {PlatformEntry[]} pages
|
|
22
|
-
* @property {PlatformEntry[]} apis
|
|
23
|
-
* @property {PlatformEntry[]} tasks
|
|
24
|
-
* @property {PlatformEntry[]} resources
|
|
25
|
-
* @property {PlatformEntry[]} components
|
|
26
|
-
* @property {PlatformEntry[]} aggregates
|
|
23
|
+
* @property {PlatformEntry[]} pages Discovered `*.page.{jsx,tsx,...}` entries.
|
|
24
|
+
* @property {PlatformEntry[]} apis Discovered `*.api.{js,mjs,cjs}` entries.
|
|
25
|
+
* @property {PlatformEntry[]} tasks Discovered `*.task.{js,mjs,cjs}` entries.
|
|
26
|
+
* @property {PlatformEntry[]} resources Discovered `*.resource.{js,mjs,cjs}` entries.
|
|
27
|
+
* @property {PlatformEntry[]} components Discovered `*.component.{jsx,tsx,...}` entries.
|
|
28
|
+
* @property {PlatformEntry[]} aggregates Discovered `*.aggregate.{js,mjs,cjs}` entries (installed packages only).
|
|
29
|
+
* @property {PlatformEntry[]} integrations Discovered `*.integration.{js,mjs,cjs}` entries.
|
|
30
|
+
* @property {PlatformEntry[]} startups Discovered `*.startup.{js,mjs,cjs}` entries.
|
|
27
31
|
*/
|
|
28
32
|
export function discoverFilesByPattern (srcDir, filePattern) {
|
|
29
33
|
const dir = path.resolve(srcDir)
|
|
@@ -48,6 +52,8 @@ function classifyFile (absPath) {
|
|
|
48
52
|
if (RESOURCE_FILE_PATTERN.test(base)) return 'resource'
|
|
49
53
|
if (COMPONENT_FILE_PATTERN.test(base)) return 'component'
|
|
50
54
|
if (AGGREGATE_FILE_PATTERN.test(base)) return 'aggregate'
|
|
55
|
+
if (INTEGRATION_FILE_PATTERN.test(base)) return 'integration'
|
|
56
|
+
if (STARTUP_FILE_PATTERN.test(base)) return 'startup'
|
|
51
57
|
return null
|
|
52
58
|
}
|
|
53
59
|
|
|
@@ -118,6 +124,8 @@ export function discoverInstalledPackageEntries (projectRoot) {
|
|
|
118
124
|
...discoverFilesByPattern(packageSrcDir, RESOURCE_FILE_PATTERN),
|
|
119
125
|
...discoverFilesByPattern(packageSrcDir, COMPONENT_FILE_PATTERN),
|
|
120
126
|
...discoverFilesByPattern(packageSrcDir, AGGREGATE_FILE_PATTERN),
|
|
127
|
+
...discoverFilesByPattern(packageSrcDir, INTEGRATION_FILE_PATTERN),
|
|
128
|
+
...discoverFilesByPattern(packageSrcDir, STARTUP_FILE_PATTERN),
|
|
121
129
|
]
|
|
122
130
|
for (const sourcePath of files) {
|
|
123
131
|
const stat = fs.statSync(sourcePath)
|
|
@@ -161,8 +169,8 @@ export function discoverInstalledPackageEntries (projectRoot) {
|
|
|
161
169
|
* @returns {Promise<PlatformFiles>}
|
|
162
170
|
*/
|
|
163
171
|
export default async function getPlatformFiles (srcDir) {
|
|
164
|
-
const out = { pages: [], apis: [], tasks: [], resources: [], components: [], aggregates: [] }
|
|
165
|
-
const bucketByKind = { page: 'pages', api: 'apis', task: 'tasks', resource: 'resources', component: 'components', aggregate: 'aggregates' }
|
|
172
|
+
const out = { pages: [], apis: [], tasks: [], resources: [], components: [], aggregates: [], integrations: [], startups: [] }
|
|
173
|
+
const bucketByKind = { page: 'pages', api: 'apis', task: 'tasks', resource: 'resources', component: 'components', aggregate: 'aggregates', integration: 'integrations', startup: 'startups' }
|
|
166
174
|
|
|
167
175
|
// Aggregates are only discovered from installed packages — never from the
|
|
168
176
|
// local `src/` — to avoid pulling in per-project duplicates of the same
|
|
@@ -173,6 +181,8 @@ export default async function getPlatformFiles (srcDir) {
|
|
|
173
181
|
...discoverFilesByPattern(srcDir, TASK_FILE_PATTERN),
|
|
174
182
|
...discoverFilesByPattern(srcDir, RESOURCE_FILE_PATTERN),
|
|
175
183
|
...discoverFilesByPattern(srcDir, COMPONENT_FILE_PATTERN),
|
|
184
|
+
...discoverFilesByPattern(srcDir, INTEGRATION_FILE_PATTERN),
|
|
185
|
+
...discoverFilesByPattern(srcDir, STARTUP_FILE_PATTERN),
|
|
176
186
|
]
|
|
177
187
|
for (const sourcePath of localFiles) {
|
|
178
188
|
const stat = fs.statSync(sourcePath)
|
package/cli/manifest-plugin.js
CHANGED
|
@@ -46,12 +46,23 @@ import { metadataIdFromFile, defaultPageRoute } from './get-platform-files.task.
|
|
|
46
46
|
* @property {string} id AggregateType string (e.g. `'User'`).
|
|
47
47
|
* @property {string} entry URL the platform serves the aggregate bundle from.
|
|
48
48
|
*
|
|
49
|
+
* @typedef {object} IntegrationManifestEntry
|
|
50
|
+
* @property {string} id Unique integration slug (e.g. `'email'`).
|
|
51
|
+
* @property {string} entry URL the platform serves the integration bundle from.
|
|
52
|
+
* @property {string[]} credentials Env var names required by the integration.
|
|
53
|
+
*
|
|
54
|
+
* @typedef {object} StartupManifestEntry
|
|
55
|
+
* @property {string} id Unique startup slug (e.g. `'create-bot-user'`).
|
|
56
|
+
* @property {string} entry URL the platform serves the startup bundle from.
|
|
57
|
+
*
|
|
49
58
|
* @typedef {object} Manifest
|
|
50
|
-
* @property {ManifestEntry[]} entries
|
|
59
|
+
* @property {ManifestEntry[]} entries Flat, ordered list of every routable thing.
|
|
51
60
|
* @property {ComponentManifestEntry[]} components Discovered `*.component.*` entries, keyed by id.
|
|
52
|
-
* @property {object[]} resourceTemplates
|
|
61
|
+
* @property {object[]} resourceTemplates Each `*.resource.js` file's default-exported template object.
|
|
53
62
|
* @property {AggregateManifestEntry[]} aggregates Discovered `*.aggregate.js` entries from installed packages.
|
|
54
|
-
* @property {
|
|
63
|
+
* @property {IntegrationManifestEntry[]} integrations Discovered `*.integration.js` entries.
|
|
64
|
+
* @property {StartupManifestEntry[]} startups Discovered `*.startup.js` entries.
|
|
65
|
+
* @property {object} config Inlined `src/config.js` default export.
|
|
55
66
|
*/
|
|
56
67
|
|
|
57
68
|
/**
|
|
@@ -100,9 +111,15 @@ export function manifestPlugin ({ entriesByStub, srcDir, staticOutDir, configVal
|
|
|
100
111
|
const components = []
|
|
101
112
|
/** @type {AggregateManifestEntry[]} */
|
|
102
113
|
const aggregates = []
|
|
114
|
+
/** @type {IntegrationManifestEntry[]} */
|
|
115
|
+
const integrations = []
|
|
116
|
+
/** @type {StartupManifestEntry[]} */
|
|
117
|
+
const startups = []
|
|
103
118
|
const seenIds = { page: new Set(), api: new Set(), task: new Set(), component: new Set() }
|
|
104
119
|
const seenResourceIds = new Set()
|
|
105
120
|
const seenAggregateIds = new Set()
|
|
121
|
+
const seenIntegrationIds = new Set()
|
|
122
|
+
const seenStartupIds = new Set()
|
|
106
123
|
|
|
107
124
|
for (const fileName of Object.keys(bundle)) {
|
|
108
125
|
const chunk = bundle[fileName]
|
|
@@ -128,6 +145,58 @@ export function manifestPlugin ({ entriesByStub, srcDir, staticOutDir, configVal
|
|
|
128
145
|
)
|
|
129
146
|
}
|
|
130
147
|
|
|
148
|
+
// Integrations provide third-party clients. The bundle exports `id`,
|
|
149
|
+
// `credentials` (env var names), and `connect({ env })`. They don't
|
|
150
|
+
// produce routable entries; they accumulate into a separate array.
|
|
151
|
+
if (entryInfo.kind === 'integration') {
|
|
152
|
+
const integrationId = mod && mod.id
|
|
153
|
+
const credentials = mod && mod.credentials
|
|
154
|
+
if (typeof integrationId !== 'string' || integrationId.trim() === '') {
|
|
155
|
+
this.error(
|
|
156
|
+
`[@ossy/app][build] integration entry ${entryInfo.sourcePath} must export a non-empty string "id"`,
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
if (!Array.isArray(credentials)) {
|
|
160
|
+
this.error(
|
|
161
|
+
`[@ossy/app][build] integration entry ${entryInfo.sourcePath} must export a "credentials" array`,
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
if (typeof mod.connect !== 'function') {
|
|
165
|
+
this.error(
|
|
166
|
+
`[@ossy/app][build] integration entry ${entryInfo.sourcePath} must export a "connect" function`,
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
if (seenIntegrationIds.has(integrationId)) {
|
|
170
|
+
this.error(`[@ossy/app][build] Duplicate integration id "${integrationId}"`)
|
|
171
|
+
}
|
|
172
|
+
seenIntegrationIds.add(integrationId)
|
|
173
|
+
integrations.push({ id: integrationId, entry: url, credentials })
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Startups are server-side one-shot hooks. The bundle exports `id`
|
|
178
|
+
// (a unique slug) and `run({ env })`. They don't produce routable
|
|
179
|
+
// entries; they accumulate into a separate `startups` array.
|
|
180
|
+
if (entryInfo.kind === 'startup') {
|
|
181
|
+
const startupId = mod && mod.id
|
|
182
|
+
if (typeof startupId !== 'string' || startupId.trim() === '') {
|
|
183
|
+
this.error(
|
|
184
|
+
`[@ossy/app][build] startup entry ${entryInfo.sourcePath} must export a non-empty string "id"`,
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
if (typeof mod.run !== 'function') {
|
|
188
|
+
this.error(
|
|
189
|
+
`[@ossy/app][build] startup entry ${entryInfo.sourcePath} must export a "run" function`,
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
if (seenStartupIds.has(startupId)) {
|
|
193
|
+
this.error(`[@ossy/app][build] Duplicate startup id "${startupId}"`)
|
|
194
|
+
}
|
|
195
|
+
seenStartupIds.add(startupId)
|
|
196
|
+
startups.push({ id: startupId, entry: url })
|
|
197
|
+
continue
|
|
198
|
+
}
|
|
199
|
+
|
|
131
200
|
// Aggregates are server-side classes — the bundle exports `Aggregate`
|
|
132
201
|
// (the class) and `id` (the AggregateType string). They don't produce
|
|
133
202
|
// routable entries; they accumulate into a separate `aggregates` array.
|
|
@@ -213,7 +282,7 @@ export function manifestPlugin ({ entriesByStub, srcDir, staticOutDir, configVal
|
|
|
213
282
|
}
|
|
214
283
|
|
|
215
284
|
/** @type {Manifest} */
|
|
216
|
-
const manifest = { entries, components, resourceTemplates, aggregates, config: configValue || {} }
|
|
285
|
+
const manifest = { entries, components, resourceTemplates, aggregates, integrations, startups, config: configValue || {} }
|
|
217
286
|
fs.mkdirSync(path.dirname(manifestPath), { recursive: true })
|
|
218
287
|
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8')
|
|
219
288
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/app",
|
|
3
|
-
"version": "1.32.
|
|
3
|
+
"version": "1.32.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"source": "./src/index.js",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -38,14 +38,14 @@
|
|
|
38
38
|
"@babel/eslint-parser": "^7.15.8",
|
|
39
39
|
"@babel/preset-react": "^7.26.3",
|
|
40
40
|
"@babel/register": "^7.25.9",
|
|
41
|
-
"@ossy/design-system": "^1.32.
|
|
41
|
+
"@ossy/design-system": "^1.32.3",
|
|
42
42
|
"@ossy/pages": "^1.23.0",
|
|
43
|
-
"@ossy/platform": "^1.31.
|
|
44
|
-
"@ossy/router": "^1.32.
|
|
45
|
-
"@ossy/router-react": "^1.32.
|
|
46
|
-
"@ossy/sdk": "^1.32.
|
|
47
|
-
"@ossy/sdk-react": "^1.32.
|
|
48
|
-
"@ossy/themes": "^1.32.
|
|
43
|
+
"@ossy/platform": "^1.31.3",
|
|
44
|
+
"@ossy/router": "^1.32.3",
|
|
45
|
+
"@ossy/router-react": "^1.32.3",
|
|
46
|
+
"@ossy/sdk": "^1.32.3",
|
|
47
|
+
"@ossy/sdk-react": "^1.32.3",
|
|
48
|
+
"@ossy/themes": "^1.32.3",
|
|
49
49
|
"@rollup/plugin-alias": "^6.0.0",
|
|
50
50
|
"@rollup/plugin-babel": "^7.0.0",
|
|
51
51
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"README.md",
|
|
80
80
|
"tsconfig.json"
|
|
81
81
|
],
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "b8cbdc545a659e96af8948aa08a89316a2c2d193"
|
|
83
83
|
}
|