@endora-commerce/mod-credentials 0.100.0

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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/admin/api/credentials-client.d.ts +11 -0
  4. package/dist/admin/api/credentials-client.d.ts.map +1 -0
  5. package/dist/admin/api/credentials-client.js +38 -0
  6. package/dist/admin/api/credentials-client.js.map +1 -0
  7. package/dist/admin/components/ConfigurationForm.d.ts +22 -0
  8. package/dist/admin/components/ConfigurationForm.d.ts.map +1 -0
  9. package/dist/admin/components/ConfigurationForm.js +89 -0
  10. package/dist/admin/components/ConfigurationForm.js.map +1 -0
  11. package/dist/admin/index.d.ts +47 -0
  12. package/dist/admin/index.d.ts.map +1 -0
  13. package/dist/admin/index.js +65 -0
  14. package/dist/admin/index.js.map +1 -0
  15. package/dist/admin/pages/CredentialsNewPage.d.ts +19 -0
  16. package/dist/admin/pages/CredentialsNewPage.d.ts.map +1 -0
  17. package/dist/admin/pages/CredentialsNewPage.js +22 -0
  18. package/dist/admin/pages/CredentialsNewPage.js.map +1 -0
  19. package/dist/admin/pages/CredentialsPage.d.ts +22 -0
  20. package/dist/admin/pages/CredentialsPage.d.ts.map +1 -0
  21. package/dist/admin/pages/CredentialsPage.js +154 -0
  22. package/dist/admin/pages/CredentialsPage.js.map +1 -0
  23. package/dist/admin-ui/ConfigurationPreviewModal.d.ts +16 -0
  24. package/dist/admin-ui/ConfigurationPreviewModal.d.ts.map +1 -0
  25. package/dist/admin-ui/ConfigurationPreviewModal.js +15 -0
  26. package/dist/admin-ui/ConfigurationPreviewModal.js.map +1 -0
  27. package/dist/admin-ui/index.d.ts +57 -0
  28. package/dist/admin-ui/index.d.ts.map +1 -0
  29. package/dist/admin-ui/index.js +56 -0
  30. package/dist/admin-ui/index.js.map +1 -0
  31. package/dist/backend/commands/create-configuration.command.d.ts +20 -0
  32. package/dist/backend/commands/create-configuration.command.d.ts.map +1 -0
  33. package/dist/backend/commands/create-configuration.command.js +70 -0
  34. package/dist/backend/commands/create-configuration.command.js.map +1 -0
  35. package/dist/backend/commands/delete-configuration.command.d.ts +16 -0
  36. package/dist/backend/commands/delete-configuration.command.d.ts.map +1 -0
  37. package/dist/backend/commands/delete-configuration.command.js +48 -0
  38. package/dist/backend/commands/delete-configuration.command.js.map +1 -0
  39. package/dist/backend/commands/update-configuration.command.d.ts +20 -0
  40. package/dist/backend/commands/update-configuration.command.d.ts.map +1 -0
  41. package/dist/backend/commands/update-configuration.command.js +94 -0
  42. package/dist/backend/commands/update-configuration.command.js.map +1 -0
  43. package/dist/backend/entities/credential-configuration.entity.d.ts +30 -0
  44. package/dist/backend/entities/credential-configuration.entity.d.ts.map +1 -0
  45. package/dist/backend/entities/credential-configuration.entity.js +84 -0
  46. package/dist/backend/entities/credential-configuration.entity.js.map +1 -0
  47. package/dist/backend/index.d.ts +73 -0
  48. package/dist/backend/index.d.ts.map +1 -0
  49. package/dist/backend/index.js +80 -0
  50. package/dist/backend/index.js.map +1 -0
  51. package/dist/backend/plugin.d.ts +43 -0
  52. package/dist/backend/plugin.d.ts.map +1 -0
  53. package/dist/backend/plugin.js +25 -0
  54. package/dist/backend/plugin.js.map +1 -0
  55. package/dist/backend/routes.admin.d.ts +27 -0
  56. package/dist/backend/routes.admin.d.ts.map +1 -0
  57. package/dist/backend/routes.admin.js +50 -0
  58. package/dist/backend/routes.admin.js.map +1 -0
  59. package/dist/backend/services/configuration-type-registry.d.ts +105 -0
  60. package/dist/backend/services/configuration-type-registry.d.ts.map +1 -0
  61. package/dist/backend/services/configuration-type-registry.js +111 -0
  62. package/dist/backend/services/configuration-type-registry.js.map +1 -0
  63. package/dist/backend/services/credentials.service.d.ts +63 -0
  64. package/dist/backend/services/credentials.service.d.ts.map +1 -0
  65. package/dist/backend/services/credentials.service.js +128 -0
  66. package/dist/backend/services/credentials.service.js.map +1 -0
  67. package/dist/backend/services/field-validator.d.ts +65 -0
  68. package/dist/backend/services/field-validator.d.ts.map +1 -0
  69. package/dist/backend/services/field-validator.js +165 -0
  70. package/dist/backend/services/field-validator.js.map +1 -0
  71. package/dist/backend/services/registry-singleton.d.ts +28 -0
  72. package/dist/backend/services/registry-singleton.d.ts.map +1 -0
  73. package/dist/backend/services/registry-singleton.js +29 -0
  74. package/dist/backend/services/registry-singleton.js.map +1 -0
  75. package/dist/backend/services/secret-value-codec.d.ts +55 -0
  76. package/dist/backend/services/secret-value-codec.d.ts.map +1 -0
  77. package/dist/backend/services/secret-value-codec.js +105 -0
  78. package/dist/backend/services/secret-value-codec.js.map +1 -0
  79. package/dist/backend/types/email-adapter.type.d.ts +10 -0
  80. package/dist/backend/types/email-adapter.type.d.ts.map +1 -0
  81. package/dist/backend/types/email-adapter.type.js +49 -0
  82. package/dist/backend/types/email-adapter.type.js.map +1 -0
  83. package/dist/backend/types/llm.type.d.ts +3 -0
  84. package/dist/backend/types/llm.type.d.ts.map +1 -0
  85. package/dist/backend/types/llm.type.js +35 -0
  86. package/dist/backend/types/llm.type.js.map +1 -0
  87. package/dist/manifest.d.ts +176 -0
  88. package/dist/manifest.d.ts.map +1 -0
  89. package/dist/manifest.js +167 -0
  90. package/dist/manifest.js.map +1 -0
  91. package/dist/migrations/20260721T011509_credentials_init.d.ts +17 -0
  92. package/dist/migrations/20260721T011509_credentials_init.d.ts.map +1 -0
  93. package/dist/migrations/20260721T011509_credentials_init.js +36 -0
  94. package/dist/migrations/20260721T011509_credentials_init.js.map +1 -0
  95. package/dist/migrations/index.d.ts +27 -0
  96. package/dist/migrations/index.d.ts.map +1 -0
  97. package/dist/migrations/index.js +29 -0
  98. package/dist/migrations/index.js.map +1 -0
  99. package/docs/credentials.md +202 -0
  100. package/i18n/en.json +47 -0
  101. package/i18n/pl.json +47 -0
  102. package/package.json +98 -0
  103. package/tailwind.css +16 -0
