@digimuza/system-core 0.0.0-stage → 0.2.0-rc.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.
Files changed (168) hide show
  1. package/INTEGRATION.md +255 -0
  2. package/README.md +164 -2
  3. package/dist/config/browser.d.ts +17 -0
  4. package/dist/config/browser.d.ts.map +1 -0
  5. package/dist/config/browser.js +16 -0
  6. package/dist/config/browser.js.map +1 -0
  7. package/dist/config/index.d.ts +71 -0
  8. package/dist/config/index.d.ts.map +1 -0
  9. package/dist/config/index.js +166 -0
  10. package/dist/config/index.js.map +1 -0
  11. package/dist/convex/functions.d.ts +424 -0
  12. package/dist/convex/functions.d.ts.map +1 -0
  13. package/dist/convex/functions.js +288 -0
  14. package/dist/convex/functions.js.map +1 -0
  15. package/dist/convex/index.d.ts +7 -0
  16. package/dist/convex/index.d.ts.map +1 -0
  17. package/dist/convex/index.js +9 -0
  18. package/dist/convex/index.js.map +1 -0
  19. package/dist/convex/schema.d.ts +350 -0
  20. package/dist/convex/schema.d.ts.map +1 -0
  21. package/dist/convex/schema.js +157 -0
  22. package/dist/convex/schema.js.map +1 -0
  23. package/dist/convex/store.d.ts +10 -0
  24. package/dist/convex/store.d.ts.map +1 -0
  25. package/dist/convex/store.js +62 -0
  26. package/dist/convex/store.js.map +1 -0
  27. package/dist/core/access.d.ts +109 -0
  28. package/dist/core/access.d.ts.map +1 -0
  29. package/dist/core/access.js +301 -0
  30. package/dist/core/access.js.map +1 -0
  31. package/dist/core/api-keys.d.ts +39 -0
  32. package/dist/core/api-keys.d.ts.map +1 -0
  33. package/dist/core/api-keys.js +115 -0
  34. package/dist/core/api-keys.js.map +1 -0
  35. package/dist/core/audit.d.ts +30 -0
  36. package/dist/core/audit.d.ts.map +1 -0
  37. package/dist/core/audit.js +66 -0
  38. package/dist/core/audit.js.map +1 -0
  39. package/dist/core/catalog.d.ts +123 -0
  40. package/dist/core/catalog.d.ts.map +1 -0
  41. package/dist/core/catalog.js +157 -0
  42. package/dist/core/catalog.js.map +1 -0
  43. package/dist/core/context.d.ts +41 -0
  44. package/dist/core/context.d.ts.map +1 -0
  45. package/dist/core/context.js +34 -0
  46. package/dist/core/context.js.map +1 -0
  47. package/dist/core/crypto.d.ts +8 -0
  48. package/dist/core/crypto.d.ts.map +1 -0
  49. package/dist/core/crypto.js +41 -0
  50. package/dist/core/crypto.js.map +1 -0
  51. package/dist/core/errors.d.ts +46 -0
  52. package/dist/core/errors.d.ts.map +1 -0
  53. package/dist/core/errors.js +77 -0
  54. package/dist/core/errors.js.map +1 -0
  55. package/dist/core/feature-flags.d.ts +26 -0
  56. package/dist/core/feature-flags.d.ts.map +1 -0
  57. package/dist/core/feature-flags.js +66 -0
  58. package/dist/core/feature-flags.js.map +1 -0
  59. package/dist/core/index.d.ts +19 -0
  60. package/dist/core/index.d.ts.map +1 -0
  61. package/dist/core/index.js +21 -0
  62. package/dist/core/index.js.map +1 -0
  63. package/dist/core/invites.d.ts +70 -0
  64. package/dist/core/invites.d.ts.map +1 -0
  65. package/dist/core/invites.js +180 -0
  66. package/dist/core/invites.js.map +1 -0
  67. package/dist/core/jobs.d.ts +38 -0
  68. package/dist/core/jobs.d.ts.map +1 -0
  69. package/dist/core/jobs.js +52 -0
  70. package/dist/core/jobs.js.map +1 -0
  71. package/dist/core/modules-service.d.ts +57 -0
  72. package/dist/core/modules-service.d.ts.map +1 -0
  73. package/dist/core/modules-service.js +77 -0
  74. package/dist/core/modules-service.js.map +1 -0
  75. package/dist/core/redact.d.ts +9 -0
  76. package/dist/core/redact.d.ts.map +1 -0
  77. package/dist/core/redact.js +58 -0
  78. package/dist/core/redact.js.map +1 -0
  79. package/dist/core/registry.d.ts +36 -0
  80. package/dist/core/registry.d.ts.map +1 -0
  81. package/dist/core/registry.js +170 -0
  82. package/dist/core/registry.js.map +1 -0
  83. package/dist/core/role-view.d.ts +19 -0
  84. package/dist/core/role-view.d.ts.map +1 -0
  85. package/dist/core/role-view.js +41 -0
  86. package/dist/core/role-view.js.map +1 -0
  87. package/dist/core/roles.d.ts +122 -0
  88. package/dist/core/roles.d.ts.map +1 -0
  89. package/dist/core/roles.js +426 -0
  90. package/dist/core/roles.js.map +1 -0
  91. package/dist/core/store.d.ts +239 -0
  92. package/dist/core/store.d.ts.map +1 -0
  93. package/dist/core/store.js +34 -0
  94. package/dist/core/store.js.map +1 -0
  95. package/dist/core/system-modules.d.ts +44 -0
  96. package/dist/core/system-modules.d.ts.map +1 -0
  97. package/dist/core/system-modules.js +205 -0
  98. package/dist/core/system-modules.js.map +1 -0
  99. package/dist/core/users.d.ts +64 -0
  100. package/dist/core/users.d.ts.map +1 -0
  101. package/dist/core/users.js +184 -0
  102. package/dist/core/users.js.map +1 -0
  103. package/dist/diagnostics/logging.d.ts +44 -0
  104. package/dist/diagnostics/logging.d.ts.map +1 -0
  105. package/dist/diagnostics/logging.js +64 -0
  106. package/dist/diagnostics/logging.js.map +1 -0
  107. package/dist/diagnostics/tracing.d.ts +65 -0
  108. package/dist/diagnostics/tracing.d.ts.map +1 -0
  109. package/dist/diagnostics/tracing.js +110 -0
  110. package/dist/diagnostics/tracing.js.map +1 -0
  111. package/dist/finance/index.d.ts +118 -0
  112. package/dist/finance/index.d.ts.map +1 -0
  113. package/dist/finance/index.js +144 -0
  114. package/dist/finance/index.js.map +1 -0
  115. package/dist/index.d.ts +10 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +7 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/modules/index.d.ts +4 -0
  120. package/dist/modules/index.d.ts.map +1 -0
  121. package/dist/modules/index.js +5 -0
  122. package/dist/modules/index.js.map +1 -0
  123. package/dist/next/index.d.ts +57 -0
  124. package/dist/next/index.d.ts.map +1 -0
  125. package/dist/next/index.js +97 -0
  126. package/dist/next/index.js.map +1 -0
  127. package/dist/react/index.d.ts +54 -0
  128. package/dist/react/index.d.ts.map +1 -0
  129. package/dist/react/index.js +62 -0
  130. package/dist/react/index.js.map +1 -0
  131. package/dist/testing/index.d.ts +33 -0
  132. package/dist/testing/index.d.ts.map +1 -0
  133. package/dist/testing/index.js +94 -0
  134. package/dist/testing/index.js.map +1 -0
  135. package/package.json +110 -4
  136. package/src/config/browser.ts +16 -0
  137. package/src/config/index.ts +216 -0
  138. package/src/convex/functions.ts +394 -0
  139. package/src/convex/index.ts +9 -0
  140. package/src/convex/schema.ts +175 -0
  141. package/src/convex/store.ts +68 -0
  142. package/src/core/access.ts +340 -0
  143. package/src/core/api-keys.ts +141 -0
  144. package/src/core/audit.ts +88 -0
  145. package/src/core/catalog.ts +226 -0
  146. package/src/core/context.ts +73 -0
  147. package/src/core/crypto.ts +43 -0
  148. package/src/core/errors.ts +97 -0
  149. package/src/core/feature-flags.ts +70 -0
  150. package/src/core/index.ts +20 -0
  151. package/src/core/invites.ts +198 -0
  152. package/src/core/jobs.ts +58 -0
  153. package/src/core/modules-service.ts +117 -0
  154. package/src/core/redact.ts +56 -0
  155. package/src/core/registry.ts +176 -0
  156. package/src/core/role-view.ts +43 -0
  157. package/src/core/roles.ts +431 -0
  158. package/src/core/store.ts +216 -0
  159. package/src/core/system-modules.ts +210 -0
  160. package/src/core/users.ts +210 -0
  161. package/src/diagnostics/logging.ts +99 -0
  162. package/src/diagnostics/tracing.ts +171 -0
  163. package/src/finance/index.ts +189 -0
  164. package/src/index.ts +19 -0
  165. package/src/modules/index.ts +18 -0
  166. package/src/next/index.ts +144 -0
  167. package/src/react/index.tsx +85 -0
  168. package/src/testing/index.ts +100 -0
