-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobjectstack.config.ts
More file actions
168 lines (158 loc) · 8.35 KB
/
Copy pathobjectstack.config.ts
File metadata and controls
168 lines (158 loc) · 8.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
import { defineStack } from '@objectstack/spec';
import { ConnectorRestPlugin } from '@objectstack/connector-rest';
import { ConnectorOpenApiPlugin } from '@objectstack/connector-openapi';
import { ConnectorMcpPlugin } from '@objectstack/connector-mcp';
// ─── Barrels ────────────────────────────────────────────────────────────────
// Every metadata directory is wired here up front, including the ones that are
// still empty. A feature branch adds its entry to its OWN barrel and never
// edits this file — which is the one file every parallel task would otherwise
// collide on. See src/*/index.ts for why each collection is a named array
// rather than `Object.values(barrel)`.
import { dulyObjects } from './src/objects/index.js';
import { dulyViews } from './src/views/index.js';
import { dulyApps } from './src/apps/index.js';
import { dulyPages } from './src/pages/index.js';
import { dulyActions } from './src/actions/index.js';
import { dulyFlows } from './src/flows/index.js';
import { dulyJobs } from './src/jobs/index.js';
import { dulyDashboards } from './src/dashboards/index.js';
import { dulyDatasets } from './src/datasets/index.js';
import { dulyMappings } from './src/mappings/index.js';
import { dulyTranslations } from './src/translations/index.js';
import { dulyEmailTemplates } from './src/email-templates/index.js';
import { dulySeeds } from './src/data/index.js';
// [#7036] Lifecycle hooks are NOT collected from the objects barrel — the
// runtime reads them from `defineStack({ hooks })` only. A `*.hook.ts` that is
// not exported from src/hooks/ is dead metadata: it type-checks, it reads as
// wired, and it never runs.
import { dulyHooks } from './src/hooks/index.js';
import { dulyFunctions } from './src/functions/index.js';
import { dulyPositions, dulyPermissionSets, dulySharingRules } from './src/security/index.js';
// ─── Action handler registration ────────────────────────────────────────────
// Action metadata declares the button; the handler is runtime code the kernel
// wires here, after the engine is ready. Pre-wired for the same reason as the
// barrels — handlers are added in src/actions/register-handlers.ts, not here.
import { registerDulyActionHandlers } from './src/actions/register-handlers.js';
import type { HandlerRegistrationContext } from './src/actions/register-handlers.js';
export const onEnable = async (ctx: { ql: HandlerRegistrationContext }) => {
registerDulyActionHandlers(ctx.ql);
};
export default defineStack({
manifest: {
id: 'ai.objectstack.duly',
namespace: 'duly',
version: '0.1.0',
type: 'app',
name: 'Duly',
description:
'Recurring obligation and duty management: every role\'s standing duties dispatched on time, tracked to completion, and visible up the line without a status meeting.',
// Protocol compatibility range (ADR-0087 D1): an incompatible runtime
// refuses this package at the boundary with the exact migration command
// instead of failing deep in a schema parse.
engines: { protocol: '^17' },
},
// `automation` backs flow and job execution, and materialises declarative
// `connectors:` entries at boot (ADR-0097). The dispatcher lives there.
//
// `hierarchy-security` is REQUIRED, not optional, and declaring it installs
// nothing. Manager visibility is authored with the ADR-0057 depth scopes,
// and `defineStack`'s own `validateHierarchyScopeCapability` refuses to load
// a stack that grants `own_and_reports`, `unit` or `unit_and_below` without
// this entry:
//
// > A stack that uses one MUST declare `requires: ['hierarchy-security']`;
// > otherwise the open runtime would silently fail closed to owner-only
// > (the metadata would lie, ADR-0049). This makes that an authoring-time
// > error instead.
//
// (`org` is NOT a hierarchy scope and passes that check — which is the
// trapdoor: it is authorable without this line and discloses the whole
// tenant. Depth for managers is `unit_and_below`, never `org`.)
//
// Declaring it does NOT fail an open-edition boot. Measured on this
// checkout with @objectstack/security-enterprise absent: `validate`, `test`
// and `build` all exit 0 and the kernel logs `Bootstrap complete`; the
// capability-provider check prints ONE warning naming the package to
// install. That warning is the expected state here — the honest signal that
// these scopes resolve to owner-only until a deployment provides the
// resolver. Do not silence it: the only ways to are installing the
// enterprise package (not wanted in this repo) or deleting this entry,
// which puts the hard error back.
//
// `triggers` is what makes an autolaunched flow actually FIRE. `automation`
// ships the flow ENGINE and the `FlowTrigger` wiring; it registers no
// concrete trigger, so without this token every flow in the app is inert.
//
// ONE token mounts all four kinds — there is no second declaration to make.
// `triggers` is the only trigger entry in the platform vocabulary
// (`PLATFORM_CAPABILITY_TOKENS`), and the CLI's capability map keys it to
// `@objectstack/trigger-record-change` plus three `extras`:
// `ScheduleTriggerPlugin` and `TimeRelativeTriggerPlugin` (both from
// `@objectstack/trigger-schedule`) and `ApiTriggerPlugin` (from
// `@objectstack/trigger-api`). So `record_change` (the #33 fan-out) and
// `time_relative` (the three #70 sweeps) come from this single entry.
// The sweeps also need the job service; `job` is in
// `PLATFORM_ALWAYS_ON_CAPABILITIES` and mounts whether or not it is named.
//
// ⛔ Omitting it fails SILENT — that is the whole reason this comment is
// long. Unlike `hierarchy-security` above, whose absence
// `validateHierarchyScopeCapability` turns into an author-time HARD ERROR,
// an undeclared trigger capability is caught by nothing at author time.
// Measured on @objectstack/cli 17.2.0 with this entry absent: `validate`,
// `typecheck`, `test` and `build` all exit 0, and `validate` prints
// `Logic: 4 Flows` and says nothing further. The ONLY channel that tells
// you is the CLI startup banner:
//
// Flows: 4 flow(s) 0 bound to triggers
// ⚠ flow 'duly_assignment_fanout' declares a 'record_change' trigger but
// is NOT bound — no 'record_change' trigger is registered —
// add requires: ['triggers']
//
// Four gates green, `defineStack` happy, and the assignment fan-out dark
// from the day it merged. With this entry the same boot reads
// `4 flow(s) 4 bound to triggers` and prints no unbound warning.
//
// `test/trigger-capability.test.ts` goes red if this token is ever dropped
// while `dulyFlows` is non-empty — the four gates will not catch it again.
// The author-time asymmetry itself is filed upstream as
// objectstack-ai/objectstack#14153.
requires: ['automation', 'triggers', 'hierarchy-security'],
plugins: [
new ConnectorRestPlugin(),
new ConnectorOpenApiPlugin(),
new ConnectorMcpPlugin(),
],
objects: dulyObjects,
views: dulyViews,
apps: dulyApps,
pages: dulyPages,
actions: dulyActions,
flows: dulyFlows,
jobs: dulyJobs,
dashboards: dulyDashboards,
datasets: dulyDatasets,
mappings: dulyMappings,
translations: dulyTranslations,
emailTemplates: dulyEmailTemplates,
data: dulySeeds,
hooks: dulyHooks,
functions: dulyFunctions,
// Security posture. The hierarchy read scopes ('own_and_reports', 'unit',
// 'unit_and_below') are resolved by @objectstack/security-enterprise, which
// is a HARD product dependency — declared as `hierarchy-security` in
// `requires` above. Without the package installed they resolve to
// owner-only, announced by the capability-provider warning on every
// validate/build rather than silently.
// See docs/product/data-model.md#security-posture.
positions: dulyPositions,
permissions: dulyPermissionSets,
sharingRules: dulySharingRules,
// Duly is sold worldwide; English is the source language and every authored
// label is expected to have a bundle entry. See src/translations/.
i18n: {
defaultLocale: 'en',
supportedLocales: ['en', 'zh-CN'],
fallbackLocale: 'en',
},
});