@@ -0,0 +1,202 @@
1
+ ---
2
+ title: Credentials
3
+ description: Reusable typed credential configurations (LLM, email adapter) referenced from settings
4
+ ---
5
+
6
+ # Credentials
7
+
8
+ The `credentials` module lets an operator define a **reusable
9
+ credential configuration once** and reference it from many places. Instead of
10
+ re-typing an API key into the AI-assistant settings, the search-embedder
11
+ settings, and the newsletter settings, you create a single *Primary LLM*
12
+ configuration and point each setting at it. Change the key once — every
13
+ consumer picks up the new value with no further edits.
14
+
15
+ Secret fields (API keys, passwords) are **encrypted at rest**, **write-only at
16
+ the boundary** (never returned in plaintext), **masked on every read**, and
17
+ **redacted in the audit log**. Every create / edit / delete is audited through
18
+ the Command Bus.
19
+
20
+ ## For Product Owners & operators
21
+
22
+ ### What a credential configuration is
23
+
24
+ A configuration is a named, coded instance of a **configuration type**. Two
25
+ types ship out of the box:
26
+
27
+ - **LLM** — providers **GPT** (OpenAI), **Gemini** (Google), **Claude**
28
+ (Anthropic), and **DeepSeek**. Fields: **API Key** (secret, required),
29
+ **Model** (required), **Base URL** (optional).
30
+ - **Email adapter** — providers **SMTP**, **Amazon SES**, and **SendGrid**.
31
+ Each provider has its own field set with exactly one secret field
32
+ (SMTP `password`, SES `secretAccessKey`, SendGrid `apiKey`).
33
+
34
+ The type and provider you pick decide which fields the form shows.
35
+
36
+ ### Creating a configuration
37
+
38
+ 1. Open **Credentials** in the admin sidebar (visible with the
39
+ `credentials:read` permission).
40
+ 2. Click **New configuration**.
41
+ 3. Pick a **Type** (e.g. *LLM*) and a **Provider** (e.g. *Claude*). The form
42
+ redraws to that provider's fields.
43
+ 4. Fill in a **Name** (e.g. `Primary LLM`) and a **Code** (a stable identifier
44
+ like `primary-llm` — this is what settings reference), then the fields
45
+ (API Key, Model, …).
46
+ 5. **Save.** The configuration appears in the list; every secret field shows as
47
+ **set** — never the value.
48
+
49
+ Editing works the same way. On edit, the **type and provider are locked** (they
50
+ cannot change — create a new configuration instead). Leaving a secret field
51
+ **blank keeps the stored secret**; typing a new value replaces it.
52
+
53
+ ### Using a configuration from a setting
54
+
55
+ Some settings are of the **"credential reference"** kind, constrained to one
56
+ configuration type. Such a setting renders as a **picker of matching
57
+ configurations** plus a **Preview** button:
58
+
59
+ 1. Open **Settings** and find the credential-reference setting (e.g. an AI
60
+ assistant's *LLM credentials*).
61
+ 2. Select your configuration from the dropdown — only configurations of the
62
+ right type are offered.
63
+ 3. Click **Preview** to see the referenced configuration read-only (secrets
64
+ masked) without leaving the page.
65
+
66
+ Assign the **same** configuration to several settings to reuse it. Update the
67
+ configuration's key once and all of them resolve the new value.
68
+
69
+ ### Safety
70
+
71
+ - **Delete is blocked while referenced.** Trying to delete a configuration that
72
+ a setting still points at fails with a clear message listing exactly which
73
+ settings to detach first.
74
+ - **Orphaned configurations** (whose type is no longer available) are shown
75
+ read-only ("unavailable") and never crash the screen.
76
+ - **No plaintext ever leaves the server** — list, detail, and preview all mask
77
+ secrets; only the server-side consumer path decrypts, in memory, for use.
78
+
79
+ ## For developers
80
+
81
+ ### Model
82
+
83
+ A configuration type is a **code-registered descriptor** (not database rows):
84
+
85
+ ```ts
86
+ interface ConfigurationTypeDescriptor {
87
+ code: string; // 'llm' | 'email_adapter' | …
88
+ label: string;
89
+ ownerModule: string;
90
+ providers: ProviderVariant[];
91
+ }
92
+ interface ProviderVariant { code: string; label: string; fields: FieldDefinition[]; }
93
+ interface FieldDefinition {
94
+ key: string;
95
+ label: string;
96
+ kind: 'string' | 'number' | 'boolean' | 'select';
97
+ required: boolean;
98
+ secret: boolean; // secret ⇒ encrypted at rest, masked on read
99
+ options?: { value: string; label: string }[];
100
+ placeholder?: string;
101
+ }
102
+ ```
103
+
104
+ A saved configuration stores `typeCode` + `providerCode` + a `values` bag
105
+ (secret fields hold AES-256-GCM envelopes, non-secret fields hold plain
106
+ scalars) in the `credential_configurations` table (`@GlobalEntity`,
107
+ platform-global).
108
+
109
+ The credentials **core is type-agnostic**: it reads
110
+ a descriptor only to render fields, derive the write-validator, and learn which
111
+ fields are secret. It never branches on a specific `typeCode` / `providerCode` —
112
+ provider meaning lives with the consumer.
113
+
114
+ ### Registering a new type (the extension point)
115
+
116
+ Register from any module's install path via the process-wide singleton — **no
117
+ change to the credentials core** is required (overlay-safe):
118
+
119
+ ```ts
120
+ import { configurationTypeRegistry } from '@core/modules/credentials/services/registry-singleton.js';
121
+
122
+ configurationTypeRegistry.register({
123
+ code: 'sms_gateway',
124
+ label: 'SMS Gateway',
125
+ ownerModule: 'my_module',
126
+ providers: [
127
+ {
128
+ code: 'twilio',
129
+ label: 'Twilio',
130
+ fields: [
131
+ { key: 'accountSid', label: 'Account SID', kind: 'string', required: true, secret: false },
132
+ { key: 'authToken', label: 'Auth Token', kind: 'string', required: true, secret: true },
133
+ ],
134
+ },
135
+ ],
136
+ });
137
+ ```
138
+
139
+ The type immediately appears in the admin type picker (`GET
140
+ /api/v1/admin/credentials/types`) and is creatable.
141
+
142
+ ### The `credential_ref` settings value type
143
+
144
+ To let a setting reference a configuration, declare it in a module's settings
145
+ manifest:
146
+
147
+ ```ts
148
+ {
149
+ code: 'prompt_actions.llm_credentials',
150
+ name: 'LLM credentials',
151
+ valueType: 'credential_ref',
152
+ configurationType: 'llm', // only configurations of this type are selectable
153
+ defaultValue: '', // empty ⇒ not configured
154
+ }
155
+ ```
156
+
157
+ `configurationType` is **required** for `credential_ref` settings and forbidden
158
+ otherwise. The stored value is simply the configuration **code**.
159
+
160
+ ### Resolving a reference (consumer side)
161
+
162
+ Resolution is a **server-side service call** (never an HTTP response) — the one
163
+ path that returns decrypted secrets, for in-memory use only:
164
+
165
+ ```ts
166
+ const code = await settings.get('prompt_actions.llm_credentials'); // → 'primary-llm'
167
+ const cred = code ? await credentials.resolve(code) : { status: 'not_configured' };
168
+ if (cred.status !== 'ok') throw new Error('LLM not configured'); // fail closed
169
+ callProvider(cred.providerCode, cred.values.apiKey, cred.values.model);
170
+ ```
171
+
172
+ `resolve` returns a discriminated result:
173
+
174
+ - `{ status: 'ok', typeCode, providerCode, values }` — secrets decrypted;
175
+ - `{ status: 'not_configured' }` — the reference is unset/empty;
176
+ - `{ status: 'unavailable', reason: 'missing' | 'inert_type' }` — a deleted
177
+ code or an unregistered type.
178
+
179
+ A consumer never receives a foreign configuration and never a plaintext secret
180
+ over the wire.
181
+
182
+ ### Delete integrity
183
+
184
+ `CredentialsService.delete` first calls
185
+ `SettingsService.listReferencesToConfiguration(code)` (the only channel by which
186
+ credentials reaches settings). A non-empty result blocks the
187
+ delete with `409 CREDENTIAL_IN_USE`, carrying `{ referencedBy: [{ settingCode,
188
+ salesChannelCode? }] }`.
189
+
190
+ ### Secrets & configuration
191
+
192
+ Secret fields reuse the platform's AES-256-GCM envelope codec keyed by the
193
+ existing **`SETTINGS_SECRET_ENCRYPTION_KEY`** env var — no new secret to
194
+ provision. Writing a secret without the key fails closed
195
+ (`SETTING_SECRET_KEY_MISSING`); boot warns if the key is unset.
196
+
197
+ ### Permissions
198
+
199
+ - `credentials:read` — view configurations and the type catalogue (secrets
200
+ masked).
201
+ - `credentials:write` — create / edit / delete configurations, including
202
+ writing secret fields.
package/i18n/en.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "actions.openCredentials.label": "Credentials",
3
+ "actions.openCredentials.description": "Manage reusable credential configurations referenced by settings",
4
+ "actions.newCredential.label": "New credential configuration",
5
+ "actions.newCredential.description": "Create a credential configuration for an LLM, email adapter, or other provider",
6
+ "page.title": "Credentials",
7
+ "page.subtitle": "Reusable credential configurations referenced by settings.",
8
+ "page.new": "New configuration",
9
+ "page.empty": "No credential configurations yet.",
10
+ "page.edit": "Edit configuration",
11
+ "page.deleteConfirm": "Delete this configuration? This cannot be undone.",
12
+ "table.name": "Name",
13
+ "table.code": "Code",
14
+ "table.type": "Type",
15
+ "table.provider": "Provider",
16
+ "table.actions": "Actions",
17
+ "action.edit": "Edit",
18
+ "action.delete": "Delete",
19
+ "action.preview": "Preview",
20
+ "action.save": "Save",
21
+ "action.cancel": "Cancel",
22
+ "form.name": "Name",
23
+ "form.code": "Code",
24
+ "form.type": "Type",
25
+ "form.provider": "Provider",
26
+ "form.secretSet": "Saved — leave blank to keep",
27
+ "form.secretUnset": "Enter a value",
28
+ "form.inert": "Unavailable — configuration type is no longer registered",
29
+ "preview.title": "Configuration preview",
30
+ "preview.secret": "Set (hidden)",
31
+ "preview.notSet": "Not set",
32
+ "error.generic": "Something went wrong.",
33
+ "error.notFound": "Configuration not found.",
34
+ "error.codeTaken": "That code is already in use.",
35
+ "error.typeUnknown": "Unknown configuration type or provider.",
36
+ "error.validationFailed": "Some fields are invalid.",
37
+ "error.inUse": "Configuration is referenced by one or more settings.",
38
+ "error.inUseWith": "Cannot delete — referenced by: {settings}. Detach it from those settings first.",
39
+ "error.typeImmutable": "The type and provider cannot be changed after creation.",
40
+ "errors.CREDENTIAL_NOT_FOUND": "Configuration not found.",
41
+ "errors.CREDENTIAL_CODE_TAKEN": "That code is already in use.",
42
+ "errors.CREDENTIAL_TYPE_UNKNOWN": "Unknown configuration type or provider.",
43
+ "errors.CREDENTIAL_VALIDATION_FAILED": "Some fields are invalid.",
44
+ "errors.CREDENTIAL_IN_USE": "Configuration is referenced by one or more settings.",
45
+ "errors.CREDENTIAL_TYPE_IMMUTABLE": "The type and provider cannot be changed after creation.",
46
+ "nav.credentials.label": "Credentials"
47
+ }
package/i18n/pl.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "actions.openCredentials.label": "Poświadczenia",
3
+ "actions.openCredentials.description": "Zarządzaj konfiguracjami poświadczeń wskazywanymi przez ustawienia",
4
+ "actions.newCredential.label": "Nowa konfiguracja poświadczeń",
5
+ "actions.newCredential.description": "Utwórz konfigurację poświadczeń dla LLM, adaptera e-mail lub innego dostawcy",
6
+ "page.title": "Poświadczenia",
7
+ "page.subtitle": "Wielokrotnego użytku konfiguracje poświadczeń wskazywane przez ustawienia.",
8
+ "page.new": "Nowa konfiguracja",
9
+ "page.empty": "Brak konfiguracji poświadczeń.",
10
+ "page.edit": "Edytuj konfigurację",
11
+ "page.deleteConfirm": "Usunąć tę konfigurację? Tej operacji nie można cofnąć.",
12
+ "table.name": "Nazwa",
13
+ "table.code": "Kod",
14
+ "table.type": "Typ",
15
+ "table.provider": "Dostawca",
16
+ "table.actions": "Akcje",
17
+ "action.edit": "Edytuj",
18
+ "action.delete": "Usuń",
19
+ "action.preview": "Podgląd",
20
+ "action.save": "Zapisz",
21
+ "action.cancel": "Anuluj",
22
+ "form.name": "Nazwa",
23
+ "form.code": "Kod",
24
+ "form.type": "Typ",
25
+ "form.provider": "Dostawca",
26
+ "form.secretSet": "Zapisano — pozostaw puste, aby zachować",
27
+ "form.secretUnset": "Wprowadź wartość",
28
+ "form.inert": "Niedostępne — typ konfiguracji nie jest już zarejestrowany",
29
+ "preview.title": "Podgląd konfiguracji",
30
+ "preview.secret": "Ustawione (ukryte)",
31
+ "preview.notSet": "Nie ustawiono",
32
+ "error.generic": "Coś poszło nie tak.",
33
+ "error.notFound": "Nie znaleziono konfiguracji.",
34
+ "error.codeTaken": "Ten kod jest już używany.",
35
+ "error.typeUnknown": "Nieznany typ konfiguracji lub dostawca.",
36
+ "error.validationFailed": "Niektóre pola są nieprawidłowe.",
37
+ "error.inUse": "Konfiguracja jest wskazywana przez co najmniej jedno ustawienie.",
38
+ "error.inUseWith": "Nie można usunąć — wskazywana przez: {settings}. Najpierw odłącz ją od tych ustawień.",
39
+ "error.typeImmutable": "Nie można zmienić typu i dostawcy po utworzeniu.",
40
+ "errors.CREDENTIAL_NOT_FOUND": "Nie znaleziono konfiguracji.",
41
+ "errors.CREDENTIAL_CODE_TAKEN": "Ten kod jest już używany.",
42
+ "errors.CREDENTIAL_TYPE_UNKNOWN": "Nieznany typ konfiguracji lub dostawca.",
43
+ "errors.CREDENTIAL_VALIDATION_FAILED": "Niektóre pola są nieprawidłowe.",
44
+ "errors.CREDENTIAL_IN_USE": "Konfiguracja jest wskazywana przez co najmniej jedno ustawienie.",
45
+ "errors.CREDENTIAL_TYPE_IMMUTABLE": "Nie można zmienić typu i dostawcy po utworzeniu.",
46
+ "nav.credentials.label": "Poświadczenia"
47
+ }
package/package.json ADDED
@@ -0,0 +1,98 @@
1
+ {
2
+ "name": "@endora-commerce/mod-credentials",
3
+ "version": "0.100.0",
4
+ "type": "module",
5
+ "sideEffects": false,
6
+ "description": "Reusable credential configurations (LLM, email adapter, …) referenced by settings and resolved by consumers; secrets encrypted at rest and write-only at the boundary.",
7
+ "license": "MIT",
8
+ "endora": {
9
+ "type": "module",
10
+ "id": "credentials"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/endora-commerce/endora-commerce.git",
15
+ "directory": "packages/modules/credentials"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/manifest.d.ts",
23
+ "default": "./dist/manifest.js"
24
+ },
25
+ "./backend": {
26
+ "types": "./dist/backend/index.d.ts",
27
+ "default": "./dist/backend/index.js"
28
+ },
29
+ "./migrations": {
30
+ "types": "./dist/migrations/index.d.ts",
31
+ "default": "./dist/migrations/index.js"
32
+ },
33
+ "./admin": {
34
+ "types": "./dist/admin/index.d.ts",
35
+ "default": "./dist/admin/index.js"
36
+ },
37
+ "./admin-ui": {
38
+ "types": "./dist/admin-ui/index.d.ts",
39
+ "default": "./dist/admin-ui/index.js"
40
+ },
41
+ "./tailwind.css": "./tailwind.css",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "i18n",
47
+ "docs",
48
+ "tailwind.css"
49
+ ],
50
+ "engines": {
51
+ "node": ">=22.18.0"
52
+ },
53
+ "peerDependencies": {
54
+ "@mikro-orm/core": "^6",
55
+ "@mikro-orm/migrations": "^6",
56
+ "@mikro-orm/postgresql": "^6",
57
+ "fastify": "^5",
58
+ "react": "^19",
59
+ "react-router-dom": "^7",
60
+ "zod": "^4",
61
+ "@endora-commerce/admin-kit": "0.100.0",
62
+ "@endora-commerce/contracts": "0.100.0",
63
+ "@endora-commerce/platform": "0.100.0"
64
+ },
65
+ "peerDependenciesMeta": {
66
+ "@endora-commerce/admin-kit": {
67
+ "optional": true
68
+ },
69
+ "react": {
70
+ "optional": true
71
+ },
72
+ "react-router-dom": {
73
+ "optional": true
74
+ }
75
+ },
76
+ "devDependencies": {
77
+ "@mikro-orm/core": "^6.6.13",
78
+ "@mikro-orm/migrations": "^6.6.13",
79
+ "@mikro-orm/postgresql": "^6.6.13",
80
+ "@types/node": "^22.9.0",
81
+ "@types/react": "^19.2.14",
82
+ "fastify": "^5.12.5",
83
+ "react": "^19.2.5",
84
+ "react-router-dom": "^7.18.2",
85
+ "typescript": "^5.9.3",
86
+ "vitest": "^4.1.11",
87
+ "zod": "^4.2.0",
88
+ "@endora-commerce/admin-kit": "0.100.0",
89
+ "@endora-commerce/contracts": "0.100.0",
90
+ "@endora-commerce/platform": "0.100.0"
91
+ },
92
+ "scripts": {
93
+ "build": "tsc -p tsconfig.build.json && tsc -p tsconfig.ui.json",
94
+ "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.ui.json --noEmit",
95
+ "lint": "eslint src",
96
+ "test": "vitest run"
97
+ }
98
+ }
package/tailwind.css ADDED
@@ -0,0 +1,16 @@
1
+ /* @endora-commerce/mod-credentials — AUTO-GENERATED by `pnpm --filter backend run manifests:generate`.
2
+ *
3
+ * The `@source` directives this package asks its host to scan
4
+ * (`specs/110-instance-repository/contracts/admin-stylesheet-composition.md` R1).
5
+ * They resolve relative to **this file**, so they hold wherever the package is
6
+ * installed — a workspace link here, `node_modules` in a client's instance.
7
+ *
8
+ * The `dist` line is what a published tarball ships and is what an instance
9
+ * scans; the `src` line is inert there and is what keeps `pnpm --filter admin
10
+ * run dev` reading source in this repository. Do not edit: run
11
+ * `pnpm --filter backend run manifests:generate`.
12
+ */
13
+ @source "./dist/admin";
14
+ @source "./src/admin";
15
+ @source "./dist/admin-ui";
16
+ @source "./src/admin-ui";