package/INTEGRATION.md ADDED
@@ -0,0 +1,255 @@
1
+ # Integrating `@digimuza/system-core`
2
+
3
+ `README.md` is the product contract. This guide shows how to wire the package
4
+ into one tenant's Next.js + Convex application.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ npm install @digimuza/system-core convex zod # + next, react for the Next.js entries
10
+ ```
11
+
12
+ Pin the version per tenant app (`"@digimuza/system-core": "0.1.0"`, or `~0.1.0`) and upgrade deliberately.
13
+
14
+ ## Entry points
15
+
16
+ | Import | Runtime | Purpose |
17
+ | - | - | - |
18
+ | `@digimuza/system-core/config` | Server only | `SystemConfig.load()` / `register(schema)`, Infisical source. Browser builds resolve to a stub that throws. |
19
+ | `@digimuza/system-core/modules` | Any | `defineModule()`, manifest types, `PermissionOf<>`. |
20
+ | `@digimuza/system-core/convex` | Convex | `systemTables`, `defineConvexSystem()`, `requirePermission`, all core services. |
21
+ | `@digimuza/system-core/next` | Next.js server | `createSystemServerClient()` (session token, tracing, typed errors), `createAgentClient()`. |
22
+ | `@digimuza/system-core/react` | Client components | `<SystemProvider>`, `useCan`, `useVisibleModules`, `useCurrentUser`, `useFeatureFlag`, `useRoleView`, `<Can>`. |
23
+ | `@digimuza/system-core/finance` | Convex | The finance business module: `finance` manifest, `financeTables`, `defineFinance(system)` functions, `FinancePermissions`, `InvoiceView`. |
24
+ | `@digimuza/system-core` | Any | `SystemError`, redaction, logger, tracer, shared types. |
25
+ | `@digimuza/system-core/testing` | Tests | `MemoryStore` (same semantics as Convex, serializable transactions). |
26
+
27
+ These seven subpaths, listed in `package.json#exports`, are the whole public surface. Deep imports
28
+ (`@digimuza/system-core/dist/...`) are not supported. Server and browser entries stay separate:
29
+ `.`, `./modules` and `./react` never import `./config`, `./convex` or `./next`, and never read
30
+ `process.env`. `npm run check:pack` enforces this in CI. Removing or renaming an entry or export,
31
+ or moving code across the server/browser line, is a breaking change (a major bump; while on 0.x,
32
+ a minor bump with a changelog note).
33
+
34
+ ## 1. Declare business modules
35
+
36
+ ```ts
37
+ // modules/finance.ts
38
+ import { defineModule } from "@digimuza/system-core/modules"
39
+
40
+ export const finance = defineModule({
41
+ id: "finance",
42
+ kind: "business",
43
+ description: "Sąskaitų peržiūra ir tvirtinimas",
44
+ permissions: [
45
+ { id: "finance:invoice:read", name: "Skaityti", description: "Peržiūrėti sąskaitą" },
46
+ { id: "finance:invoice:approve", name: "Tvirtinti", description: "Patvirtinti sąskaitą" },
47
+ ],
48
+ initialSubroles: [
49
+ { id: "finance:reader", name: "Skaitytojas", description: "Gali peržiūrėti sąskaitas", permissions: ["finance:invoice:read"] },
50
+ ],
51
+ featureFlags: [{ id: "finance:bulk-approve", description: "Bulk approval", default: false }],
52
+ })
53
+ ```
54
+
55
+ `defineModule` validates when it is imported: ID formats, permission prefixes,
56
+ and subroles that reference only their own module's permissions. When the
57
+ modules are composed, ID collisions and unknown dependencies are rejected.
58
+
59
+ ## 2. Convex
60
+
61
+ ```ts
62
+ // convex/schema.ts
63
+ import { defineSchema, defineTable } from "convex/server"
64
+ import { systemTables } from "@digimuza/system-core/convex"
65
+ export default defineSchema({ ...systemTables, invoices: defineTable({ /* … */ }) })
66
+ ```
67
+
68
+ ```ts
69
+ // convex/system.ts (the module path must match `functionsModule`, default "system")
70
+ import { defineConvexSystem } from "@digimuza/system-core/convex"
71
+ import { finance } from "../modules/finance"
72
+
73
+ export const system = defineConvexSystem({
74
+ modules: [finance],
75
+ // superUserEmails defaults to process.env.SUPER_USER_EMAILS (set on the Convex deployment)
76
+ inviteDelivery: { deliver: async ({ email, url, operationId }) => { /* send email */ } },
77
+ inviteUrl: (token) => `${process.env.APP_URL}/invite?token=${token}`,
78
+ })
79
+
80
+ export const {
81
+ session, completeSignIn, registerSystem,
82
+ listModules, setModuleEnabled, listPermissions, explainDecision,
83
+ getUser, findUserByIdentity, listUsers, suspendUser, activateUser, getMyProfile, updateMyProfile,
84
+ listRoles, getRole, listSubroles, createRole, copyRole, updateRole, archiveRole,
85
+ createSubrole, copySubrole, previewSubroleChange, updateSubrole, archiveSubrole,
86
+ assignRoles, revokeRole, setDelegationScope,
87
+ listInvites, getInvite, revokeInvite, createInvite, resendInvite, _createInvite, _resendInvite, _recordInviteDelivery,
88
+ listMyApiKeys, setApiKeyRoles, revokeApiKey, createApiKey, rotateApiKey, _createApiKey, _rotateApiKey,
89
+ listFeatureFlags, setFeatureFlag, resetFeatureFlag, listAudit,
90
+ roleViewStatus, startRoleView, stopRoleView,
91
+ } = system.functions
92
+ ```
93
+
94
+ `system.requirePermission(ctx, …)` and `system.context(ctx)` take the app's own
95
+ generated `QueryCtx` / `MutationCtx` directly; no cast is needed.
96
+
97
+ The default identity mapping reads `email`, and `emailVerified` or the raw
98
+ `email_verified` claim, so custom JWT providers (WorkOS AuthKit with a JWT
99
+ template, most OIDC setups) work without `identityFromJwt`. Pass
100
+ `identityFromJwt` only to change the provider name or claims.
101
+
102
+ ### Business modules shipped in the package
103
+
104
+ ```ts
105
+ // convex/schema.ts
106
+ import { systemTables } from "@digimuza/system-core/convex"
107
+ import { financeTables } from "@digimuza/system-core/finance"
108
+ export default defineSchema({ ...systemTables, ...financeTables })
109
+
110
+ // convex/system.ts
111
+ import { finance } from "@digimuza/system-core/finance"
112
+ export const system = defineConvexSystem({ modules: [finance] })
113
+
114
+ // convex/finance.ts
115
+ import { defineFinance } from "@digimuza/system-core/finance"
116
+ import { system } from "./system"
117
+ export const { listInvoices, createInvoice, approveInvoice, bulkApproveInvoices } = defineFinance(system)
118
+ ```
119
+
120
+ Each function guards itself (permission, module enabled, role view), checks the
121
+ object (existence, state transition), writes, and records an audit event in one
122
+ transaction. The UI stays in the app.
123
+
124
+ ### View as role (Super)
125
+
126
+ A real Super (verified email in `SUPER_USER_EMAILS`) can preview the system as
127
+ a holder of one role: `startRoleView({ roleId })`, `stopRoleView()`,
128
+ `roleViewStatus()`. While a preview is active, every decision treats the Super
129
+ as that role: business permissions, module state (disabled modules stay off),
130
+ Super-only actions (`setModuleEnabled`, …), the core's admin functions,
131
+ delegation and invites. `session` returns `actor.isSuper: false`, the role's
132
+ permissions, `canViewAs: true` and `roleView: { roleId, roleName }`. The
133
+ Super's own API keys keep the owner's real Super status, so a preview never
134
+ breaks running agents. Starting and stopping are audited
135
+ (`super.role_view.start` / `.stop`); an archived role ends the preview.
136
+
137
+ Business functions guard themselves on the server, in the same transaction as
138
+ the change:
139
+
140
+ ```ts
141
+ // convex/invoices.ts
142
+ import { mutation } from "./_generated/server"
143
+ import { v } from "convex/values"
144
+ import { recordAudit } from "@digimuza/system-core/convex"
145
+ import { system } from "./system"
146
+
147
+ export const approve = mutation({
148
+ args: { invoiceId: v.id("invoices"), apiKey: v.optional(v.string()) },
149
+ handler: async (ctx, args) => {
150
+ const { sys, actor } = await system.requirePermission(ctx, "finance:invoice:approve", { apiKey: args.apiKey })
151
+ // Object-level checks (ownership, allowed state transition) go here.
152
+ await ctx.db.patch("invoices", args.invoiceId, { approved: true })
153
+ await recordAudit(sys, actor, { action: "finance.invoice.approve", targetType: "invoice", targetId: args.invoiceId })
154
+ return { operationId: sys.operationId }
155
+ },
156
+ })
157
+ ```
158
+
159
+ Background jobs store `toActorRef(actor)` and call `authorizeJob(sys, ref, permission)`
160
+ when they run. A `null` result means the job must do nothing. External side
161
+ effects use `claimOperation` and `completeOperation` for replay protection.
162
+
163
+ ## 3. Deployment (Coolify)
164
+
165
+ 1. Pin the app version and the package version.
166
+ 2. Coolify provides `INFISCAL_BASE_URL`, `INFISCAL_CLIENT_ID`, `INFISCAL_SECRET`,
167
+ `INFISCAL_PATH`, `INFISCAL_ENV`, `INFISCAL_PROJECT_ID` and `SUPER_USER_EMAILS`.
168
+ 3. `npx convex deploy`, then `npx convex run system:registerSystem`. Running it
169
+ again is safe. Conflicts abort the whole registration, so a partial catalog
170
+ is never activated.
171
+ 4. On the first sign-in of a verified email from `SUPER_USER_EMAILS`, the
172
+ Super account is created. Everyone else needs an invite.
173
+
174
+ ## 4. Next.js server
175
+
176
+ ```ts
177
+ import SystemConfig from "@digimuza/system-core/config"
178
+ import { createSystemServerClient } from "@digimuza/system-core/next"
179
+ import { z } from "zod"
180
+
181
+ await SystemConfig.load()
182
+ const env = SystemConfig.register(z.object({ APP_URL: z.string().url() }), { moduleId: "web" })
183
+
184
+ const client = createSystemServerClient({ getToken: () => getConvexToken(), headers: await headers() })
185
+ const me = await client.query(api.system.session, { operationId: client.operationId })
186
+ ```
187
+
188
+ Agents call system-aware functions with `createAgentClient({ url, apiKey })`.
189
+
190
+ ## 5. Client components
191
+
192
+ ```tsx
193
+ "use client"
194
+ import { SystemProvider, Can, useVisibleModules } from "@digimuza/system-core/react"
195
+
196
+ <SystemProvider session={api.system.session}>
197
+ <Can permission="finance:invoice:approve"><ApproveButton /></Can>
198
+ </SystemProvider>
199
+ ```
200
+
201
+ These values only decide what the UI shows. Convex re-checks every call. The
202
+ subscription is live, so the UI updates when a permission is revoked.
203
+
204
+ ## Errors
205
+
206
+ Public functions throw `ConvexError({ code, message, operationId, fields? })`
207
+ with `code` ∈ `UNAUTHENTICATED | FORBIDDEN | NOT_FOUND | VALIDATION | CONFLICT | UNAVAILABLE`.
208
+ `toSystemError(e)` normalizes the error on the client. The exact denial reason
209
+ is only logged and is available through `explainDecision` (diagnostics,
210
+ `permissions:decision:explain`). Records the actor may not see return
211
+ `NOT_FOUND`, the same as records that don't exist.
212
+
213
+ ## Development
214
+
215
+ ```bash
216
+ npm test # vitest: acceptance scenarios, Convex end-to-end (convex-test), units
217
+ npm run typecheck # TypeScript 7
218
+ npm run build # tsc → dist/
219
+ npm run check:pack # pack, install into a clean consumer, import + type-check every entry, browser/server separation
220
+ npm run lint # biome lint
221
+ ```
222
+
223
+ ## Releasing
224
+
225
+ Branch-based release cycle (same for every digimuza project). The version comes from the release branch name.
226
+
227
+ ```
228
+ feature/DIG-123-x ──PR──▶ main ──cut──▶ release/X.Y.Z ──PR (merge commit)──▶ production
229
+ (dev) npm X.Y.Z-rc.N @next npm X.Y.Z @latest
230
+ ```
231
+
232
+ | Branch | npm | Who consumes it |
233
+ | - | - | - |
234
+ | `main` | nothing | development |
235
+ | `release/X.Y.Z`, `hotfix/X.Y.Z` | `X.Y.Z-rc.N` under dist-tag `next`, one rc per push | staging: `npm install @digimuza/system-core@next` (or pin `X.Y.Z-rc.N`) |
236
+ | `production` | `X.Y.Z` under dist-tag `latest` | production tenant apps |
237
+
238
+ 1. **Cut**: `npm run release:cut -- 0.2.0` creates `release/0.2.0` from `origin/main`, bumps `package.json` and pushes.
239
+ After the cut only fixes go into the release branch.
240
+ 2. **Stage**: every push to `release/0.2.0` runs `.github/workflows/release.yml` → verify → publish
241
+ `0.2.0-rc.1`, `-rc.2`, … with tag `next`. Linear issues (`DIG-n` in commit messages) move to **In Staging**
242
+ and onto project milestone `v0.2.0`.
243
+ 3. **Release**: open a PR `release/0.2.0 → production` and merge it **with a merge commit** (not squash).
244
+ CI checks the source branch and version. The push to `production` publishes `0.2.0` as `latest`,
245
+ tags `v0.2.0`, creates a GitHub Release, moves the issues to **Done**, posts a Linear project update
246
+ and opens and auto-merges a PR `production → main` so fixes reach `main`.
247
+ 4. **Hotfix**: `hotfix/0.2.1` from `production`, bump `package.json`, push (publishes `0.2.1-rc.N`), then PR to `production`.
248
+
249
+ Guards: the release branch version must match `package.json`, a version already on npm is never republished,
250
+ and `production` refuses to publish `X.Y.Z` unless an `X.Y.Z-rc.N` was staged first. A manual run
251
+ (Actions → Release → Run workflow, `dry_run` on) does everything with `npm publish --dry-run` and skips tags,
252
+ releases and Linear.
253
+
254
+ Publishing uses npm trusted publishing (OIDC) bound to `digimuza/system-core` + `release.yml`, so no npm token is stored.
255
+ Linear updates need the `LINEAR_API_KEY` repo secret (sourced from Infisical); without it they are skipped.
package/README.md CHANGED
@@ -1,3 +1,165 @@
1
- # Temporary Holding Version
1
+ Vienai įmonei diegiama atskira Next.js ir Convex aplikacija. `@digimuza/system-core` yra bendras NPM paketas. Kliento aplikacija registruoja verslo modulius, o branduolys tvarko konfigūraciją, tapatybes, teises ir diagnostiką. `finance` ir `powerbi` yra modulio sutarties pavyzdžiai.
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # Moduliai ir jų paskirtis
4
+
5
+ `config` įkelia ir pagal Zod schemas validuoja serverio konfigūraciją. `auth` susieja patikimo tiekėjo tapatybę su lokaliu vartotoju. `users` saugo stabilų ID, tapatybės sąsają, patvirtinto el. pašto būseną ir paskyros būseną. Kliento papildomi įrašai siejami per `userId`. `profile` leidžia aktyviam vartotojui tvarkyti savo profilio pateikimo laukus. Tapatybės, el. pašto patvirtinimo, būsenos ir rolių keitimas turi atskirus procesus.
6
+
7
+ `roles` valdo roles, subroles, jų sudėtį ir priskyrimus. `permissions` registruoja kode aprašytus veiksmus ir priima prieigos sprendimus. `invites` valdo vienkartinius, atšaukiamus kvietimus su galiojimo terminu ir numatomomis rolėmis. `api-keys` išduoda, rotuoja ir atšaukia agentų raktus. Modulių registras saugo modulių tipą, verslo modulių būseną ir registracijos versiją.
8
+
9
+ `logging` registruoja struktūruotus įvykius. `tracing` sieja Next.js, Convex ir išorinių operacijų žingsnius pagal operacijos ID. `feature-flags` valdo funkcijų prieinamumą jau įjungtuose moduliuose. Funkcijos žyma negali suteikti teisės. Audito įrašai fiksuoja saugumui svarbių pakeitimų autorių, taikinį, laiką, rezultatą ir pakeistas sąsajas. Diagnostikoje maskuojamos paslaptys, sesijų duomenys ir raktai, taip pat ir `Super` rodinyje.
10
+
11
+ # Viešasis paketas ir jo naudotojai
12
+
13
+ Pirmoji versija platinama vienu versijuojamu NPM paketu su atskirais importo keliais. Kiekvienas klientas savo aplikacijoje fiksuoja paketo versiją ir turi atskirą Convex diegimą. Aplikacija pasirenka įtraukiamus verslo modulius, jų ekranus, prisijungimo ir kvietimų pristatymo tiekėjus. Paketas apibrėžia bendras serverio operacijas, duomenų schemas, TypeScript tipus ir sąsajas šioms integracijoms.
14
+
15
+ | Kas integruoja | Siūlomas importo kelias | Ką gauna |
16
+ | - | - | - |
17
+ | Serverio paleidimas | `@digimuza/system-core/config` | `SystemConfig.load()` ir sinchroninį `register(schema)` po įkėlimo |
18
+ | Modulio autorius | `@digimuza/system-core/modules` | `defineModule()`, manifesto tipus ir validaciją |
19
+ | Convex aplikacija | `@digimuza/system-core/convex` | Sistemos registraciją, užklausų ir mutacijų pagalbines funkcijas, teisių patikrą |
20
+ | Next.js serveris | `@digimuza/system-core/next` | Autentifikuotos sesijos perdavimą ir tipizuotą kreipimąsi į Convex |
21
+ | Next.js kliento komponentai | `@digimuza/system-core/react` | Dabartinio vartotojo, matomų modulių ir leidžiamų veiksmų duomenis kliento kuriamam UI |
22
+
23
+ Šie pavadinimai yra projektuojama v1 sutartis. Paleidimo konfigūracija, Infisical klientas ir paslaptys pasiekiami tik serverio importuose. Kliento komponentų importavimas neturi reikalauti serverio aplinkos kintamųjų.
24
+
25
+ # Funkcijų katalogas
26
+
27
+ | Modulis | V1 operacijos | Tikrinamas rezultatas |
28
+ | - | - | - |
29
+ | `config` | Įkelti vieną konfigūracijos versiją, validuoti kelių modulių schemas, pateikti nuasmenintą būseną | Lygiagretūs `load()` naudoja tą patį įkėlimą. `register()` iki įkėlimo grąžina aiškią klaidą. Būsena nerodo reikšmių. |
30
+ | `modules` | Registruoti manifestus, išvardyti įdiegtus modulius, gauti efektyvią būseną, įjungti ar išjungti verslo modulį | Pakartotinis registravimas išsaugo kliento pasirinkimą. Sisteminio modulio išjungimo užklausa atmetama. |
31
+ | `auth` | Pradėti ir užbaigti prisijungimą per pasirinktą tiekėją, nustatyti veikėją, atsijungti | Pasibaigusi sesija neleidžia atlikti apsaugoto veiksmo. Neatpažintai paskyrai reikalingas galiojantis kvietimas arba pradinis patvirtintas `Super` prisijungimas. |
32
+ | `users` | Peržiūrėti vartotoją, rasti pagal tapatybę, puslapiuoti sąrašą, sustabdyti ir aktyvuoti paskyrą | Pakartotinai gavus prisijungimo įvykį lieka vienas vartotojas. Aktyvavimas neatkuria atšauktų raktų. |
33
+ | `profile` | Skaityti ir redaguoti savo rodomą vardą, kalbą ir laiko juostą | Įrašomi tik leidžiami laukai. Kliento profilio plėtiniai turi atskirą schemą ir prieigos taisykles. |
34
+ | `invites` | Sukurti, pristatyti, pakartotinai išsiųsti, atšaukti, priimti, rodyti būseną | Pakartotinis siuntimas pakeičia ankstesnį žetoną. Nepavykus pristatyti galima kartoti nesukuriant naujos paskyros. |
35
+ | `permissions` | Registruoti katalogą, išvardyti teises pagal modulį, patikrinti veiksmą, paaiškinti sprendimą įgaliotam operatoriui | UI ir serveris naudoja tą patį sprendimo modelį. Serveris apsaugo veiksmą net tiesiogiai iškvietus Convex funkciją. |
36
+ | `roles` | Kurti, kopijuoti, redaguoti ir archyvuoti roles bei subroles, peržiūrėti ryšius, priskirti roles ir jas atšaukti | Prieš keitimą galima matyti paveiktas roles ir gavėjų skaičių. Archyvuotas objektas nebesuteikia teisių. |
37
+ | `api-keys` | Sukurti savininko raktą su rolėmis, išvardyti jo raktus, keisti roles, rotuoti ir atšaukti | Raktų sąraše matomas identifikavimo prefiksas, galiojimas ir būsena. Paslaptis parodoma vieną kartą. |
38
+ | `feature-flags` | Registruoti modulio žymas kode, skaityti efektyvią reikšmę, keisti instaliacijos reikšmę, grąžinti numatytąją | V1 žymos yra loginės ir galioja vienai instaliacijai. Nežinoma žyma nesuaktyvina funkcijos. Žymos reikšmė naudojama kartu su modulio ir teisės patikromis. |
39
+ | `logging` | Rašyti struktūruotus įvykius su lygiu, modulio ID, įvykio vardu ir koreliacijos ID | Vienos užklausos klaidą galima rasti pagal ID. Tokenai ir slapti laukai pašalinami prieš siunčiant į žurnalų saugyklą. |
40
+ | `tracing` | Pradėti operaciją, susieti jos žingsnius, perduoti kontekstą foninei užduočiai, užbaigti su rezultatu | Pagal vieną trace ID matomi Next.js, Convex ir integracijos žingsniai, jų trukmės ir klaidos vieta. |
41
+ | `audit` | Įrašyti prieigos bei administravimo pakeitimus, leisti įgaliotam asmeniui filtruoti pagal laiką, veikėją ir objektą | Agentui išsaugomi rakto ir savininko ID. Sėkmingo saugomo pakeitimo auditas įrašomas kartu su DB pakeitimu. |
42
+
43
+ # Naujo modulio sutartis
44
+
45
+ Modulio autorius pateikia manifestą ir registruoja jį aplikacijos sudėtyje. Identifikatorius nekinta tarp versijų. Kiekviena teisė ir pradinė subrolė turi identifikatorių, pavadinimą ir aprašą. Žemiau pateiktas sutrumpintas siūlomo API pavyzdys.
46
+
47
+ ```ts
48
+ import { defineModule } from "@digimuza/system-core/modules"
49
+
50
+ export const finance = defineModule({
51
+ id: "finance",
52
+ kind: "business",
53
+ description: "Sąskaitų peržiūra ir tvirtinimas",
54
+ permissions: [
55
+ { id: "finance:invoice:read", name: "Skaityti", description: "Peržiūrėti sąskaitą" },
56
+ { id: "finance:invoice:approve", name: "Tvirtinti", description: "Patvirtinti sąskaitą" },
57
+ ],
58
+ initialSubroles: [{
59
+ id: "finance:reader",
60
+ name: "Skaitytojas",
61
+ description: "Gali peržiūrėti sąskaitas",
62
+ permissions: ["finance:invoice:read"],
63
+ }],
64
+ })
65
+ ```
66
+
67
+ Kiekvieno modulio dokumentacijoje privalomi paskirtis, tipas, viešos operacijos, duomenų savininkas, konfigūracijos raktai, teisės, pradinės subrolės, žymos ir bent vienas sėkmės bei atsisakymo scenarijus. Programinė priklausomybė nuo kito modulio nesuteikia jo teisių. Išimtas iš aplikacijos ar nepažįstamas modulis tampa neprieinamas net turint ankstesnį DB priskyrimą.
68
+
69
+ # Administravimo ir integracijų paviršius
70
+
71
+ Kliento dashboardas gali pateikti šiuos rodinius: mano profilis ir raktai, vartotojai ir kvietimai, rolės bei subrolės, modulių katalogas, funkcijų žymos, auditas ir diagnostika. Sąrašai palaiko puslapiavimą. Rolės detalė rodo subroles, jų teises ir gavėjus pagal žiūrinčiojo įgaliojimus. Modulio kortelėje rodoma konfigūruota ir konkrečiam veikėjui efektyvi būsena, kad `Super` aiškiai matytų, ką gali naudoti klientas.
72
+
73
+ Autentifikacijos adapteris grąžina patikrintą tiekėjo tapatybę. Kvietimų siuntimo adapteris gauna gavėją, vienkartinę nuorodą ir pristatymo operacijos ID. Logų ir trace eksportuotojai gauna jau išvalytus įvykius. Adapterių klaidos turi aiškų rezultatą: privalomos tapatybės patikros gedimas blokuoja prieigą, laiško siuntimo gedimas palieka kartojamą pristatymą, diagnostikos eksportuotojo gedimas nekeičia jau įvykdytos verslo operacijos rezultato.
74
+
75
+ Viešos funkcijos pateikia stabilius klaidų kodus autentifikacijos, teisių, duomenų validacijos, konflikto ir laikino nepasiekiamumo atvejams. Klientui grąžinamas operacijos ID. Kai pats įrašo egzistavimas yra ribota informacija, svetimas ir neegzistuojantis įrašas išorei atrodo vienodai. Tiksli atmetimo priežastis pasiekiama tik įgaliotame diagnostikos rodinyje.
76
+
77
+ # Diegimo ir leidimų priėmimas
78
+
79
+ Coolify diegimas turi fiksuoti aplikacijos bei paketo versijas, validuoti konfigūraciją, vykdyti suderinamas Convex migracijas, registruoti manifestus ir patikrinti abiejų vykdymo aplinkų parengtį. Projekto identifikacijai numatomas diegimo parametras `INFISCAL_PROJECT_ID`. Pakartotinas migracijos ar registracijos paleidimas išsaugo rezultatą. Nepavykęs diegimas neaktyvuoja iš dalies užregistruoto katalogo. Grįžimas prie ankstesnės kodo versijos galimas tik jei ji suderinama su aktyvia schema ir teisių katalogu.
80
+
81
+ Prieš publikuojant versiją etaloninė Next.js + Convex aplikacija įdiegia supakuotą NPM artefaktą. Tikrinami deklaruoti importai ir tipai, serverio ir naršyklės paketų atskyrimas, įdiegimas į tuščią Convex, atnaujinimas iš ankstesnės palaikomos versijos ir to paties diegimo pakartojimas. Suderinamos Next.js, React, Convex ir Zod versijos nurodomos leidimo peer dependencies ir tikrinamos CI.
82
+
83
+ #
84
+
85
+ Priėmimo bandyme operatorius pakviečia darbuotoją, darbuotojas prisijungia ir susikuria ribotos rolės raktą. Įjungus bandomąjį verslo modulį agentas atlieka leidžiamą veiksmą. Tada pakeičiama rolė, atšaukiamas raktas ir tikrinama, ar jau suplanuotas darbas sustabdomas. Pagal tą pačią operaciją turi būti galima susieti audito įrašą ir techninę diagnostiką. Papildomai kartojamas nepavykęs kvietimo pristatymas, simuliuojamas išjungtas diagnostikos eksportuotojas ir patikrinama, kad jokioje naršyklės ar žurnalo išvestyje nėra paslapčių.
86
+
87
+ # Konfigūracija ir diegimas
88
+
89
+ `import SystemConfig from "@digimuza/system-core/config"` → `await SystemConfig.load()` → `const env = SystemConfig.register(schema)`. Coolify pateikia pradinius `INFISCAL_BASE_URL`, `INFISCAL_CLIENT_ID`, `INFISCAL_SECRET`, `INFISCAL_PATH` ir `INFISCAL_ENV`. Diegimo konfigūracija taip pat turi vienareikšmiškai identifikuoti Infisical projektą. Aplikacijos paslapčių šaltinis yra Infisical. Trūkstant privalomos reikšmės atitinkamas servisas nepasiekia parengties būsenos. Klaidoje pateikiamas rakto pavadinimas.
90
+
91
+ Next.js ir Convex vykdymo aplinkoms konfigūracija pateikiama atskirai. Convex užklausos ir mutacijos prieigos patikrą atlieka naudodamos lokaliai prieinamą aktyvios versijos konfigūraciją. Diegimas laikomas baigtu, kai ankstesnės versijos instancijos nebeaptarnauja užklausų. Naršyklė gauna tik aiškiai viešomis paskelbtas reikšmes.
92
+
93
+ # Peržiūra kaip rolė
94
+
95
+ Tikras `Super` (patvirtintas el. paštas `SUPER_USER_EMAILS` sąraše) gali laikinai peržiūrėti sistemą kaip vienos rolės turėtojas. Peržiūros metu kiekvienas prieigos sprendimas taikomas kaip tai rolei: verslo teisės, modulių būsena, tik `Super` leidžiami veiksmai, administravimo funkcijos, delegavimas ir kvietimai. Sesija rodo `isSuper: false` ir rolės teises. `Super` savo API raktams lieka tikruoju `Super`. Pradžia ir pabaiga įrašomos į auditą; archyvuota rolė peržiūrą užbaigia.
96
+
97
+ # Verslo moduliai pakete
98
+
99
+ `@digimuza/system-core/finance` yra pirmasis pakartotinai naudojamas verslo modulis: manifestas, `financeTables`, `defineFinance(system)` funkcijos ir teisės. Aplikacija tik įtraukia lenteles į schemą ir eksportuoja funkcijas; vartotojo sąsaja lieka aplikacijoje.
100
+
101
+ # Rolės ir modulio registracija
102
+
103
+ Vienintelė įmonės valdomų suteikimų grandinė yra gavėjas → rolė → subrolė → teisė. Gavėjas yra vartotojas arba agento API raktas. Kiekviename lygyje leidžiama turėti kelias sąsajas. Viena subrolė priklauso vienam moduliui. Rolė gali sujungti kelių modulių subroles. Tiesioginis subrolės ar teisės suteikimas gavėjui yra neleistina operacija.
104
+
105
+ Teisės raktas yra stabilus `modulis:objektas:veiksmas`. Kiekvienas modulis kode deklaruoja savo ID, tipą, paskirtį, teises ir pradinių subrolių šablonus. Diegimo registracija pagal stabilius ID sukuria trūkstamus įrašus. Esamų subrolių administratoriaus pakeitimai ir modulio būsena išsaugomi. Nauja teisė atsiranda kataloge. Jos įtraukimas į jau naudojamą subrolę turi būti sąmoningas DB pakeitimas. Pasenusi arba nežinoma teisė atmetama, identifikatoriai naujai prasmei nenaudojami. Nesuderinamos registracijos ir ID kolizijos sustabdo diegimą.
106
+
107
+ Sisteminiai moduliai visada įjungti. Verslo modulis pirmą kartą registruojamas išjungtas. Jį įjungti ar išjungti gali tik `Super`. Išjungus išlieka duomenys ir priskyrimai. `Admin` yra įprasta administravimo rolė su konkrečiomis teisėmis. `Super` nustatomas pagal aktyvios paskyros patikimo autentifikacijos tiekėjo patvirtintą el. paštą ir diegimo `SUPER_USER_EMAILS` sąrašą. Sąrašas taikomas po pakartotinio diegimo. DB rolės pavadinimas šio statuso nesuteikia.
108
+
109
+ # Prieigos sprendimas
110
+
111
+ Serveris nustato veikėją iš sesijos arba API rakto. Neaiški tapatybė, nežinoma teisė, neveikianti paskyra ar prieigos patikros klaida užklausą atmeta. Autentifikacijos pradžia ir kvietimo priėmimas turi atskirus aiškiai aprašytus įėjimo taškus. Verslo kode kviečiama `await requirePermission(ctx, "finance:invoice:approve")`. Konkretų objektą turinčioms teisėms serverio funkcija papildomai tikrina objekto ryšį ir leistiną būsenos perėjimą.
112
+
113
+ Žmogui teisė galioja, kai bent viena jo rolė ją suteikia ir modulis įjungtas. Aktyviam vartotojui automatiškai priskiriama apsaugota profilio rolė, suteikianti visas savo profilio teises. Profilio savininką serveris nustato iš sesijos. Aktyvus `Super` gali naudoti visus registruotus modulius ir visas teises, įskaitant diagnostiką. Verslo duomenų vientisumo taisyklės galioja visiems.
114
+
115
+ Agentui būtinas aktyvus raktas, aktyvus savininkas, įjungtas modulis, teisė per rakto roles ir ta pati šiuo metu galiojanti savininko teisė. Tikrinama teisės, o ne rolės ID sankirta. Kiekvieno rakto rolės nepriklausomos. `Super` statusas, išjungtų modulių išimtis ir asmeninės sesijos veiksmai raktui nepersiduoda. Pirmajai versijai raktų išdavimas, prieigos administravimas ir `Super` diagnostika skirti tik žmogaus sesijai.
116
+
117
+ # Delegavimas ir paskyrų gyvavimo ciklas
118
+
119
+ Rolės priskyrimui reikia ir `roles:assignment:create`, ir leidimo suteikti konkrečią tikslinę rolę. Delegavimo apimtis saugoma pagal stabilius rolių ID. Rolę galima suteikti tik jei visos jos suteikiamos teisės telpa į suteikiančiojo įgaliojimus. Vertinamos ir išjungtų modulių teisės, kad modulis vėliau neaktyvuotų neautorizuotų priskyrimų. Įprastas delegatas negali keisti savo įgaliojimų, saugomų rolių ar delegavimo ribų. Pradinę `Admin` rolę įmonei suteikia `Super`.
120
+
121
+ Subrolės redagavimas keičia visas ją naudojančias roles. Prieš pakeitimą serveris įvertina paveiktas roles ir gavėjus. Pakeitimas leidžiamas tik valdant visas paveiktas roles ir galint deleguoti pridedamas teises. Jei bendrą subrolę naudoja saugoma rolė, administratorius gali kurti atskirą kopiją savo valdomai rolei. Šios taisyklės galioja ir importui, masiniams veiksmams bei kvietimams.
122
+
123
+ Kvietimas susiejamas su el. paštu ir konkrečių rolių ID. Priėmimo metu tikrinamas patvirtintas gavėjo adresas, galiojimas, vienkartinis panaudojimas ir dabartinė kvietėjo teisė suteikti kiekvieną rolę. Pasikeitus įgaliojimams visas priėmimas atmetamas. Paskyra, priskyrimai ir kvietimo panaudojimas įrašomi atominiu veiksmu. Prisijungimo tapatybė susiejama pagal patikimo tiekėjo stabilų subjekto ID. Vien sutampančio el. pašto nepakanka sulieti paskyras.
124
+
125
+ API rakto paslaptis rodoma vieną kartą. Convex saugo rakto ID, kriptografinę patikros reikšmę, savininką, pavadinimą, galiojimą ir atšaukimo būseną. Panaikinus raktą jo atkurti negalima. Blokavus arba uždarius savininko paskyrą atšaukiami jo raktai. Savininkui praradus tik vieną teisę kitos rakto teisės išlieka. Savininkui vėl gavus teisę ji vėl veikia, jei raktas tebėra aktyvus ir jo rolė vis dar ją suteikia.
126
+
127
+ # Convex įgyvendinimo sutartis
128
+
129
+ Ryšiams numatytos atskiros indeksuotos lentelės: `userRoles`, `apiKeyRoles`, `roleSubroles`, `subrolePermissions`. Atskirai saugomi `users`, `roles`, `subroles`, `modules`, `apiKeys`, `invites`, delegavimo ribos ir audito įvykiai. Užtikrinamas porų unikalumas, pakartotinių operacijų saugumas ir puslapiavimas. Nėra produkto nustatyto rolių skaičiaus limito. Didžiausiai palaikomai instaliacijai prieš išleidimą atliekamas apkrovos bandymas. Jei prieigos sprendimo nepavyksta apskaičiuoti iki galo, jis atmetamas.
130
+
131
+ Next.js UI gali paslėpti veiksmą, tačiau visos viešos Convex funkcijos tikrina veikėją serveryje. Mutacija tikrina teises ir keičia duomenis vienoje transakcijoje. Užklausa skaito aktualius priskyrimus. Ilgalaikis JWT arba naršyklės kešas negali išsaugoti atšauktos teisės. Po atšaukimo patikra taikoma ir aktyvioms prenumeratoms. Jau vartotojui perduotų duomenų atšaukimas nesugrąžina.
132
+
133
+ Foninė užduotis saugo veikėjo ir rakto ID, vykdymo metu iš naujo tikrina būseną ir teises. Išorinis veiksmas vykdomas pagal identifikuojamą operaciją su apsauga nuo pakartojimo. Atšaukimas sustabdo dar nepradėtą darbą. Jei išorinė sistema jau priėmė komandą, rezultatas užfiksuojamas audite. Vidiniams sistemos priežiūros darbams naudojamas siauras atskiras įėjimo taškas be vartotojo `Super` privilegijų.
134
+
135
+ # Privalomi priėmimo scenarijai
136
+
137
+ 1. Gavėjas gauna tą pačią teisę per dvi roles. Pašalinus vieną kelią veiksmas leidžiamas, pašalinus paskutinį atmetamas.
138
+
139
+ 2. Pasikeitus subrolei pokytis pasiekia ir vartotoją, ir rakto roles nuo kitos patikros. Agentui savininko teisės išlieka viršutine riba.
140
+
141
+ 3. Raktui tiesiogiai siunčiamas teisės arba subrolės ID. Serveris atmeta visą priskyrimą.
142
+
143
+ 4. `Super` savininko raktas be rolių neturi verslo teisių. Su finansų role jis gali naudoti tik įjungtą `finance` modulį.
144
+
145
+ 5. Išjungus modulį blokuojami UI, tiesioginė API, agentas ir laukiančios užduotys. Žmogaus `Super` sesijai modulis prieinamas. Įjungus grįžta anksčiau suteiktos teisės.
146
+
147
+ 6. Pakeitęs profilio užklausos `userId`, vartotojas negali perskaityti ar redaguoti kito profilio. Asmeninis profilio veiksmas negali pakeisti `Super` identiteto.
148
+
149
+ 7. Kvietimas panaudojamas du kartus, pasibaigia arba kvietėjas netenka įgaliojimų. Papildomų priskyrimų nesukuriama.
150
+
151
+ 8. Raktas atšaukiamas tarp užduoties sukūrimo ir vykdymo. Užduotis nesukuria šalutinio poveikio.
152
+
153
+ 9. Delegatas mėgina suteikti `Admin` per kvietimą, pakeisti bendrą subrolę ar savo delegavimo ribas. Operacija atmetama.
154
+
155
+ 10. Du lygiagretūs pakeitimai mėgina apeiti delegavimo ribą. Galutinė būsena tenkina tas pačias taisykles kaip nuosekliai įvykdyti patikrinti pakeitimai.
156
+
157
+ 11. Pakartotinė modulio registracija išsaugo vartotojų pakeitimus ir įjungimo būseną. Nauja teisė savaime nepatenka į seną `Full` subrolę.
158
+
159
+ 12. Po diegimo iš `SUPER_USER_EMAILS` pašalinta aktyvi sesija praranda `Super`. Nepatvirtintas adresas arba DB rolė vardu `Super` privilegijos nesuteikia.
160
+
161
+ 13. Nežinoma teisė, ištrinta rolė, pasibaigęs raktas ar užblokuotas savininkas nesuteikia prieigos. Audite galima atskirti agentą nuo jo savininko.
162
+
163
+ # Techniniai šaltiniai
164
+
165
+ [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html) · [Convex transakcijos](https://docs.convex.dev/database/advanced/occ) · [Convex actions](https://docs.convex.dev/functions/actions)
@@ -0,0 +1,17 @@
1
+ declare const fail: () => never;
2
+ export declare const envSource: typeof fail;
3
+ export declare const staticSource: typeof fail;
4
+ export declare const infisicalSource: typeof fail;
5
+ export declare const createSystemConfig: typeof fail;
6
+ export declare const INFISICAL_BOOTSTRAP_KEYS: readonly string[];
7
+ export declare class ConfigError extends Error {
8
+ }
9
+ declare const SystemConfig: {
10
+ load: typeof fail;
11
+ register: typeof fail;
12
+ status: typeof fail;
13
+ reset: typeof fail;
14
+ };
15
+ export default SystemConfig;
16
+ export { SystemConfig };
17
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/config/browser.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,IAAI,QAAO,KAEhB,CAAA;AAED,eAAO,MAAM,SAAS,aAAO,CAAA;AAC7B,eAAO,MAAM,YAAY,aAAO,CAAA;AAChC,eAAO,MAAM,eAAe,aAAO,CAAA;AACnC,eAAO,MAAM,kBAAkB,aAAO,CAAA;AACtC,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAAO,CAAA;AAC7D,qBAAa,WAAY,SAAQ,KAAK;CAAG;AAEzC,QAAA,MAAM,YAAY;IAAK,IAAI;IAAQ,QAAQ;IAAQ,MAAM;IAAQ,KAAK;CAAQ,CAAA;eAC/D,YAAY;AAC3B,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,16 @@
1
+ // Browser stub for `@digimuza/system-core/config`. Configuration, the Infisical
2
+ // client and secrets are server-only; this file keeps them out of client bundles.
3
+ const fail = () => {
4
+ throw new Error("@digimuza/system-core/config is server-only and cannot be used in the browser");
5
+ };
6
+ export const envSource = fail;
7
+ export const staticSource = fail;
8
+ export const infisicalSource = fail;
9
+ export const createSystemConfig = fail;
10
+ export const INFISICAL_BOOTSTRAP_KEYS = [];
11
+ export class ConfigError extends Error {
12
+ }
13
+ const SystemConfig = { load: fail, register: fail, status: fail, reset: fail };
14
+ export default SystemConfig;
15
+ export { SystemConfig };
16
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/config/browser.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,kFAAkF;AAClF,MAAM,IAAI,GAAG,GAAU,EAAE;IACvB,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAA;AAClG,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAA;AAC7B,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAA;AAChC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAA;AACnC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAA;AACtC,MAAM,CAAC,MAAM,wBAAwB,GAAsB,EAAE,CAAA;AAC7D,MAAM,OAAO,WAAY,SAAQ,KAAK;CAAG;AAEzC,MAAM,YAAY,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;AAC9E,eAAe,YAAY,CAAA;AAC3B,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,71 @@
1
+ import type { z } from "zod";
2
+ import { SystemError } from "../core/errors.js";
3
+ export type ConfigValues = Readonly<Record<string, string>>;
4
+ /** A source of configuration values (env, Infisical, static for tests). */
5
+ export interface ConfigSource {
6
+ readonly name: string;
7
+ load(): Promise<Record<string, string>>;
8
+ }
9
+ export declare class ConfigError extends SystemError {
10
+ /** Only key names — never values. */
11
+ readonly keys: string[];
12
+ constructor(reason: string, keys: string[], message: string);
13
+ }
14
+ type Env = Record<string, string | undefined>;
15
+ /** Reads process environment variables (Coolify deployment parameters). */
16
+ export declare function envSource(env?: Env): ConfigSource;
17
+ export declare function staticSource(values: Record<string, string>, name?: string): ConfigSource;
18
+ /** Bootstrap parameters Coolify provides for Infisical. */
19
+ export declare const INFISICAL_BOOTSTRAP_KEYS: readonly ["INFISCAL_BASE_URL", "INFISCAL_CLIENT_ID", "INFISCAL_SECRET", "INFISCAL_PATH", "INFISCAL_ENV", "INFISCAL_PROJECT_ID"];
20
+ export interface InfisicalSourceOptions {
21
+ env?: Env;
22
+ fetch?: typeof fetch;
23
+ timeoutMs?: number;
24
+ }
25
+ /**
26
+ * Loads secrets from Infisical using Universal Auth. Bootstrap credentials come
27
+ * from the deployment environment; missing ones produce a ConfigError naming the keys.
28
+ */
29
+ export declare function infisicalSource(options?: InfisicalSourceOptions): ConfigSource;
30
+ export interface RegisteredSchema {
31
+ moduleId: string;
32
+ keys: string[];
33
+ }
34
+ /** De-identified status: names only, never values. */
35
+ export interface ConfigStatus {
36
+ state: "idle" | "loading" | "loaded" | "failed";
37
+ /** Incremented on each successful load. */
38
+ version: number;
39
+ loadedAt: number | null;
40
+ sources: string[];
41
+ keys: string[];
42
+ registered: RegisteredSchema[];
43
+ error?: {
44
+ reason: string;
45
+ keys: string[];
46
+ };
47
+ }
48
+ export interface SystemConfigOptions {
49
+ /** Default: env, then Infisical (Infisical wins on conflicts). */
50
+ sources?: readonly ConfigSource[];
51
+ }
52
+ export interface SystemConfigApi {
53
+ /** Loads one configuration version. Concurrent calls share the same load. */
54
+ load(): Promise<ConfigStatus>;
55
+ /**
56
+ * Synchronously validates and returns typed values for `schema`.
57
+ * Throws ConfigError before `load()` finished or when keys are missing/invalid.
58
+ */
59
+ register<S extends z.ZodType>(schema: S, options?: {
60
+ moduleId?: string;
61
+ }): z.infer<S>;
62
+ status(): ConfigStatus;
63
+ /** Testing only: forget the loaded version. */
64
+ reset(): void;
65
+ }
66
+ export declare function createSystemConfig(options?: SystemConfigOptions): SystemConfigApi;
67
+ /** Process-wide instance: `await SystemConfig.load(); const env = SystemConfig.register(schema)`. */
68
+ declare const SystemConfig: SystemConfigApi;
69
+ export default SystemConfig;
70
+ export { SystemConfig };
71
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAE3D,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACxC;AAED,qBAAa,WAAY,SAAQ,WAAW;IAC1C,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAA;IACvB,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAI1D;CACF;AAED,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAG7C,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,GAAE,GAAkB,GAAG,YAAY,CAS/D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,SAAW,GAAG,YAAY,CAE1F;AAED,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,YACnC,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,qBAAqB,CACb,CAAA;AAEV,MAAM,WAAW,sBAAsB;IACrC,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,YAAY,CAoClF;AAED,MAAM,WAAW,gBAAgB;IAAG,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE;AAEtE,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAA;IAC/C,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,UAAU,EAAE,gBAAgB,EAAE,CAAA;IAC9B,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAC3C;AAED,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,IAAI,IAAI,OAAO,CAAC,YAAY,CAAC,CAAA;IAC7B;;;OAGG;IACH,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACrF,MAAM,IAAI,YAAY,CAAA;IACtB,+CAA+C;IAC/C,KAAK,IAAI,IAAI,CAAA;CACd;AAOD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,eAAe,CAyErF;AAED,qGAAqG;AACrG,QAAA,MAAM,YAAY,EAAE,eAAsC,CAAA;eAC3C,YAAY;AAC3B,OAAO,EAAE,YAAY,EAAE,CAAA"}