@rytass/bpm-core-nestjs-module 0.12.0 → 0.13.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 (55) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +160 -3
  3. package/package.json +3 -3
  4. package/src/lib/attachment/attachment-options.d.ts +11 -0
  5. package/src/lib/attachment/attachment-options.js +21 -6
  6. package/src/lib/attachment/attachment-options.js.map +1 -1
  7. package/src/lib/attachment/index.d.ts +1 -0
  8. package/src/lib/attachment/index.js +1 -0
  9. package/src/lib/attachment/index.js.map +1 -1
  10. package/src/lib/bpm/bpm-root.module.d.ts +35 -0
  11. package/src/lib/bpm/bpm-root.module.js +8 -0
  12. package/src/lib/bpm/bpm-root.module.js.map +1 -1
  13. package/src/lib/bpm-auth/bpm-auth.authorization.js +3 -2
  14. package/src/lib/bpm-auth/bpm-auth.authorization.js.map +1 -1
  15. package/src/lib/bpm-auth/bpm-auth.decorators.js +2 -1
  16. package/src/lib/bpm-auth/bpm-auth.decorators.js.map +1 -1
  17. package/src/lib/bpm-auth/bpm-resolver-access.decorator.d.ts +13 -0
  18. package/src/lib/bpm-auth/bpm-resolver-access.decorator.js +27 -0
  19. package/src/lib/bpm-auth/bpm-resolver-access.decorator.js.map +1 -0
  20. package/src/lib/bpm-auth/bpm-resolver-metadata.d.ts +73 -0
  21. package/src/lib/bpm-auth/bpm-resolver-metadata.js +158 -0
  22. package/src/lib/bpm-auth/bpm-resolver-metadata.js.map +1 -0
  23. package/src/lib/bpm-auth/index.d.ts +2 -0
  24. package/src/lib/bpm-auth/index.js +2 -0
  25. package/src/lib/bpm-auth/index.js.map +1 -1
  26. package/src/lib/condition/condition.service.js +45 -4
  27. package/src/lib/condition/condition.service.js.map +1 -1
  28. package/src/lib/identity/identity-options.d.ts +16 -0
  29. package/src/lib/identity/identity-options.js.map +1 -1
  30. package/src/lib/identity/identity.module.d.ts +6 -0
  31. package/src/lib/identity/identity.module.js +9 -2
  32. package/src/lib/identity/identity.module.js.map +1 -1
  33. package/src/lib/migrations/0000000000001-enable-postgres-extensions.d.ts +9 -1
  34. package/src/lib/migrations/0000000000001-enable-postgres-extensions.js +55 -4
  35. package/src/lib/migrations/0000000000001-enable-postgres-extensions.js.map +1 -1
  36. package/src/lib/notification/index.d.ts +1 -0
  37. package/src/lib/notification/index.js +1 -0
  38. package/src/lib/notification/index.js.map +1 -1
  39. package/src/lib/organization/dto/manager-resolution.input.d.ts +7 -7
  40. package/src/lib/organization/dto/membership.input.d.ts +7 -7
  41. package/src/lib/organization/dto/org-unit.input.d.ts +28 -6
  42. package/src/lib/organization/dto/org-unit.input.js +4 -2
  43. package/src/lib/organization/dto/org-unit.input.js.map +1 -1
  44. package/src/lib/organization/dto/position.input.d.ts +4 -4
  45. package/src/lib/organization/index.d.ts +4 -0
  46. package/src/lib/organization/index.js +4 -0
  47. package/src/lib/organization/index.js.map +1 -1
  48. package/src/lib/organization/organization.mutations.d.ts +1 -0
  49. package/src/lib/organization/organization.mutations.js +10 -0
  50. package/src/lib/organization/organization.mutations.js.map +1 -1
  51. package/src/lib/organization/organization.service.d.ts +43 -0
  52. package/src/lib/organization/organization.service.js +166 -7
  53. package/src/lib/organization/organization.service.js.map +1 -1
  54. package/src/lib/template/dto/approval-template.input.d.ts +31 -20
  55. package/src/lib/template/dto/approval-template.input.js.map +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,38 @@
