@flowdular/sdk 0.3.1 → 0.3.2
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/.ai/platform-capabilities.md +2 -0
- package/.ai/references/catalog/migrations/0005_catalog_list_indexes.down.sql +3 -0
- package/.ai/references/catalog/migrations/0005_catalog_list_indexes.up.sql +11 -0
- package/.ai/references/catalog/module.json +11 -1
- package/.ai/references/catalog/package.json +2 -2
- package/.ai/references/catalog/spec/module.yaml +25 -4
- package/.ai/references/catalog/src/agent/tools.ts +19 -10
- package/.ai/references/catalog/src/api/endpoints.ts +150 -10
- package/.ai/references/catalog/src/api/list-cursor.ts +83 -0
- package/.ai/references/catalog/src/client/CatalogView.tsrx +505 -159
- package/.ai/references/catalog/src/client/api.ts +124 -36
- package/.ai/references/catalog/src/client/contribution.tsrx +5 -0
- package/.ai/references/catalog/src/client/state.ts +169 -3
- package/.ai/references/catalog/src/domain/lists.ts +7 -0
- package/.ai/references/catalog/src/domain/types.ts +20 -0
- package/.ai/references/catalog/src/platform.ts +20 -0
- package/.ai/references/catalog/src/services/catalog-service.ts +143 -8
- package/.ai/references/catalog/src/services/database-repository.ts +104 -17
- package/.ai/references/catalog/src/services/item-export.ts +81 -0
- package/.ai/references/catalog/src/services/migration.ts +27 -1
- package/.ai/references/catalog/src/services/repository.ts +31 -2
- package/.ai/references/catalog/tests/agent-tools.test.ts +6 -5
- package/.ai/references/catalog/tests/client-state.test.ts +124 -0
- package/.ai/references/catalog/tests/endpoints.test.ts +269 -0
- package/.ai/references/catalog/tests/export.test.ts +134 -0
- package/.ai/references/catalog/tests/idempotency.test.ts +15 -14
- package/.ai/references/catalog/tests/list.test.ts +217 -0
- package/.ai/references/catalog/tests/migrations.test.ts +58 -2
- package/.ai/references/catalog/tests/module.test.ts +2 -1
- package/.ai/references/catalog/tests/support/database.ts +14 -0
- package/.ai/references/catalog/translations/en.json +35 -4
- package/.ai/references/catalog/translations/pl.json +35 -4
- package/.ai/references/catalog.provenance.json +34 -26
- package/README.md +1 -1
- package/assets/flowdular-banner.webp +0 -0
- package/modules/access/module.json +1 -1
- package/modules/access/spec/module.yaml +1 -1
- package/modules/agents/module.json +1 -1
- package/modules/agents/spec/module.yaml +1 -1
- package/modules/approvals/module.json +1 -1
- package/modules/approvals/spec/module.yaml +1 -1
- package/modules/audit/module.json +1 -1
- package/modules/audit/spec/module.yaml +1 -1
- package/modules/auth/module.json +2 -2
- package/modules/auth/package.json +1 -1
- package/modules/auth/spec/module.yaml +2 -2
- package/modules/auth/src/middleware/authentication.ts +5 -1
- package/modules/auth/src/services/auth-service.ts +26 -0
- package/modules/auth/src/services/database-repository.ts +9 -0
- package/modules/auth/src/services/repository.ts +2 -0
- package/modules/automations/module.json +1 -1
- package/modules/automations/spec/module.yaml +1 -1
- package/modules/connectors/module.json +1 -1
- package/modules/connectors/spec/module.yaml +1 -1
- package/modules/directory/module.json +1 -1
- package/modules/directory/spec/module.yaml +1 -1
- package/modules/documents/module.json +1 -1
- package/modules/documents/spec/module.yaml +1 -1
- package/modules/exports/module.json +1 -1
- package/modules/exports/spec/module.yaml +1 -1
- package/modules/import/module.json +1 -1
- package/modules/import/spec/module.yaml +1 -1
- package/modules/metering/module.json +1 -1
- package/modules/metering/spec/module.yaml +1 -1
- package/modules/notifications/module.json +1 -1
- package/modules/notifications/spec/module.yaml +1 -1
- package/modules/reports/module.json +1 -1
- package/modules/reports/spec/module.yaml +1 -1
- package/modules/sandbox/module.json +1 -1
- package/modules/sandbox/spec/module.yaml +1 -1
- package/modules/search/module.json +1 -1
- package/modules/search/spec/module.yaml +1 -1
- package/modules/system/migrations/0001_system_module_activations.down.sql +2 -0
- package/modules/system/migrations/0001_system_module_activations.up.sql +17 -0
- package/modules/system/module.json +3 -2
- package/modules/system/package.json +2 -2
- package/modules/system/spec/module.yaml +98 -1
- package/modules/system/src/client/ModulesView.tsrx +101 -8
- package/modules/system/src/client/api.ts +52 -11
- package/modules/system/src/client/module-columns.tsrx +32 -6
- package/modules/system/src/client/state.ts +26 -0
- package/modules/system/src/domain/modules.ts +93 -0
- package/modules/system/src/index.ts +13 -0
- package/modules/system/src/platform.ts +41 -1
- package/modules/system/src/server/capability.ts +6 -0
- package/modules/system/src/server/endpoints.ts +125 -5
- package/modules/system/src/server/index.ts +26 -0
- package/modules/system/src/server/module-catalog.ts +19 -0
- package/modules/system/src/server/runtime.ts +102 -0
- package/modules/system/src/services/database-repository.ts +91 -0
- package/modules/system/src/services/migration.ts +39 -0
- package/modules/system/src/services/module-activation-service.ts +245 -0
- package/modules/system/src/services/repository.ts +17 -0
- package/modules/system/translations/en.json +17 -1
- package/modules/system/translations/pl.json +17 -1
- package/modules/users/module.json +2 -2
- package/modules/users/package.json +1 -1
- package/modules/users/spec/module.yaml +6 -9
- package/modules/users/src/client/UsersView.tsrx +27 -13
- package/modules/users/src/client/member-columns.tsrx +13 -4
- package/modules/users/src/client/state.ts +16 -0
- package/modules/users/src/services/users-service.ts +3 -0
- package/modules/users/translations/en.json +2 -1
- package/modules/users/translations/pl.json +2 -1
- package/modules/workflows/module.json +2 -2
- package/modules/workflows/package.json +1 -1
- package/modules/workflows/spec/module.yaml +2 -2
- package/modules/workflows/src/services/database-repository.ts +93 -53
- package/package.json +1 -1
- package/packages/client/package.json +1 -0
- package/packages/client/src/ApplicationShell.tsrx +46 -5
- package/packages/client/src/index.ts +5 -0
- package/packages/client/src/shell/modules.ts +49 -0
- package/packages/client/src/shell/types.ts +3 -0
- package/packages/contracts/src/index.ts +11 -1
- package/packages/server/src/endpoint.ts +17 -1
- package/packages/server/src/index.ts +10 -0
- package/packages/server/src/module-activation.ts +69 -0
- package/assets/flowdular-banner.png +0 -0
|
@@ -87,6 +87,7 @@ describe('catalog migrations', () => {
|
|
|
87
87
|
it('declares forced PostgreSQL row security for every tenant table', () => {
|
|
88
88
|
for (const migration of databaseMigrations) {
|
|
89
89
|
const sql = migration.sql.postgresql ?? '';
|
|
90
|
+
if (!sql.includes('CREATE TABLE')) continue;
|
|
90
91
|
expect(sql).toContain('ENABLE ROW LEVEL SECURITY');
|
|
91
92
|
expect(sql).toContain('FORCE ROW LEVEL SECURITY');
|
|
92
93
|
expect(sql).toContain("current_setting('coreloom.tenant_id', true)");
|
|
@@ -110,9 +111,9 @@ describe('catalog migrations', () => {
|
|
|
110
111
|
transaction.execute({
|
|
111
112
|
text: `INSERT INTO catalog_items
|
|
112
113
|
(id, tenant_id, sku, sku_normalized, name, kind, unit,
|
|
113
|
-
base_price_minor, currency, status, created_at)
|
|
114
|
+
base_price_minor, currency, status, created_at, updated_at)
|
|
114
115
|
VALUES ('item-1', 'tenant-a', 'SKU-1', 'sku-1', 'Bolt', 'product',
|
|
115
|
-
'pcs', 500, 'EUR', 'active', 1)`,
|
|
116
|
+
'pcs', 500, 'EUR', 'active', 1, 1)`,
|
|
116
117
|
}),
|
|
117
118
|
{ tenantId: 'tenant-a', access: 'write' },
|
|
118
119
|
);
|
|
@@ -139,6 +140,61 @@ describe('catalog migrations', () => {
|
|
|
139
140
|
).toEqual([{ sku: 'SKU-1' }]);
|
|
140
141
|
});
|
|
141
142
|
|
|
143
|
+
it('adds the update time and the list indexes, and refuses a half-applied schema', async () => {
|
|
144
|
+
await apply();
|
|
145
|
+
const schema = lease.database.schema;
|
|
146
|
+
expect(await schema.hasColumn('catalog_items', 'updated_at')).toBe(true);
|
|
147
|
+
expect(await schema.hasIndex('catalog_items_tenant_name_idx')).toBe(true);
|
|
148
|
+
expect(await schema.hasIndex('catalog_items_tenant_updated_idx')).toBe(
|
|
149
|
+
true,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
await lease.database.execute({
|
|
153
|
+
text: 'DROP INDEX catalog_items_tenant_name_idx',
|
|
154
|
+
});
|
|
155
|
+
await lease.database.execute({
|
|
156
|
+
text: `DELETE FROM ${DATABASE_MIGRATION_LEDGER} WHERE namespace = 'catalog.core'`,
|
|
157
|
+
});
|
|
158
|
+
expect((await status()).at(-1)).toMatchObject({
|
|
159
|
+
id: '0005_catalog_list_indexes',
|
|
160
|
+
state: 'partial',
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('backfills the update time of rows that predate it', async () => {
|
|
165
|
+
await runDatabaseMigrations(
|
|
166
|
+
lease.database,
|
|
167
|
+
'catalog.core',
|
|
168
|
+
databaseMigrations.slice(0, 4),
|
|
169
|
+
);
|
|
170
|
+
await lease.database.transaction(
|
|
171
|
+
(transaction) =>
|
|
172
|
+
transaction.execute({
|
|
173
|
+
text: `INSERT INTO catalog_items
|
|
174
|
+
(id, tenant_id, sku, sku_normalized, name, kind, unit,
|
|
175
|
+
base_price_minor, currency, status, created_at)
|
|
176
|
+
VALUES ('item-1', 'tenant-a', 'SKU-1', 'sku-1', 'Bolt', 'product',
|
|
177
|
+
'pcs', 500, 'EUR', 'active', 1234)`,
|
|
178
|
+
}),
|
|
179
|
+
{ tenantId: 'tenant-a', access: 'write' },
|
|
180
|
+
);
|
|
181
|
+
expect((await apply()).at(-1)).toMatchObject({
|
|
182
|
+
id: '0005_catalog_list_indexes',
|
|
183
|
+
action: 'applied',
|
|
184
|
+
});
|
|
185
|
+
expect(
|
|
186
|
+
(
|
|
187
|
+
await lease.database.transaction(
|
|
188
|
+
(transaction) =>
|
|
189
|
+
transaction.query<{ updated_at: string | number }>({
|
|
190
|
+
text: 'SELECT updated_at FROM catalog_items',
|
|
191
|
+
}),
|
|
192
|
+
{ tenantId: 'tenant-a', access: 'read' },
|
|
193
|
+
)
|
|
194
|
+
).rows.map((row) => Number(row.updated_at)),
|
|
195
|
+
).toEqual([1234]);
|
|
196
|
+
});
|
|
197
|
+
|
|
142
198
|
it('runs clean on a second migration pass', async () => {
|
|
143
199
|
await apply();
|
|
144
200
|
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
CatalogServiceError,
|
|
14
14
|
} from '../src/services/catalog-service.ts';
|
|
15
15
|
import {
|
|
16
|
+
allItems,
|
|
16
17
|
closeCatalogTestDatabases,
|
|
17
18
|
createCatalogTestDatabase,
|
|
18
19
|
type CatalogTestDatabase,
|
|
@@ -161,7 +162,7 @@ describe('catalog.core', () => {
|
|
|
161
162
|
},
|
|
162
163
|
TEST_ACTOR,
|
|
163
164
|
);
|
|
164
|
-
expect(await service
|
|
165
|
+
expect(await allItems(service, 'tenant-b')).toEqual([]);
|
|
165
166
|
});
|
|
166
167
|
|
|
167
168
|
it('keeps lifecycle revisions append-only and tenant-scoped', async () => {
|
|
@@ -4,6 +4,20 @@ import {
|
|
|
4
4
|
DatabaseCatalogRepository,
|
|
5
5
|
migrateCatalogDatabase,
|
|
6
6
|
} from '../../src/services/database-repository.ts';
|
|
7
|
+
import {
|
|
8
|
+
FIRST_LIST_PAGE,
|
|
9
|
+
type CatalogService,
|
|
10
|
+
} from '../../src/services/catalog-service.ts';
|
|
11
|
+
import type { CatalogItem } from '../../src/domain/types.ts';
|
|
12
|
+
|
|
13
|
+
/** The first page at the ceiling in SKU order: every item of a small test tenant. */
|
|
14
|
+
export async function allItems(
|
|
15
|
+
service: CatalogService,
|
|
16
|
+
tenantId: string,
|
|
17
|
+
): Promise<readonly CatalogItem[]> {
|
|
18
|
+
return (await service.listPage(tenantId, { ...FIRST_LIST_PAGE, sort: 'sku' }))
|
|
19
|
+
.items;
|
|
20
|
+
}
|
|
7
21
|
|
|
8
22
|
const TENANT_TABLES = [
|
|
9
23
|
'catalog_items',
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
"drawer.editTitle": "Edit catalog item",
|
|
8
8
|
"action.edit": "Edit",
|
|
9
9
|
"action.history": "History",
|
|
10
|
+
"action.archiveSelected": "Archive selected",
|
|
11
|
+
"action.restoreSelected": "Restore selected",
|
|
12
|
+
"action.archiveRefused": "Select at least one active item.",
|
|
13
|
+
"action.restoreRefused": "Select at least one archived item.",
|
|
14
|
+
"action.close": "Close",
|
|
15
|
+
"archiveMany.title": "Archive selected items",
|
|
16
|
+
"archiveMany.description": "Archive {count} selected items? Archived items can be restored later.",
|
|
17
|
+
"common.messages": "Messages",
|
|
18
|
+
"denied.title": "Catalog access denied",
|
|
19
|
+
"denied.description": "Your account may not read catalog items in this workspace.",
|
|
10
20
|
"delete.title": "Delete catalog item",
|
|
11
21
|
"delete.description": "Delete {name} permanently? This cannot be undone.",
|
|
12
22
|
"delete.drawerDescription": "This permanently removes the archived catalog item.",
|
|
@@ -17,7 +27,13 @@
|
|
|
17
27
|
"error.delete": "Could not delete the catalog item.",
|
|
18
28
|
"error.history": "Could not load catalog item history.",
|
|
19
29
|
"error.load": "Could not load catalog items.",
|
|
30
|
+
"error.archiveMany": "Could not archive the selected items.",
|
|
31
|
+
"error.restoreMany": "Could not restore the selected items.",
|
|
20
32
|
"error.request": "The catalog operation failed.",
|
|
33
|
+
"export.action": "Export CSV",
|
|
34
|
+
"export.started": "The catalog export started. It appears on the Exports screen once the file is ready.",
|
|
35
|
+
"export.link": "Open Exports",
|
|
36
|
+
"export.error": "Could not start the export.",
|
|
21
37
|
"form.cancel": "Cancel",
|
|
22
38
|
"form.currency": "Currency",
|
|
23
39
|
"form.kind": "Kind",
|
|
@@ -37,27 +53,42 @@
|
|
|
37
53
|
"status.active": "Active",
|
|
38
54
|
"status.archived": "Archived",
|
|
39
55
|
"filters.label": "Filters",
|
|
40
|
-
"filters.
|
|
56
|
+
"filters.kind": "Kind",
|
|
57
|
+
"filters.allKinds": "All kinds",
|
|
58
|
+
"filters.status": "Status",
|
|
59
|
+
"filters.allStatuses": "All statuses",
|
|
41
60
|
"lifecycle.title": "Lifecycle",
|
|
42
61
|
"lifecycle.description": "Archive an item before deleting it permanently.",
|
|
43
62
|
"lifecycle.history": "View history",
|
|
44
63
|
"lifecycle.archive": "Archive item",
|
|
45
64
|
"lifecycle.restore": "Restore item",
|
|
46
65
|
"lifecycle.delete": "Delete item",
|
|
66
|
+
"notice.archivedMany": "Archived {updated}, missing {missing}, refused {refused}.",
|
|
67
|
+
"notice.restoredMany": "Restored {updated}, missing {missing}, refused {refused}.",
|
|
47
68
|
"page.action.new": "New item",
|
|
48
69
|
"page.action.refresh": "Refresh",
|
|
49
70
|
"page.description": "Products and services with stable tenant-scoped SKUs.",
|
|
50
71
|
"page.eyebrow": "Commercial master data",
|
|
51
72
|
"page.title": "Catalog",
|
|
73
|
+
"pagination.label": "Catalog pages",
|
|
74
|
+
"pagination.previous": "Previous",
|
|
75
|
+
"pagination.next": "Next",
|
|
76
|
+
"pagination.size": "Items per page",
|
|
77
|
+
"pagination.summary": "Page {page} · from item {from}",
|
|
52
78
|
"price.fallback": "{amount} {currency} minor",
|
|
79
|
+
"selection.label": "Select all items on screen",
|
|
80
|
+
"selection.rowLabel": "Select {name}",
|
|
81
|
+
"selection.clear": "Clear selection",
|
|
82
|
+
"selection.summary": "{count} selected",
|
|
53
83
|
"table.caption": "Catalog items",
|
|
54
|
-
"table.column.
|
|
84
|
+
"table.column.name": "Name",
|
|
85
|
+
"table.column.sku": "SKU",
|
|
55
86
|
"table.column.kind": "Kind",
|
|
56
87
|
"table.column.price": "Price",
|
|
57
88
|
"table.column.status": "Status",
|
|
89
|
+
"table.column.updated": "Updated",
|
|
58
90
|
"table.column.actions": "Actions",
|
|
59
|
-
"table.count.
|
|
60
|
-
"table.count.other": "items: {count}",
|
|
91
|
+
"table.count.page": "{count} on this page",
|
|
61
92
|
"table.empty.hint": "Create the first product or service.",
|
|
62
93
|
"table.empty.title": "No catalog items yet",
|
|
63
94
|
"table.emptyFiltered.hint": "No item in this workspace matches the current filter.",
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
"drawer.editTitle": "Edytuj pozycję katalogu",
|
|
8
8
|
"action.edit": "Edytuj",
|
|
9
9
|
"action.history": "Historia",
|
|
10
|
+
"action.archiveSelected": "Archiwizuj zaznaczone",
|
|
11
|
+
"action.restoreSelected": "Przywróć zaznaczone",
|
|
12
|
+
"action.archiveRefused": "Zaznacz co najmniej jedną aktywną pozycję.",
|
|
13
|
+
"action.restoreRefused": "Zaznacz co najmniej jedną zarchiwizowaną pozycję.",
|
|
14
|
+
"action.close": "Zamknij",
|
|
15
|
+
"archiveMany.title": "Archiwizuj zaznaczone pozycje",
|
|
16
|
+
"archiveMany.description": "Zarchiwizować zaznaczone pozycje ({count})? Zarchiwizowane pozycje można później przywrócić.",
|
|
17
|
+
"common.messages": "Komunikaty",
|
|
18
|
+
"denied.title": "Brak dostępu do katalogu",
|
|
19
|
+
"denied.description": "Twoje konto nie może odczytywać pozycji katalogu w tej przestrzeni roboczej.",
|
|
10
20
|
"delete.title": "Usuń pozycję katalogu",
|
|
11
21
|
"delete.description": "Usunąć trwale pozycję {name}? Tej operacji nie można cofnąć.",
|
|
12
22
|
"delete.drawerDescription": "Ta operacja trwale usuwa zarchiwizowaną pozycję katalogu.",
|
|
@@ -17,7 +27,13 @@
|
|
|
17
27
|
"error.delete": "Nie udało się usunąć pozycji katalogu.",
|
|
18
28
|
"error.history": "Nie udało się wczytać historii pozycji katalogu.",
|
|
19
29
|
"error.load": "Nie udało się wczytać pozycji katalogu.",
|
|
30
|
+
"error.archiveMany": "Nie udało się zarchiwizować zaznaczonych pozycji.",
|
|
31
|
+
"error.restoreMany": "Nie udało się przywrócić zaznaczonych pozycji.",
|
|
20
32
|
"error.request": "Operacja na katalogu nie powiodła się.",
|
|
33
|
+
"export.action": "Eksportuj CSV",
|
|
34
|
+
"export.started": "Eksport katalogu wystartował. Pojawi się na ekranie Eksporty, gdy plik będzie gotowy.",
|
|
35
|
+
"export.link": "Otwórz Eksporty",
|
|
36
|
+
"export.error": "Nie udało się rozpocząć eksportu.",
|
|
21
37
|
"form.cancel": "Anuluj",
|
|
22
38
|
"form.currency": "Waluta",
|
|
23
39
|
"form.kind": "Rodzaj",
|
|
@@ -37,27 +53,42 @@
|
|
|
37
53
|
"status.active": "Aktywna",
|
|
38
54
|
"status.archived": "Zarchiwizowana",
|
|
39
55
|
"filters.label": "Filtry",
|
|
40
|
-
"filters.
|
|
56
|
+
"filters.kind": "Rodzaj",
|
|
57
|
+
"filters.allKinds": "Wszystkie rodzaje",
|
|
58
|
+
"filters.status": "Status",
|
|
59
|
+
"filters.allStatuses": "Wszystkie statusy",
|
|
41
60
|
"lifecycle.title": "Cykl życia",
|
|
42
61
|
"lifecycle.description": "Zarchiwizuj pozycję przed jej trwałym usunięciem.",
|
|
43
62
|
"lifecycle.history": "Zobacz historię",
|
|
44
63
|
"lifecycle.archive": "Archiwizuj pozycję",
|
|
45
64
|
"lifecycle.restore": "Przywróć pozycję",
|
|
46
65
|
"lifecycle.delete": "Usuń pozycję",
|
|
66
|
+
"notice.archivedMany": "Zarchiwizowano {updated}, brak {missing}, odrzucono {refused}.",
|
|
67
|
+
"notice.restoredMany": "Przywrócono {updated}, brak {missing}, odrzucono {refused}.",
|
|
47
68
|
"page.action.new": "Nowa pozycja",
|
|
48
69
|
"page.action.refresh": "Odśwież",
|
|
49
70
|
"page.description": "Produkty i usługi ze stałym SKU w obrębie przestrzeni roboczej.",
|
|
50
71
|
"page.eyebrow": "Dane podstawowe sprzedaży",
|
|
51
72
|
"page.title": "Katalog",
|
|
73
|
+
"pagination.label": "Strony katalogu",
|
|
74
|
+
"pagination.previous": "Poprzednia",
|
|
75
|
+
"pagination.next": "Następna",
|
|
76
|
+
"pagination.size": "Pozycji na stronie",
|
|
77
|
+
"pagination.summary": "Strona {page} · od pozycji {from}",
|
|
52
78
|
"price.fallback": "{amount} {currency} w groszach",
|
|
79
|
+
"selection.label": "Zaznacz wszystkie pozycje na ekranie",
|
|
80
|
+
"selection.rowLabel": "Zaznacz {name}",
|
|
81
|
+
"selection.clear": "Wyczyść zaznaczenie",
|
|
82
|
+
"selection.summary": "Zaznaczono: {count}",
|
|
53
83
|
"table.caption": "Pozycje katalogu",
|
|
54
|
-
"table.column.
|
|
84
|
+
"table.column.name": "Nazwa",
|
|
85
|
+
"table.column.sku": "SKU",
|
|
55
86
|
"table.column.kind": "Rodzaj",
|
|
56
87
|
"table.column.price": "Cena",
|
|
57
88
|
"table.column.status": "Status",
|
|
89
|
+
"table.column.updated": "Zmieniono",
|
|
58
90
|
"table.column.actions": "Akcje",
|
|
59
|
-
"table.count.
|
|
60
|
-
"table.count.other": "pozycje: {count}",
|
|
91
|
+
"table.count.page": "Na tej stronie: {count}",
|
|
61
92
|
"table.empty.hint": "Dodaj pierwszy produkt lub usługę.",
|
|
62
93
|
"table.empty.title": "Nie ma jeszcze pozycji katalogu",
|
|
63
94
|
"table.emptyFiltered.hint": "Żadna pozycja w tej przestrzeni roboczej nie pasuje do filtra.",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "catalog.core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"repository": "Flowdular/official-modules",
|
|
5
|
-
"sourceCommit": "
|
|
6
|
-
"artifactSha256": "
|
|
5
|
+
"sourceCommit": "edad0ec198877c0359f11512b7c0055f87d5f8b4",
|
|
6
|
+
"artifactSha256": "3e1c8530eed822c35e12f24545492bf7614bbd47e3a9255a869423d7e1662ef4",
|
|
7
7
|
"files": {
|
|
8
8
|
"LICENSE": "155d722071bad9d0d832482e06fd5a47f7034389cb63aabcb39f4282aa3499fc",
|
|
9
9
|
"migrations/0001_catalog_core.down.sql": "0962a1edf0bde959cd4facccf77bd5b634d6cc25f125a0c79a61770c8871093f",
|
|
@@ -14,43 +14,51 @@
|
|
|
14
14
|
"migrations/0003_catalog_history_service_actors.up.sql": "7caae787ca2fc1e331ccbfda4df5982beec76136e8dc486aab5532ccd338a722",
|
|
15
15
|
"migrations/0004_catalog_idempotency_ledger.down.sql": "8ba72d8edc4d25ecf6d041888cf321690c25afdaf3723812ddd7d391d75370aa",
|
|
16
16
|
"migrations/0004_catalog_idempotency_ledger.up.sql": "41e86ba2051159c6cc9672bfae17c1d02051da975f1c43c566a2b66592673cb0",
|
|
17
|
+
"migrations/0005_catalog_list_indexes.down.sql": "3dd547d738e75513abef502afc4bf9b51851ec9405b6b719c6134b897c5b1776",
|
|
18
|
+
"migrations/0005_catalog_list_indexes.up.sql": "dc3ece30b93fba0c91be58f772d1ae421cfbba49439e8c72a06aead6720f5db5",
|
|
17
19
|
"migrations/README.md": "2a15fd001713c2552a3c82b186246aa5fec136f43143cc2d9aa15bd491a09d41",
|
|
18
|
-
"module.json": "
|
|
19
|
-
"package.json": "
|
|
20
|
-
"spec/module.yaml": "
|
|
20
|
+
"module.json": "4a4e5b5414f97a6b023c0ed64d0df313aa3ab4e8771f8e33137e589818ad20fd",
|
|
21
|
+
"package.json": "6dd4972624c2a141b038c024137a29b0e5223a28f9021653f2aa6517fb464b56",
|
|
22
|
+
"spec/module.yaml": "c30518bd28e5d184ef122f194f5c1308ff5c522df6638085ccc8121a78d40971",
|
|
21
23
|
"src/acl/permissions.ts": "3375521a5a229736ffac5a948140ec347dc7a7e4fba80e778c0baaf9e0622590",
|
|
22
|
-
"src/agent/tools.ts": "
|
|
23
|
-
"src/api/endpoints.ts": "
|
|
24
|
+
"src/agent/tools.ts": "3403db7954906dc2c79227ba0420b5cb4bfb57063b7cfc285e6e556f16be9266",
|
|
25
|
+
"src/api/endpoints.ts": "205ef36d058f246f99b77336e7246a23aaca611c696a1f6f09758f66e8a93a29",
|
|
26
|
+
"src/api/list-cursor.ts": "dcb763edc0128a3aac95e9ca3c5158611a7f2c6a4c71484438c89b7f4d79bb0d",
|
|
24
27
|
"src/client/CatalogHistoryDrawer.tsrx": "6cdba5249be81e70da703cb34c1a2210943ce5e5fb596ee77cf7952e2acf3ee3",
|
|
25
28
|
"src/client/CatalogItemForm.tsrx": "7dafa4149975d9e7d5784c8a5391b5b64c2405991aaead713d94b61c41168c2c",
|
|
26
|
-
"src/client/CatalogView.tsrx": "
|
|
27
|
-
"src/client/api.ts": "
|
|
28
|
-
"src/client/contribution.tsrx": "
|
|
29
|
+
"src/client/CatalogView.tsrx": "bc1e543690e07d52b51626832f36afe3fde87bf2dc45642324507df8384d7303",
|
|
30
|
+
"src/client/api.ts": "eaa55af81d26aa0190d19b3102c363c1ee25b2bdc05436446ac95dcde62aea75",
|
|
31
|
+
"src/client/contribution.tsrx": "6cbf79e6188bdf24b9cec4a06ae621e03efd5d0c76ad72b28828eee9155ab893",
|
|
29
32
|
"src/client/index.ts": "03eb0664cdafccb66cb25f2e1b07e6959c2dfa9bdbfffc3e7edf9b535ba4949a",
|
|
30
33
|
"src/client/navigation-copy.ts": "9a8757e64f4001a93e2bc2861c686a19f791f9d67a396d9e658023b1ec4cea8f",
|
|
31
|
-
"src/client/state.ts": "
|
|
32
|
-
"src/domain/
|
|
34
|
+
"src/client/state.ts": "61601f6037c4bb8a709b69b10c1a37e59b45b0c941240c436f7861c2b034dcc1",
|
|
35
|
+
"src/domain/lists.ts": "83749967f99fa0c4f44abc0c614108b844321e50ce6408553215e6233ad6e350",
|
|
36
|
+
"src/domain/types.ts": "374efeb24c4f7d41e3c660336e721fa362418579837d44a46724076d03287a0b",
|
|
33
37
|
"src/domain/variables.ts": "131130e57838235b1f3fcb799da44baeae16522bb346d522827e022305c110b5",
|
|
34
38
|
"src/index.ts": "5b27943018db9a18651d62add7d6f8397d7c492a204381fae74547b99b91990d",
|
|
35
|
-
"src/platform.ts": "
|
|
39
|
+
"src/platform.ts": "f048082a33c1c688e4952750c762c8b65a4626ff52cc9c4eaca2156014bac631",
|
|
36
40
|
"src/server/index.ts": "90eae107d863418124e5d10c4d1fe8a119bd14da605b36de708c18d8500c4b5e",
|
|
37
41
|
"src/server/runtime.ts": "5f4389a6adf8265f6737c489baf686f63cc3550662103d28b2da9800dd9f5b63",
|
|
38
|
-
"src/services/catalog-service.ts": "
|
|
42
|
+
"src/services/catalog-service.ts": "66e61dfbd9797d31e6814c18efcd21cfcb7b220f7df22677868f486f3fa0e9d1",
|
|
39
43
|
"src/services/data-classes.ts": "ea09b1a7def59fee43d57ca7dab6fdb4d646b51df2cacb60af96676c43602b33",
|
|
40
|
-
"src/services/database-repository.ts": "
|
|
44
|
+
"src/services/database-repository.ts": "1b72ce91a2f85f6572825766781a806d94fe0d2abb91872ee9acae3b1e70db2e",
|
|
41
45
|
"src/services/index.ts": "a08aefe5101814538666f861536287fc382e6c655d62ba9b9ef4bbfbc6ede4af",
|
|
42
|
-
"src/services/
|
|
43
|
-
"src/services/
|
|
46
|
+
"src/services/item-export.ts": "b2a4613b43a98d0d41699481bb5e85a770f9a60cb2241579b065effb6936c80b",
|
|
47
|
+
"src/services/migration.ts": "57c9a857d4074973e14b5e3a1c4548a92ad0faca371419e7daf2334f3ef701ab",
|
|
48
|
+
"src/services/repository.ts": "9f560033875d05654148b4a11897465ee4eefa0d7fa701439e8f562da9fba1db",
|
|
44
49
|
"src/services/target-idempotency.ts": "7111b56a30b691eaaaa64f5691895ac94b6e0735b0079794835bbbeba5102cb0",
|
|
45
|
-
"tests/agent-tools.test.ts": "
|
|
50
|
+
"tests/agent-tools.test.ts": "7762c14bc353ee3085df46a91cf370eb5c25b2edb7096f0a4b0e033f220ea726",
|
|
51
|
+
"tests/client-state.test.ts": "ea146c793b14d0f9bc5e36d92e92894ced6531b8fcbd11c8be1486b62313b8c3",
|
|
46
52
|
"tests/data-classes.test.ts": "bea08e4d1d7380ccdebc211374b74a6034714b192fd98bfb90a2218067b35658",
|
|
47
|
-
"tests/endpoints.test.ts": "
|
|
48
|
-
"tests/
|
|
49
|
-
"tests/
|
|
50
|
-
"tests/
|
|
51
|
-
"tests/
|
|
52
|
-
"
|
|
53
|
-
"
|
|
53
|
+
"tests/endpoints.test.ts": "a2d700f4c3eb6fbbef5c57ed5591017a27c98e17fe84fba8426fcd3a2820b210",
|
|
54
|
+
"tests/export.test.ts": "de83066272cee5f7f5736d636d7b9b97dab09778ba661816e401bf926b826402",
|
|
55
|
+
"tests/idempotency.test.ts": "faea4a2cfa04e81b7155399cba807af4c1ba4448cdfeab733d1afe801d27734f",
|
|
56
|
+
"tests/list.test.ts": "97605b50020841cbdac62f9d44b65f0f7dce9c4c4972af6409afeb6b9b66e59a",
|
|
57
|
+
"tests/migrations.test.ts": "fb796aecedb997f6395c2c15e45bf4abfae4677953fa8cb420c94e9cfba8222f",
|
|
58
|
+
"tests/module.test.ts": "af961a5bcddc41d304d14841f8810976f43f46b46ab7814142fdb921a773e92a",
|
|
59
|
+
"tests/support/database.ts": "4ff6d093ca2e80baab3dea476018661473d6474db63d67655f1edc667b8472ac",
|
|
60
|
+
"translations/en.json": "a86d70e02ccf46a2a132d5bee0de7c528c0eb56a85c269a78e0c2e7e0de24e37",
|
|
61
|
+
"translations/pl.json": "8157d83467e9dd8d9700e2fb188f1a730073f805d2a8b3f0ba98f02f2ca9a264",
|
|
54
62
|
"tsconfig.json": "140bb4775df421146563d13d2f78ff74cb3c2decab6737db32938339248a92ba",
|
|
55
63
|
"vitest.config.ts": "d13725b13c3712ec91c1646e9226fb172eec2599f72f4e6608bece9912e2bd81"
|
|
56
64
|
}
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://flowdular.com)
|
|
2
2
|
|
|
3
3
|
# Flowdular SDK
|
|
4
4
|
|
|
Binary file
|
package/modules/auth/module.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"schemaVersion": 1,
|
|
4
4
|
"id": "auth.core",
|
|
5
5
|
"package": "@flowdular/module-auth",
|
|
6
|
-
"version": "0.13.
|
|
6
|
+
"version": "0.13.11",
|
|
7
7
|
"profile": "full",
|
|
8
8
|
"capabilities": ["api", "database", "client", "translations", "cli"],
|
|
9
9
|
"platform": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"dependencies": [
|
|
13
13
|
{
|
|
14
14
|
"id": "system.core",
|
|
15
|
-
"range": "^0.
|
|
15
|
+
"range": "^0.8.0"
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
18
|
"tenancy": "required",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
schemaVersion: 2
|
|
2
2
|
id: auth.core
|
|
3
|
-
specVersion: 0.13.
|
|
3
|
+
specVersion: 0.13.11
|
|
4
4
|
status: approved
|
|
5
5
|
name: Authentication Core
|
|
6
6
|
description: Provides tenant-aware accounts, password authentication, sessions, scopes, tenant roles, API tokens for machine clients, the module settings store, the auth audit trail, security headers, authentication screens, and server authorization middleware.
|
|
@@ -13,7 +13,7 @@ capabilities:
|
|
|
13
13
|
- cli
|
|
14
14
|
dependencies:
|
|
15
15
|
- id: system.core
|
|
16
|
-
range: ^0.
|
|
16
|
+
range: ^0.8.0
|
|
17
17
|
tenancy: required
|
|
18
18
|
locales:
|
|
19
19
|
- en
|
|
@@ -70,7 +70,11 @@ export function endpointIdentityFromContext(
|
|
|
70
70
|
): EndpointIdentity | null {
|
|
71
71
|
const principal = principalFromContext(context);
|
|
72
72
|
return principal
|
|
73
|
-
? {
|
|
73
|
+
? {
|
|
74
|
+
subjectId: principal.accountId,
|
|
75
|
+
tenantId: principal.tenantId,
|
|
76
|
+
permissions: new Set(principal.scopes),
|
|
77
|
+
}
|
|
74
78
|
: null;
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -385,6 +385,8 @@ export const AUDIT_ACTIONS = Object.freeze({
|
|
|
385
385
|
roleDeleted: 'auth.role.deleted',
|
|
386
386
|
settingsUpdated: 'settings.updated',
|
|
387
387
|
settingsFlagChanged: 'settings.flag.changed',
|
|
388
|
+
moduleActivated: 'system.module.activated',
|
|
389
|
+
moduleDeactivated: 'system.module.deactivated',
|
|
388
390
|
});
|
|
389
391
|
|
|
390
392
|
export const AUDIT_ACTION_LIST = Object.freeze(Object.values(AUDIT_ACTIONS));
|
|
@@ -886,6 +888,13 @@ export class AuthService {
|
|
|
886
888
|
);
|
|
887
889
|
}
|
|
888
890
|
|
|
891
|
+
/** How many members hold the owner role, counted the same way for the same screen. */
|
|
892
|
+
countTenantOwners(tenantId: string): Promise<number> {
|
|
893
|
+
return this.#repository.countTenantOwners(
|
|
894
|
+
this.#identifier(tenantId, 'tenantId'),
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
|
|
889
898
|
/**
|
|
890
899
|
* The identity bindings this workspace's own providers assert about its
|
|
891
900
|
* members, one bounded page per call. A binding names the account, the
|
|
@@ -2912,6 +2921,23 @@ export class AuthService {
|
|
|
2912
2921
|
);
|
|
2913
2922
|
}
|
|
2914
2923
|
|
|
2924
|
+
/** The one audit row a committed per-workspace module activation change owes. */
|
|
2925
|
+
async recordModuleActivation(
|
|
2926
|
+
actor: AuthActor,
|
|
2927
|
+
change: { readonly moduleId: string; readonly active: boolean },
|
|
2928
|
+
): Promise<void> {
|
|
2929
|
+
await this.#audit(
|
|
2930
|
+
actor.tenantId,
|
|
2931
|
+
this.#actorOf(actor),
|
|
2932
|
+
change.active
|
|
2933
|
+
? AUDIT_ACTIONS.moduleActivated
|
|
2934
|
+
: AUDIT_ACTIONS.moduleDeactivated,
|
|
2935
|
+
'module',
|
|
2936
|
+
change.moduleId,
|
|
2937
|
+
{ active: change.active },
|
|
2938
|
+
);
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2915
2941
|
async queryAudit(query: AuditQuery): Promise<AuditActorPage> {
|
|
2916
2942
|
const limit = Math.min(
|
|
2917
2943
|
Math.max(1, Math.trunc(query.limit)),
|
|
@@ -939,6 +939,15 @@ export class DatabaseAuthRepository implements AuthRepository {
|
|
|
939
939
|
return rows[0] ? integer(rows[0].total, 'total') : 0;
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
+
async countTenantOwners(tenantId: string): Promise<number> {
|
|
943
|
+
const rows = await this.#query<CountRow>(tenantId, {
|
|
944
|
+
text: `SELECT count(*) AS total FROM auth_memberships
|
|
945
|
+
WHERE tenant_id = $1 AND role = 'owner'`,
|
|
946
|
+
parameters: [tenantId],
|
|
947
|
+
});
|
|
948
|
+
return rows[0] ? integer(rows[0].total, 'total') : 0;
|
|
949
|
+
}
|
|
950
|
+
|
|
942
951
|
async findTenantMember(
|
|
943
952
|
tenantId: string,
|
|
944
953
|
accountId: string,
|
|
@@ -363,6 +363,8 @@ export interface AuthRepository {
|
|
|
363
363
|
): Promise<TenantMemberSortedPage>;
|
|
364
364
|
/** How many memberships the workspace holds, an index range over 0030. */
|
|
365
365
|
countTenantMembers(tenantId: string): Promise<number>;
|
|
366
|
+
/** How many of those memberships hold the owner role, whatever their status. */
|
|
367
|
+
countTenantOwners(tenantId: string): Promise<number>;
|
|
366
368
|
/** One member, for a caller that needs a single account rather than the roll. */
|
|
367
369
|
findTenantMember(
|
|
368
370
|
tenantId: string,
|