1
+ ## 0.13.0 (2026-09-03)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **bpm-auth:** let a host stamp its own route metadata on BPM resolvers ([49bedb7](https://github.com/Rytass/BPMCore/commit/49bedb7))
6
+ - **identity:** let a host turn off the identity GraphQL queries ([33630f8](https://github.com/Rytass/BPMCore/commit/33630f8))
7
+
8
+ ### 🩹 Fixes
9
+
10
+ - **migrations:** stop dropping extensions this migration may not have created ([88256d1](https://github.com/Rytass/BPMCore/commit/88256d1))
11
+ - **condition:** name the Node version when cel-js cannot be required ([2691e63](https://github.com/Rytass/BPMCore/commit/2691e63))
12
+ - **bpm-auth:** list only real GraphQL handlers, and keep symbol metadata keys ([9cc4593](https://github.com/Rytass/BPMCore/commit/9cc4593))
13
+ - ⚠️ **attachment:** refuse to sign production attachment URLs with the public dev key ([c40ce67](https://github.com/Rytass/BPMCore/commit/c40ce67))
14
+ - **migrations:** explain what to do when CREATE EXTENSION is denied ([a0c9c38](https://github.com/Rytass/BPMCore/commit/a0c9c38))
15
+ - **condition:** load cel-js on first use, not on import ([e2a64c9](https://github.com/Rytass/BPMCore/commit/e2a64c9))
16
+ - **template:** let UpdateApprovalTemplateInput say "keep the category" ([c11c248](https://github.com/Rytass/BPMCore/commit/c11c248))
17
+ - **organization:** let update inputs say "leave this alone", and allow deleting a position ([e09e012](https://github.com/Rytass/BPMCore/commit/e09e012))
18
+
19
+ ### ⚠️ Breaking Changes
20
+
21
+ - **attachment:** refuse to sign production attachment URLs with the public dev key ([c40ce67](https://github.com/Rytass/BPMCore/commit/c40ce67))
22
+ a NODE_ENV=production process that never set
23
+ attachmentSignedUrlSecret no longer starts. BPMRootModule mounts
24
+ AttachmentModule unconditionally, so this reaches hosts that serve no
25
+ attachments at all. Set the secret, or set
26
+ attachmentAllowInsecureSignedUrlSecret: true to acknowledge that the signing
27
+ key is public.
28
+ Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
29
+ Claude-Session: https://claude.ai/code/session_016VKxnq3cFuySFMLMZhtd2E
30
+
31
+ ### ❤️ Thank You
32
+
33
+ - Chia Yu Pai @fantasywind
34
+ - Claude Opus 5
35
+
1
36
  ## 0.12.0 (2026-08-27)
2
37
 
3
38
  ### 🚀 Features
package/README.md CHANGED
@@ -582,6 +582,62 @@ export class BPMAuthContextFactory {
582
582
  > module or a database table) so adding a new BPM tier in a future
583
583
  > BPMCore release becomes a one-line addition.
584
584
 
585
+ ### Coexisting with a host global guard
586
+
587
+ `APP_GUARD`-registered guards run **before** BPM's own. A guard that decides
588
+ by route metadata therefore judges BPM's resolvers by metadata BPM never
589
+ writes — and `@rytass/member-base-nestjs-module`'s `CasbinGuard` rejects any
590
+ route without `@CheckPermission`:
591
+
592
+ ```json
593
+ { "errors": [{ "message": "Route has no permission metadata",
594
+ "path": ["orgUnits"],
595
+ "extensions": { "code": "FORBIDDEN" } }] }
596
+ ```
597
+
598
+ Every BPM query and mutation fails this way, before BPM's guards run at all.
599
+ BPM cannot import the host's decorator, and a decorator cannot read module
600
+ options — it runs when the class is defined. So BPM's resolvers register
601
+ themselves, and `resolverMetadataFactory` replays your factory over them at
602
+ module wiring time:
603
+
604
+ ```ts
605
+ import { PERMISSION_METADATA_KEY } from '@rytass/member-base-nestjs-module';
606
+ import { BPMRootModule, type BPMResolverMetadataFactory } from '@rytass/bpm-core-nestjs-module';
607
+
608
+ const HOST_PERMISSIONS: Readonly<Record<string, readonly string[]>> = {
609
+ admin: ['bpm:admin'],
610
+ authenticated: ['bpm:use'],
611
+ designer: ['bpm:design'],
612
+ };
613
+
614
+ const resolverMetadataFactory: BPMResolverMetadataFactory = ({ access }) => ({
615
+ [PERMISSION_METADATA_KEY]: HOST_PERMISSIONS[access],
616
+ });
617
+
618
+ BPMRootModule.forRoot({ resolverMetadataFactory, /* ... */ });
619
+ ```
620
+
621
+ The factory is called once per handler and receives `{ access, resolverName,
622
+ methodName }`. `access` is the authority BPM's own guards require —
623
+ `'admin'`, `'designer'`, or `'authenticated'` — so the common case is one
624
+ lookup table rather than a per-operation list. `methodName` is also the
625
+ GraphQL field name (`orgUnits`, `createOrgUnit`, `member`) when a handful of
626
+ operations need finer grants. Returning `null` leaves a handler untouched.
627
+
628
+ The returned record is written onto the prototype method, which is exactly
629
+ what Nest hands a guard as `context.getHandler()`; BPM's own guards still run
630
+ afterwards, so both permission models apply.
631
+
632
+ `listBPMResolverHandlers()` prints every handler the factory will be offered,
633
+ which is the quickest way to build the mapping table:
634
+
635
+ ```ts
636
+ import { listBPMResolverHandlers } from '@rytass/bpm-core-nestjs-module';
637
+
638
+ console.table([...listBPMResolverHandlers()]);
639
+ ```
640
+
585
641
  ## Member Resolver
586
642
 
587
643
  The package resolves display names, email addresses, and approver candidates
@@ -873,6 +929,7 @@ BPMRootModule.forRootAsync({
873
929
  | ------------------------------------------------ | ------------------------------ | -------------------------------------------------------------- |
874
930
  | `authContextFactory` | `undefined` | Reads `BPMAuthContext` from NestJS `ExecutionContext`. |
875
931
  | `memberResolverProvider` | required | Provider for `BPM_MEMBER_RESOLVER`. |
932
+ | `resolverMetadataFactory` | `undefined` | Stamps the host's own route metadata onto every BPM GraphQL handler. Required when the host installs a global metadata-driven guard — see "Coexisting with a host global guard". |
876
933
  | `attachmentStorageProvider` | local `.storage/attachments` | Host-provided `@rytass/storages` adapter. |
877
934
  | `workflowServiceTaskDispatcherProvider` | built-in `fetch` dispatcher | Host provider for executable workflow `WEBHOOK` service tasks. |
878
935
  | `businessCalendarProvider` | Monday–Friday calendar | Host provider for `BPM_BUSINESS_CALENDAR`, used by `BUSINESS_DAY` SLAs. BPMCore ships no holiday data. |
@@ -880,9 +937,11 @@ BPMRootModule.forRootAsync({
880
937
  | `attachmentRoutePrefix` | `/attachments` | Drives both the BPM signed URL path and the Nest controller mount path for `AttachmentController`. Must be set at module wiring time (see "Attachment Storage" below). |
881
938
  | `attachmentStorageProviderId` | `local` | Value stored on attachment metadata for the active adapter. |
882
939
  | `attachmentPublicBaseUrl` | `http://localhost:17603` | Public base URL for signed attachment URLs. |
883
- | `attachmentSignedUrlSecret` | local development secret | HMAC secret for signed attachment download/preview tokens. |
940
+ | `attachmentSignedUrlSecret` | local development secret | HMAC secret for signed attachment download/preview tokens. Under `NODE_ENV=production` BPM refuses to start while this is unset. |
941
+ | `attachmentAllowInsecureSignedUrlSecret` | `false` | Opt-in that lets a `NODE_ENV=production` process boot on the built-in development secret anyway. Only for throwaway environments — the value is published in this package. |
884
942
  | `attachmentSignedUrlTtlSeconds` | `300` | Signed attachment URL lifetime in seconds. |
885
943
  | `identityMemberMetadataCacheTtlMs` | `300000` | Member metadata cache TTL. |
944
+ | `identityRegisterResolvers` | `true` | Set to `false` when the host already publishes `member` / `members` / `memberCount` / `searchMembers` GraphQL queries. `IdentityService` stays available either way. |
886
945
  | `notificationInAppEnabled` | `true` | Enables in-app notification records. |
887
946
  | `notificationEmailEnabled` | `auto` | Enables email when SMTP settings are complete. |
888
947
  | `notificationEmailSmtpHost` | `null` | SMTP host. |
@@ -919,8 +978,95 @@ BPMRootModule.forRootAsync({
919
978
 
920
979
  Production deployments should override all local development secrets.
921
980
 
981
+ ### Mounting a single domain module
982
+
983
+ `BPMRootModule` is the supported entry point and the only one that wires the
984
+ whole product. A host that wants **one** BPM domain — most often organization
985
+ data, with no workflow, forms, or notifications — can import that domain
986
+ module on its own. These are self-contained: they declare their own
987
+ `TypeOrmModule.forFeature` and their services inject nothing but `DataSource`
988
+ and repositories.
989
+
990
+ ```ts
991
+ import { Module } from '@nestjs/common';
992
+ import { OrganizationModule, OrganizationService } from '@rytass/bpm-core-nestjs-module';
993
+
994
+ @Module({ imports: [OrganizationModule] })
995
+ export class HostOrganizationModule {}
996
+ ```
997
+
998
+ | Module | Self-contained | Notes |
999
+ | -------------------- | -------------- | -------------------------------------------------------------------- |
1000
+ | `OrganizationModule` | yes | Org units, positions, memberships, manager resolution. Mounted alone, `deletePosition` silently skips its approval-template and ad-hoc-directive reference checks (it logs when it does) — those tables are not in the schema. |
1001
+ | `FormModule` | yes | Form definitions and versions. |
1002
+ | `TemplateModule` | yes | Approval templates, versions, categories. |
1003
+ | `ConditionModule` | yes | CEL lint and evaluation only. |
1004
+ | `IdentityModule` | no | Needs `memberResolverProvider`; use `IdentityModule.forRoot(...)`. |
1005
+ | `AttachmentModule` | no | Needs storage and signed-URL options; use `AttachmentModule.forRoot(...)`. |
1006
+
1007
+ What you still owe them:
1008
+
1009
+ - **Migrations.** `BPM_CORE_MIGRATIONS` is one list for the whole package; a
1010
+ single-module host still runs all of it, and still needs the extensions in
1011
+ "Database prerequisites" below.
1012
+ - **Auth.** A domain module imported directly does not bring `BPMAuthModule`,
1013
+ so `@BPMAdminOnly()` on its resolvers has no auth context accessor to
1014
+ inject. Either import `BPMAuthModule.forRoot({ contextFactory })` alongside
1015
+ it, or use the domain **service** and publish your own GraphQL surface.
1016
+ - **Resolver metadata.** `resolverMetadataFactory` is applied by
1017
+ `BPMRootModule`, which is not in play here. A host that needs it on this path
1018
+ calls `applyBPMResolverMetadata(factory)` itself, once, before the
1019
+ application starts.
1020
+
1021
+ The domain services (`OrganizationService` and friends) are the stable part of
1022
+ this arrangement; a module's internal wiring is not. If you are here because
1023
+ `BPMRootModule` collides with your schema, `identityRegisterResolvers` and
1024
+ `resolverMetadataFactory` usually let you keep the supported entry point.
1025
+
1026
+ ### Testing a host that depends on BPM
1027
+
1028
+ BPM loads `cel-js` — ESM-only, with a `chevrotain` dependency whose exports
1029
+ map `jest-resolve` cannot follow — lazily, on the first CEL expression it
1030
+ parses. Importing anything from the package root does not reach it, so a host
1031
+ jest suite needs no `moduleNameMapper` entry and no stub.
1032
+
1033
+ A suite that *does* exercise conditions (template validation, workflow
1034
+ transitions) will load `cel-js` for real. If your jest version cannot resolve
1035
+ it, map it to a stub of your own:
1036
+
1037
+ ```ts
1038
+ // jest.config.ts
1039
+ moduleNameMapper: { '^cel-js$': '<rootDir>/test/cel-js.stub.ts' },
1040
+ ```
1041
+
922
1042
  ## Database Setup
923
1043
 
1044
+ ### Database prerequisites
1045
+
1046
+ BPM's first migration enables two PostgreSQL extensions — `uuid-ossp` for
1047
+ `uuid_generate_v4()` defaults and `ltree` for the org unit `path` column:
1048
+
1049
+ ```sql
1050
+ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
1051
+ CREATE EXTENSION IF NOT EXISTS "ltree";
1052
+ ```
1053
+
1054
+ `CREATE EXTENSION` needs the CREATE privilege **on the database**, which a
1055
+ least-privilege application role normally does not have — including on Rytass
1056
+ platforms, where that privilege is revoked by convention. Have a superuser,
1057
+ the database owner, or `rds_superuser` run the two statements once before the
1058
+ first migration run.
1059
+
1060
+ PostgreSQL itself returns early from `CREATE EXTENSION IF NOT EXISTS` when the
1061
+ extension is present, so a least-privilege role runs migrations fine once a DBA
1062
+ has installed them. What the migration adds is the other case: when they are
1063
+ missing and the role cannot create them, it stops with the SQL above and who
1064
+ needs to run it, rather than a bare `42501` that says nothing about needing a
1065
+ DBA.
1066
+
1067
+ The migration's `down()` is deliberately a no-op — the extensions may predate
1068
+ BPM and other schemas in the same database may depend on them.
1069
+
924
1070
  The package exports helpers for Vault-backed TypeORM setup:
925
1071
 
926
1072
  ```ts
@@ -1521,14 +1667,25 @@ npm publish --access public
1521
1667
 
1522
1668
  ## Production Notes
1523
1669
 
1524
- - Replace all local fallback secrets before production.
1670
+ - **BREAKING (upgrade note).** Replace all local fallback secrets before
1671
+ production. Under `NODE_ENV=production`, `attachmentSignedUrlSecret` is now
1672
+ enforced: BPM refuses to start rather than sign attachment URLs with the
1673
+ value published in this package. `BPMRootModule` mounts `AttachmentModule`
1674
+ unconditionally, so this applies **even to a host that never serves
1675
+ attachments** — an existing production deployment that never set the secret
1676
+ will fail to boot after upgrading. Set the secret, or set
1677
+ `attachmentAllowInsecureSignedUrlSecret: true` to acknowledge that the
1678
+ signing key is public and boot anyway. Never set that flag on anything
1679
+ serving real attachments.
1525
1680
  - Use a production storage adapter instead of local filesystem storage.
1526
1681
  - Keep old signature keys available for verification after key rotation.
1527
1682
  - Keep in-process schedulers disabled in API replicas unless a dedicated worker
1528
1683
  is not available.
1529
1684
  - Do not enable TypeORM `synchronize` in production.
1530
1685
  - Ensure GraphQL auth context is available for protected operations.
1531
- - Run migrations before serving traffic with a new package version.
1686
+ - Run migrations before serving traffic with a new package version, and
1687
+ install the PostgreSQL extensions listed under "Database prerequisites"
1688
+ once, with a privileged role, before the first run.
1532
1689
 
1533
1690
  ## License
1534
1691
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rytass/bpm-core-nestjs-module",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Embeddable NestJS BPM approval workflow module: workflow engine, approval templates, forms, organization/member contracts, attachments, signatures, notifications, delegation, and TypeORM migrations.",
5
5
  "keywords": [
6
6
  "bpm",
@@ -29,7 +29,7 @@
29
29
  "access": "public"
30
30
  },
31
31
  "engines": {
32
- "node": ">=20.0.0"
32
+ "node": ">=20.19.0"
33
33
  },
34
34
  "type": "commonjs",
35
35
  "main": "./src/index.js",
@@ -155,7 +155,7 @@
155
155
  "@nestjs/core": ">=10.0.0",
156
156
  "@nestjs/graphql": ">=12.0.0",
157
157
  "@nestjs/typeorm": ">=10.0.0",
158
- "@rytass/bpm-core-shared": "^0.12.0",
158
+ "@rytass/bpm-core-shared": "^0.13.0",
159
159
  "@rytass/secret-adapter-vault-nestjs": ">=0.4.5",
160
160
  "express": ">=4.0.0",
161
161
  "graphql": ">=16.0.0",
@@ -12,6 +12,17 @@ export interface BPMRootAttachmentOptions {
12
12
  * signed attachment URLs. Defaults to `/attachments`.
13
13
  */
14
14
  readonly attachmentRoutePrefix?: string | null;
15
+ /**
16
+ * Opt-in escape hatch that lets a `NODE_ENV=production` process boot while
17
+ * still signing attachment URLs with the built-in development secret.
18
+ *
19
+ * Without it, a production process that never set
20
+ * `attachmentSignedUrlSecret` refuses to start. Set this only for a
21
+ * throwaway environment that happens to run with `NODE_ENV=production` and
22
+ * serves no real attachments — the built-in value is published in this
23
+ * package, so anyone can forge a signed attachment URL against it.
24
+ */
25
+ readonly attachmentAllowInsecureSignedUrlSecret?: boolean;
15
26
  /**
16
27
  * HMAC secret used to sign attachment download and preview tokens.
17
28
  */
@@ -14,12 +14,27 @@ exports.DEFAULT_BPM_ATTACHMENT_OPTIONS = {
14
14
  function resolveBPMAttachmentOptions(options = {}) {
15
15
  const resolvedSignedUrlSecret = normalizeText(options.attachmentSignedUrlSecret) ??
16
16
  exports.DEFAULT_BPM_ATTACHMENT_OPTIONS.signedUrlSecret;
17
- // Warn everywhere except an explicit local development run. Gating this on
18
- // `NODE_ENV === 'production'` meant a staging host that never set the variable
19
- // signed attachment URLs with a constant published in this package — and said
20
- // nothing about it. One extra line in a developer's console is the cheaper
21
- // trade.
22
- if (resolvedSignedUrlSecret === exports.DEFAULT_BPM_ATTACHMENT_OPTIONS.signedUrlSecret &&
17
+ const usesBuiltInSecret = resolvedSignedUrlSecret === exports.DEFAULT_BPM_ATTACHMENT_OPTIONS.signedUrlSecret;
18
+ // A console warning is the wrong instrument for a published constant that
19
+ // makes every signed attachment URL forgeable: in a container it scrolls past
20
+ // with the boot log and nobody reads it again. Under `NODE_ENV=production`
21
+ // the process refuses to start instead, and a host that genuinely wants the
22
+ // development value there has to say so.
23
+ if (usesBuiltInSecret &&
24
+ process.env.NODE_ENV === 'production' &&
25
+ options.attachmentAllowInsecureSignedUrlSecret !== true) {
26
+ throw new Error([
27
+ '[@rytass/bpm-core-nestjs-module] attachmentSignedUrlSecret is unset, so BPM would sign attachment URLs with the built-in local development value that ships in this package — anyone could forge one.',
28
+ 'Set BPMRootModuleOptions.attachmentSignedUrlSecret to a strong secret.',
29
+ 'If this service never serves attachments, BPM still mounts AttachmentModule, so set attachmentAllowInsecureSignedUrlSecret: true to acknowledge that the signing key is public and boot anyway.',
30
+ ].join(' '));
31
+ }
32
+ // Outside production, still warn everywhere except an explicit local
33
+ // development run. Gating the warning on production alone meant a staging
34
+ // host that never set the variable signed attachment URLs with the published
35
+ // constant — and said nothing about it. One extra line in a developer's
36
+ // console is the cheaper trade.
37
+ if (usesBuiltInSecret &&
23
38
  process.env.NODE_ENV !== 'development' &&
24
39
  process.env.NODE_ENV !== 'test') {
25
40
  // eslint-disable-next-line no-console
@@ -1 +1 @@
1
- {"version":3,"file":"attachment-options.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/attachment/attachment-options.ts"],"names":[],"mappings":";;;AAoDA,kEAmCC;AAQD,0EAMC;AA5DY,QAAA,sBAAsB,GACjC,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAEtB,QAAA,8BAA8B,GAAiC;IAC1E,aAAa,EAAE,wBAAwB;IACvC,WAAW,EAAE,cAAc;IAC3B,eAAe,EAAE,sCAAsC;IACvD,mBAAmB,EAAE,GAAG;IACxB,iBAAiB,EAAE,OAAO;CAC3B,CAAC;AAEF,SAAgB,2BAA2B,CACzC,UAAoC,EAAE;IAEtC,MAAM,uBAAuB,GAC3B,aAAa,CAAC,OAAO,CAAC,yBAAyB,CAAC;QAChD,sCAA8B,CAAC,eAAe,CAAC;IAEjD,2EAA2E;IAC3E,+EAA+E;IAC/E,8EAA8E;IAC9E,2EAA2E;IAC3E,SAAS;IACT,IACE,uBAAuB,KAAK,sCAA8B,CAAC,eAAe;QAC1E,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa;QACtC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAC/B,CAAC;QACD,sCAAsC;QACtC,OAAO,CAAC,IAAI,CACV,0QAA0Q,CAC3Q,CAAC;IACJ,CAAC;IAED,OAAO;QACL,aAAa,EAAE,sBAAsB,CAAC,OAAO,CAAC,uBAAuB,CAAC;QACtE,WAAW,EAAE,oBAAoB,CAAC,OAAO,CAAC,qBAAqB,CAAC;QAChE,eAAe,EAAE,uBAAuB;QACxC,mBAAmB,EAAE,wBAAwB,CAC3C,OAAO,CAAC,6BAA6B,EACrC,sCAA8B,CAAC,mBAAmB,CACnD;QACD,iBAAiB,EACf,aAAa,CAAC,OAAO,CAAC,2BAA2B,CAAC;YAClD,sCAA8B,CAAC,iBAAiB;KACnD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,+BAA+B,CAC7C,KAAgC;IAEhC,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAErD,OAAO,gBAAgB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAgC;IAC9D,MAAM,eAAe,GACnB,aAAa,CAAC,KAAK,CAAC,IAAI,sCAA8B,CAAC,aAAa,CAAC;IAEvE,OAAO,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAgC;IAC5D,MAAM,eAAe,GACnB,aAAa,CAAC,KAAK,CAAC,IAAI,sCAA8B,CAAC,WAAW,CAAC;IACrE,MAAM,gBAAgB,GAAG,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC;QACtD,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC;IAE1B,OAAO,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,aAAa,CAAC,KAAgC;IACrD,MAAM,YAAY,GAAG,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAEzC,OAAO,YAAY,IAAI,IAAI,CAAC;AAC9B,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAyB,EACzB,QAAgB;IAEhB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACxE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"attachment-options.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/attachment/attachment-options.ts"],"names":[],"mappings":"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"}
@@ -3,3 +3,4 @@ export * from './attachment-storage.provider';
3
3
  export * from './attachment-storage.token';
4
4
  export * from './attachment.module';
5
5
  export * from './attachment.service';
6
+ export * from './dto/upload-attachment.input';
@@ -6,4 +6,5 @@ tslib_1.__exportStar(require("./attachment-storage.provider"), exports);
6
6
  tslib_1.__exportStar(require("./attachment-storage.token"), exports);
7
7
  tslib_1.__exportStar(require("./attachment.module"), exports);
8
8
  tslib_1.__exportStar(require("./attachment.service"), exports);
9
+ tslib_1.__exportStar(require("./dto/upload-attachment.input"), exports);
9
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/attachment/index.ts"],"names":[],"mappings":";;;AAAA,+DAAqC;AACrC,wEAA8C;AAC9C,qEAA2C;AAC3C,8DAAoC;AACpC,+DAAqC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/attachment/index.ts"],"names":[],"mappings":";;;AAAA,+DAAqC;AACrC,wEAA8C;AAC9C,qEAA2C;AAC3C,8DAAoC;AACpC,+DAAqC;AACrC,wEAA8C"}
@@ -2,6 +2,7 @@ import { DynamicModule, InjectionToken, Provider } from '@nestjs/common';
2
2
  import { ModuleMetadata } from '@nestjs/common/interfaces';
3
3
  import { BPMRootAttachmentOptions } from '../attachment/attachment-options';
4
4
  import { AttachmentStorage } from '../attachment/attachment-storage.token';
5
+ import { BPMResolverMetadataFactory } from '../bpm-auth/bpm-resolver-metadata';
5
6
  import { BPMAuthModuleOptions } from '../bpm-auth/bpm-auth.options';
6
7
  import { BPMBusinessCalendar } from '../calendar/business-calendar.token';
7
8
  import { BPMFormDataSourceRegistry } from '../form-data-source';
@@ -61,6 +62,22 @@ export interface BPMRootModuleOptions extends Pick<ModuleMetadata, 'imports'>, B
61
62
  * `@rytass/bpm-core-nestjs-module` to a specific external identity system.
62
63
  */
63
64
  readonly memberResolverProvider: Provider<BPMMemberResolver>;
65
+ /**
66
+ * Host-supplied factory that stamps the host's own route metadata onto every
67
+ * BPM GraphQL handler.
68
+ *
69
+ * Needed when the host installs a **global** guard that judges routes by
70
+ * metadata BPM knows nothing about. `@rytass/member-base-nestjs-module`
71
+ * registers a `CasbinGuard` that rejects any route without
72
+ * `@CheckPermission` metadata, so without this every BPM query and mutation
73
+ * fails with `Route has no permission metadata` before BPM's own guards run.
74
+ *
75
+ * The factory is called once per handler at module wiring time, receives the
76
+ * authority BPM itself requires (`admin`, `designer`, `authenticated`) plus
77
+ * the resolver and method names, and returns the metadata to write. See
78
+ * `BPMResolverMetadataFactory`.
79
+ */
80
+ readonly resolverMetadataFactory?: BPMResolverMetadataFactory;
64
81
  /**
65
82
  * Host-provided dispatcher for executable workflow service tasks.
66
83
  *
@@ -116,6 +133,15 @@ export interface BPMRootModuleAsyncOptions extends Pick<ModuleMetadata, 'imports
116
133
  * through its Nest `useFactory`, `useClass`, or `useExisting` definition.
117
134
  */
118
135
  readonly formDataSourceRegistryProvider?: Provider<BPMFormDataSourceRegistry>;
136
+ /**
137
+ * Whether BPM registers its identity GraphQL queries. See
138
+ * `BPMRootIdentityOptions.identityRegisterResolvers`.
139
+ *
140
+ * Set at module wiring time, like `attachmentRoutePrefix`, because Nest
141
+ * collects resolver providers while building the schema — before the
142
+ * `useFactory` below has run.
143
+ */
144
+ readonly identityRegisterResolvers?: boolean;
119
145
  /**
120
146
  * Providers injected into `useFactory`.
121
147
  *
@@ -131,6 +157,15 @@ export interface BPMRootModuleAsyncOptions extends Pick<ModuleMetadata, 'imports
131
157
  * `@rytass/bpm-core-nestjs-module` to a specific external identity system.
132
158
  */
133
159
  readonly memberResolverProvider: Provider<BPMMemberResolver>;
160
+ /**
161
+ * Host-supplied factory that stamps the host's own route metadata onto every
162
+ * BPM GraphQL handler. See
163
+ * `BPMRootModuleOptions.resolverMetadataFactory`.
164
+ *
165
+ * Read at module wiring time rather than from `useFactory`, because Nest
166
+ * builds the resolver metadata before any async factory has run.
167
+ */
168
+ readonly resolverMetadataFactory?: BPMResolverMetadataFactory;
134
169
  /**
135
170
  * Host-provided dispatcher for executable workflow service tasks.
136
171
  *
@@ -6,6 +6,7 @@ const tslib_1 = require("tslib");
6
6
  const common_1 = require("@nestjs/common");
7
7
  const attachment_module_1 = require("../attachment/attachment.module");
8
8
  const bpm_auth_module_1 = require("../bpm-auth/bpm-auth.module");
9
+ const bpm_resolver_metadata_1 = require("../bpm-auth/bpm-resolver-metadata");
9
10
  const calendar_module_1 = require("../calendar/calendar.module");
10
11
  const delegation_module_1 = require("../delegation/delegation.module");
11
12
  const form_module_1 = require("../form/form.module");
@@ -53,6 +54,9 @@ let BPMRootModule = BPMRootModule_1 = class BPMRootModule {
53
54
  * wiring time (no async secret loading needed).
54
55
  */
55
56
  static forRoot(options) {
57
+ if (options.resolverMetadataFactory) {
58
+ (0, bpm_resolver_metadata_1.applyBPMResolverMetadata)(options.resolverMetadataFactory);
59
+ }
56
60
  const featureModules = createBPMFeatureModules(options);
57
61
  return {
58
62
  exports: [...featureModules],
@@ -73,6 +77,9 @@ let BPMRootModule = BPMRootModule_1 = class BPMRootModule {
73
77
  * during application bootstrap.
74
78
  */
75
79
  static forRootAsync(options) {
80
+ if (options.resolverMetadataFactory) {
81
+ (0, bpm_resolver_metadata_1.applyBPMResolverMetadata)(options.resolverMetadataFactory);
82
+ }
76
83
  const authOptions = {
77
84
  imports: options.imports,
78
85
  inject: options.inject,
@@ -109,6 +116,7 @@ let BPMRootModule = BPMRootModule_1 = class BPMRootModule {
109
116
  }),
110
117
  bpm_auth_module_1.BPMAuthModule.forRootAsync(authOptions),
111
118
  identity_module_1.IdentityModule.forRootAsync({
119
+ identityRegisterResolvers: options.identityRegisterResolvers,
112
120
  imports: options.imports,
113
121
  inject: options.inject,
114
122
  memberResolverProvider: options.memberResolverProvider,
@@ -1 +1 @@
1
- {"version":3,"file":"bpm-root.module.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm/bpm-root.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bpm-root.module.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm/bpm-root.module.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ const tslib_1 = require("tslib");
7
7
  const common_1 = require("@nestjs/common");
8
8
  const bpm_auth_context_extractor_1 = require("./bpm-auth-context.extractor");
9
9
  const bpm_auth_guard_1 = require("./bpm-auth.guard");
10
+ const bpm_resolver_access_decorator_1 = require("./bpm-resolver-access.decorator");
10
11
  const ADMIN_PERMISSIONS = new Set([
11
12
  'bpm:*',
12
13
  'bpm:admin',
@@ -51,9 +52,9 @@ exports.BPMDesignerGuard = BPMDesignerGuard;
51
52
  exports.BPMDesignerGuard = BPMDesignerGuard = tslib_1.__decorate([
52
53
  (0, common_1.Injectable)()
53
54
  ], BPMDesignerGuard);
54
- const BPMAdminOnly = () => (0, common_1.UseGuards)(bpm_auth_guard_1.BPMAuthenticatedGuard, BPMAdminGuard);
55
+ const BPMAdminOnly = () => (0, bpm_resolver_access_decorator_1.withBPMResolverAccess)('admin', (0, common_1.UseGuards)(bpm_auth_guard_1.BPMAuthenticatedGuard, BPMAdminGuard));
55
56
  exports.BPMAdminOnly = BPMAdminOnly;
56
- const BPMDesignerOnly = () => (0, common_1.UseGuards)(bpm_auth_guard_1.BPMAuthenticatedGuard, BPMDesignerGuard);
57
+ const BPMDesignerOnly = () => (0, bpm_resolver_access_decorator_1.withBPMResolverAccess)('designer', (0, common_1.UseGuards)(bpm_auth_guard_1.BPMAuthenticatedGuard, BPMDesignerGuard));
57
58
  exports.BPMDesignerOnly = BPMDesignerOnly;
58
59
  function isBPMAdmin(authContext) {
59
60
  return (authContext.roles.includes('BPM_ADMIN') ||
@@ -1 +1 @@
1
- {"version":3,"file":"bpm-auth.authorization.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm-auth/bpm-auth.authorization.ts"],"names":[],"mappings":";;;AA8DA,gCAOC;AAED,sCAQC;;AA/ED,2CAMwB;AAExB,6EAAqE;AACrE,qDAAyD;AAEzD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,OAAO;IACP,WAAW;IACX,WAAW;IACX,aAAa;CACd,CAAC,CAAC;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,OAAO;IACP,WAAW;IACX,WAAW;IACX,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,iBAAiB;IACjB,qBAAqB;IACrB,iBAAiB;IACjB,qBAAqB;CACtB,CAAC,CAAC;AAGI,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,WAAW,CAAC,OAAyB;QACnC,MAAM,WAAW,GAAG,IAAA,kDAAqB,EAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,WAAW,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,2BAAkB,CAAC,kCAAkC,CAAC,CAAC;IACnE,CAAC;CACF,CAAA;AAVY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAUzB;AAGM,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,WAAW,CAAC,OAAyB;QACnC,MAAM,WAAW,GAAG,IAAA,kDAAqB,EAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,WAAW,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,2BAAkB,CAAC,qCAAqC,CAAC,CAAC;IACtE,CAAC;CACF,CAAA;AAVY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;GACA,gBAAgB,CAU5B;AAEM,MAAM,YAAY,GAAG,GAAqC,EAAE,CACjE,IAAA,kBAAS,EAAC,sCAAqB,EAAE,aAAa,CAAC,CAAC;AADrC,QAAA,YAAY,gBACyB;AAE3C,MAAM,eAAe,GAAG,GAAqC,EAAE,CACpE,IAAA,kBAAS,EAAC,sCAAqB,EAAE,gBAAgB,CAAC,CAAC;AADxC,QAAA,eAAe,mBACyB;AAErD,SAAgB,UAAU,CAAC,WAA2B;IACpD,OAAO,CACL,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;QACvC,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAC1C,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAClC,CACF,CAAC;AACJ,CAAC;AAED,SAAgB,aAAa,CAAC,WAA2B;IACvD,OAAO,CACL,UAAU,CAAC,WAAW,CAAC;QACvB,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC1C,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAC1C,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,CACrC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"bpm-auth.authorization.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm-auth/bpm-auth.authorization.ts"],"names":[],"mappings":";;;AAqEA,gCAOC;AAED,sCAQC;;AAtFD,2CAMwB;AAExB,6EAAqE;AACrE,qDAAyD;AACzD,mFAAwE;AAExE,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,OAAO;IACP,WAAW;IACX,WAAW;IACX,aAAa;CACd,CAAC,CAAC;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,OAAO;IACP,WAAW;IACX,WAAW;IACX,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,iBAAiB;IACjB,qBAAqB;IACrB,iBAAiB;IACjB,qBAAqB;CACtB,CAAC,CAAC;AAGI,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,WAAW,CAAC,OAAyB;QACnC,MAAM,WAAW,GAAG,IAAA,kDAAqB,EAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,WAAW,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,2BAAkB,CAAC,kCAAkC,CAAC,CAAC;IACnE,CAAC;CACF,CAAA;AAVY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAUzB;AAGM,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,WAAW,CAAC,OAAyB;QACnC,MAAM,WAAW,GAAG,IAAA,kDAAqB,EAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,WAAW,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,2BAAkB,CAAC,qCAAqC,CAAC,CAAC;IACtE,CAAC;CACF,CAAA;AAVY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;GACA,gBAAgB,CAU5B;AAEM,MAAM,YAAY,GAAG,GAAqC,EAAE,CACjE,IAAA,qDAAqB,EACnB,OAAO,EACP,IAAA,kBAAS,EAAC,sCAAqB,EAAE,aAAa,CAAC,CAChD,CAAC;AAJS,QAAA,YAAY,gBAIrB;AAEG,MAAM,eAAe,GAAG,GAAqC,EAAE,CACpE,IAAA,qDAAqB,EACnB,UAAU,EACV,IAAA,kBAAS,EAAC,sCAAqB,EAAE,gBAAgB,CAAC,CACnD,CAAC;AAJS,QAAA,eAAe,mBAIxB;AAEJ,SAAgB,UAAU,CAAC,WAA2B;IACpD,OAAO,CACL,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC;QACvC,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAC1C,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAClC,CACF,CAAC;AACJ,CAAC;AAED,SAAgB,aAAa,CAAC,WAA2B;IACvD,OAAO,CACL,UAAU,CAAC,WAAW,CAAC;QACvB,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC1C,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAC1C,oBAAoB,CAAC,GAAG,CAAC,UAAU,CAAC,CACrC,CACF,CAAC;AACJ,CAAC"}
@@ -4,7 +4,8 @@ exports.BPMCurrentMemberId = exports.BPMCurrentAuthContext = exports.BPMAuthenti
4
4
  const common_1 = require("@nestjs/common");
5
5
  const bpm_auth_guard_1 = require("./bpm-auth.guard");
6
6
  const bpm_auth_context_extractor_1 = require("./bpm-auth-context.extractor");
7
- const BPMAuthenticated = () => (0, common_1.UseGuards)(bpm_auth_guard_1.BPMAuthenticatedGuard);
7
+ const bpm_resolver_access_decorator_1 = require("./bpm-resolver-access.decorator");
8
+ const BPMAuthenticated = () => (0, bpm_resolver_access_decorator_1.withBPMResolverAccess)('authenticated', (0, common_1.UseGuards)(bpm_auth_guard_1.BPMAuthenticatedGuard));
8
9
  exports.BPMAuthenticated = BPMAuthenticated;
9
10
  exports.BPMCurrentAuthContext = (0, common_1.createParamDecorator)((_data, context) => (0, bpm_auth_context_extractor_1.extractBPMAuthContext)(context));
10
11
  exports.BPMCurrentMemberId = (0, common_1.createParamDecorator)((_data, context) => (0, bpm_auth_context_extractor_1.extractBPMAuthContext)(context)?.memberId ?? null);
@@ -1 +1 @@
1
- {"version":3,"file":"bpm-auth.decorators.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm-auth/bpm-auth.decorators.ts"],"names":[],"mappings":";;;AAAA,2CAIwB;AACxB,qDAAyD;AACzD,6EAAqE;AAE9D,MAAM,gBAAgB,GAAG,GAAqC,EAAE,CACrE,IAAA,kBAAS,EAAC,sCAAqB,CAAC,CAAC;AADtB,QAAA,gBAAgB,oBACM;AAEtB,QAAA,qBAAqB,GAAG,IAAA,6BAAoB,EACvD,CAAC,KAAc,EAAE,OAAyB,EAAE,EAAE,CAAC,IAAA,kDAAqB,EAAC,OAAO,CAAC,CAC9E,CAAC;AAEW,QAAA,kBAAkB,GAAG,IAAA,6BAAoB,EACpD,CAAC,KAAc,EAAE,OAAyB,EAAE,EAAE,CAC5C,IAAA,kDAAqB,EAAC,OAAO,CAAC,EAAE,QAAQ,IAAI,IAAI,CACnD,CAAC"}
1
+ {"version":3,"file":"bpm-auth.decorators.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm-auth/bpm-auth.decorators.ts"],"names":[],"mappings":";;;AAAA,2CAIwB;AACxB,qDAAyD;AACzD,6EAAqE;AACrE,mFAAwE;AAEjE,MAAM,gBAAgB,GAAG,GAAqC,EAAE,CACrE,IAAA,qDAAqB,EAAC,eAAe,EAAE,IAAA,kBAAS,EAAC,sCAAqB,CAAC,CAAC,CAAC;AAD9D,QAAA,gBAAgB,oBAC8C;AAE9D,QAAA,qBAAqB,GAAG,IAAA,6BAAoB,EACvD,CAAC,KAAc,EAAE,OAAyB,EAAE,EAAE,CAAC,IAAA,kDAAqB,EAAC,OAAO,CAAC,CAC9E,CAAC;AAEW,QAAA,kBAAkB,GAAG,IAAA,6BAAoB,EACpD,CAAC,KAAc,EAAE,OAAyB,EAAE,EAAE,CAC5C,IAAA,kDAAqB,EAAC,OAAO,CAAC,EAAE,QAAQ,IAAI,IAAI,CACnD,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { BPMResolverAccessLevel } from './bpm-resolver-metadata';
2
+ type BPMResolverDecorator = ClassDecorator & MethodDecorator;
3
+ /**
4
+ * Wraps one of BPM's authorization decorators so the decorated class or method
5
+ * also lands in the resolver registry.
6
+ *
7
+ * The registry is what makes `BPMRootModuleOptions.resolverMetadataFactory`
8
+ * possible: a decorator runs when the class is defined, long before any module
9
+ * option exists, so the only way a host can reach these handlers is for BPM to
10
+ * remember them and replay the host's factory later.
11
+ */
12
+ export declare function withBPMResolverAccess(access: BPMResolverAccessLevel, decorate: BPMResolverDecorator): BPMResolverDecorator;
13
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withBPMResolverAccess = withBPMResolverAccess;
4
+ const bpm_resolver_metadata_1 = require("./bpm-resolver-metadata");
5
+ /**
6
+ * Wraps one of BPM's authorization decorators so the decorated class or method
7
+ * also lands in the resolver registry.
8
+ *
9
+ * The registry is what makes `BPMRootModuleOptions.resolverMetadataFactory`
10
+ * possible: a decorator runs when the class is defined, long before any module
11
+ * option exists, so the only way a host can reach these handlers is for BPM to
12
+ * remember them and replay the host's factory later.
13
+ */
14
+ function withBPMResolverAccess(access, decorate) {
15
+ const applyDecorator = decorate;
16
+ const decorator = (target, propertyKey, descriptor) => {
17
+ if (propertyKey === undefined) {
18
+ (0, bpm_resolver_metadata_1.registerBPMResolverClassAccess)(target, access);
19
+ }
20
+ else {
21
+ (0, bpm_resolver_metadata_1.registerBPMResolverMethodAccess)(target.constructor, String(propertyKey), access);
22
+ }
23
+ return applyDecorator(target, propertyKey, descriptor);
24
+ };
25
+ return decorator;
26
+ }
27
+ //# sourceMappingURL=bpm-resolver-access.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bpm-resolver-access.decorator.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/bpm-auth/bpm-resolver-access.decorator.ts"],"names":[],"mappings":";;AAuBA,sDAyBC;AAhDD,mEAIiC;AAUjC;;;;;;;;GAQG;AACH,SAAgB,qBAAqB,CACnC,MAA8B,EAC9B,QAA8B;IAE9B,MAAM,cAAc,GAAG,QAAuC,CAAC;IAE/D,MAAM,SAAS,GAAqB,CAClC,MAAM,EACN,WAAW,EACX,UAAU,EACJ,EAAE;QACR,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,IAAA,sDAA8B,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,IAAA,uDAA+B,EAC5B,MAA2C,CAAC,WAAW,EACxD,MAAM,CAAC,WAAW,CAAC,EACnB,MAAM,CACP,CAAC;QACJ,CAAC;QAED,OAAO,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC;IAEF,OAAO,SAA4C,CAAC;AACtD,CAAC"}