@things-factory/auth-base 10.1.250 → 10.1.256

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.
@@ -6,6 +6,7 @@ const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
6
6
  const env_1 = require("@things-factory/env");
7
7
  const passkey_js_1 = require("../controllers/passkey.js");
8
8
  const confirm_identity_js_1 = require("../controllers/confirm-identity.js");
9
+ const auth_error_js_1 = require("../errors/auth-error.js");
9
10
  const signin_js_1 = require("../controllers/signin.js");
10
11
  const identity_confirmation_js_1 = require("../service/identity-confirmation/identity-confirmation.js");
11
12
  const access_token_cookie_js_1 = require("../utils/access-token-cookie.js");
@@ -86,15 +87,27 @@ exports.webAuthnGlobalPublicRouter.get('/auth/signin-webauthn/challenge', async
86
87
  (0, passkey_js_1.rememberChallenge)(context, options.challenge);
87
88
  context.body = options;
88
89
  });
89
- /* The body is `{ response, redirectTo }`. */
90
+ /*
91
+ * The sign-in screen posts this as a form, the way it posts a password: `response` is the browser's
92
+ * answer as JSON text, `redirectTo` where to go after. So a refusal takes the password's way too -
93
+ * `authenticate401Middleware` answers the page with the one that follows from the code (a locked
94
+ * account to the activate page, which sends the unlock mail again), never a page inside a fetch body.
95
+ */
90
96
  exports.webAuthnGlobalPublicRouter.post('/auth/signin-webauthn', async (context) => {
91
97
  const challenge = (0, passkey_js_1.takeChallenge)(context);
92
98
  const { response, redirectTo } = context.request.body || {};
93
99
  const { domain } = context.state;
94
- const { token } = await (0, passkey_js_1.signinWithPasskey)(response, challenge, (0, passkey_js_1.siteOf)(context), context);
100
+ const { token } = await (0, passkey_js_1.signinWithPasskey)(passkeyAnswerOf(response), challenge, (0, passkey_js_1.siteOf)(context), context);
95
101
  (0, access_token_cookie_js_1.setAccessTokenCookie)(context, token);
96
- /* A two-step exchange run by fetch in the browser cannot follow a 3xx, so the next address is data. */
97
- const redirectURL = `/auth/checkin${domain ? '/' + domain.subdomain : ''}?redirect_to=${encodeURIComponent(redirectTo || '/')}`;
98
- context.body = { redirectURL, verified: true };
102
+ context.redirect(`/auth/checkin${domain ? '/' + domain.subdomain : ''}?redirect_to=${encodeURIComponent(redirectTo || '/')}`);
99
103
  });
104
+ /* The browser's answer from the form field. Text that is not one is a failed verification, like any other bad answer. */
105
+ function passkeyAnswerOf(field) {
106
+ try {
107
+ return JSON.parse(String(field));
108
+ }
109
+ catch {
110
+ throw new auth_error_js_1.AuthError({ errorCode: auth_error_js_1.AuthError.ERROR_CODES.AUTHN_VERIFICATION_FAILED, detail: { reason: 'unreadable answer' } });
111
+ }
112
+ }
100
113
  //# sourceMappingURL=webauthn-router.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webauthn-router.js","sourceRoot":"","sources":["../../server/router/webauthn-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAC/B,6CAAwD;AAExD,0DAUkC;AAClC,4EAAoE;AACpE,wDAAyD;AACzD,wGAA8G;AAC9G,4EAAsE;AACtE,8EAAyE;AAE5D,QAAA,0BAA0B,GAAG,IAAI,oBAAM,EAAE,CAAA;AACzC,QAAA,2BAA2B,GAAG,IAAI,oBAAM,EAAE,CAAA;AAEvD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,gBAAiB,CAAA;AAE1C,MAAM,0BAA0B,GAAG,YAAM,CAAC,GAAG,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAA;AACvF,MAAM,SAAS,GAAG,YAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;AAErD;;;GAGG;AAEH,6EAA6E;AAC7E,mCAA2B,CAAC,GAAG,CAAC,iCAAiC,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACjF,MAAM,OAAO,GAAG,MAAM,IAAA,4BAAe,EAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAA,mBAAM,EAAC,OAAO,CAAC,CAAC,CAAA;IAE1E,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,GAAG,GAAG,CAAA;QACpB,OAAO,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,mDAAmD,EAAE,CAAA;QAC7E,OAAM;IACR,CAAC;IAED,IAAA,8BAAiB,EAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAC7C,OAAO,CAAC,IAAI,GAAG,OAAO,CAAA;AACxB,CAAC,CAAC,CAAA;AAEF,2FAA2F;AAC3F,mCAA2B,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACxE,MAAM,SAAS,GAAG,IAAA,0BAAa,EAAC,OAAO,CAAC,CAAA;IACxC,MAAM,IAAA,qCAAe,EAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,IAAA,gCAAmB,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,IAAA,mBAAM,EAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAE9H,OAAO,CAAC,IAAI,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,qCAAqC,EAAE,CAAA;AACnF,CAAC,CAAC,CAAA;AAEF,gFAAgF;AAChF,mCAA2B,CAAC,IAAI,CAAC,wBAAwB,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACzE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAA;IAC/C,MAAM,IAAA,qCAAe,EAAC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,IAAA,0BAAc,EAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAA;IAEzG,OAAO,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;AACpC,CAAC,CAAC,CAAA;AAEF,mHAAmH;AACnH,mCAA2B,CAAC,GAAG,CAAC,wBAAwB,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACxE,OAAO,CAAC,IAAI,GAAG,EAAE,cAAc,EAAE,IAAA,yCAAc,EAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAA;AAC3G,CAAC,CAAC,CAAA;AAEF,2DAA2D;AAC3D,mCAA2B,CAAC,MAAM,CAAC,wBAAwB,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IAC3E,IAAA,6CAAkB,EAAC,OAAO,CAAC,CAAA;IAC3B,OAAO,CAAC,IAAI,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AACrC,CAAC,CAAC,CAAA;AAEF,4CAA4C;AAC5C,mCAA2B,CAAC,GAAG,CAAC,mCAAmC,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACnF,MAAM,OAAO,GAAG,MAAM,IAAA,gCAAmB,EAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAA,mBAAM,EAAC,OAAO,CAAC,CAAC,CAAA;IAEtF,IAAA,8BAAiB,EAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAC7C,OAAO,CAAC,IAAI,GAAG,OAAO,CAAA;AACxB,CAAC,CAAC,CAAA;AAEF,iGAAiG;AACjG,mCAA2B,CAAC,IAAI,CAAC,2BAA2B,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IAC5E,MAAM,SAAS,GAAG,IAAA,0BAAa,EAAC,OAAO,CAAC,CAAA;IACxC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAA;IAErD,MAAM,IAAA,4BAAe,EAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAA,mBAAM,EAAC,OAAO,CAAC,CAAC,CAAA;IAErF,OAAO,CAAC,IAAI,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AACnC,CAAC,CAAC,CAAA;AAEF;;;GAGG;AACH,mCAA2B,CAAC,GAAG,CAAC,qBAAqB,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACrE,MAAM,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE;QAChC,WAAW,EAAE,oBAAoB;QACjC,aAAa,EAAE,wBAAwB;QACvC,IAAI,EAAE;YACJ,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ;YACrC,UAAU,EAAE,IAAA,gDAAsB,EAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC;YACtE,0BAA0B;YAC1B,SAAS;SACV;KACF,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,aAAa;AACb,kCAA0B,CAAC,GAAG,CAAC,iCAAiC,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IAChF,MAAM,OAAO,GAAG,MAAM,IAAA,0BAAa,EAAC,IAAA,mBAAM,EAAC,OAAO,CAAC,CAAC,CAAA;IAEpD,IAAA,8BAAiB,EAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAC7C,OAAO,CAAC,IAAI,GAAG,OAAO,CAAA;AACxB,CAAC,CAAC,CAAA;AAEF,6CAA6C;AAC7C,kCAA0B,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;IACvE,MAAM,SAAS,GAAG,IAAA,0BAAa,EAAC,OAAO,CAAC,CAAA;IACxC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAA;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEhC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAA,8BAAiB,EAAC,QAAQ,EAAE,SAAS,EAAE,IAAA,mBAAM,EAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAA;IACxF,IAAA,6CAAoB,EAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAEpC,uGAAuG;IACvG,MAAM,WAAW,GAAG,gBAAgB,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,kBAAkB,CAAC,UAAU,IAAI,GAAG,CAAC,EAAE,CAAA;IAE/H,OAAO,CAAC,IAAI,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AAChD,CAAC,CAAC,CAAA","sourcesContent":["import Router from 'koa-router'\nimport { appPackage, config } from '@things-factory/env'\n\nimport {\n registerPasskey,\n registrationOptions,\n rememberChallenge,\n reverifyOptions,\n reverifyWithPasskey,\n signinOptions,\n signinWithPasskey,\n siteOf,\n takeChallenge\n} from '../controllers/passkey.js'\nimport { confirmIdentity } from '../controllers/confirm-identity.js'\nimport { verifyPassword } from '../controllers/signin.js'\nimport { confirmedUntil, forgetConfirmation } from '../service/identity-confirmation/identity-confirmation.js'\nimport { setAccessTokenCookie } from '../utils/access-token-cookie.js'\nimport { sameOriginRedirectPath } from '../utils/same-origin-redirect.js'\n\nexport const webAuthnGlobalPublicRouter = new Router()\nexport const webAuthnGlobalPrivateRouter = new Router()\n\nconst { name: rpName } = appPackage as any\n\nconst disableUserFavoredLanguage = config.get('i18n/disableUserFavoredLanguage', false)\nconst languages = config.get('i18n/languages', false)\n\n/*\n * A refusal throws `AuthError`; `authenticate401Middleware` answers it with 401 and the refusal in\n * the request's language as the body. The screens read that body as the message.\n */\n\n// Confirming it is the signed-in person - only their own passkeys can answer\nwebAuthnGlobalPrivateRouter.get('/auth/verify-webauthn/challenge', async context => {\n const options = await reverifyOptions(context.state.user, siteOf(context))\n\n if (!options) {\n context.status = 400\n context.body = { error: 'No biometric credentials registered for this user' }\n return\n }\n\n rememberChallenge(context, options.challenge)\n context.body = options\n})\n\n/* A passkey that answers is also the recent confirmation a door may ask for (ADR-0168). */\nwebAuthnGlobalPrivateRouter.post('/auth/verify-webauthn', async context => {\n const challenge = takeChallenge(context)\n await confirmIdentity('passkey', context, user => reverifyWithPasskey(user, context.request.body, challenge, siteOf(context)))\n\n context.body = { verified: true, message: 'Biometric authentication successful' }\n})\n\n/* The same confirmation by password - the body is `{ password }` (ADR-0168). */\nwebAuthnGlobalPrivateRouter.post('/auth/confirm-identity', async context => {\n const { password } = context.request.body || {}\n await confirmIdentity('password', context, user => verifyPassword(user, String(password ?? ''), context))\n\n context.body = { confirmed: true }\n})\n\n/* Until when the confirmation holds - a screen puts away what it shows at that moment. Null when there is none. */\nwebAuthnGlobalPrivateRouter.get('/auth/confirm-identity', async context => {\n context.body = { confirmedUntil: confirmedUntil(context, context.state.user?.id)?.toISOString() ?? null }\n})\n\n/* Letting the confirmation go before it ends by itself. */\nwebAuthnGlobalPrivateRouter.delete('/auth/confirm-identity', async context => {\n forgetConfirmation(context)\n context.body = { confirmed: false }\n})\n\n// Adding a passkey for the signed-in person\nwebAuthnGlobalPrivateRouter.get('/auth/register-webauthn/challenge', async context => {\n const options = await registrationOptions(context.state.user, rpName, siteOf(context))\n\n rememberChallenge(context, options.challenge)\n context.body = options\n})\n\n/* The body is `{ response, name }` - the browser's answer, and the label the screen proposes. */\nwebAuthnGlobalPrivateRouter.post('/auth/verify-registration', async context => {\n const challenge = takeChallenge(context)\n const { response, name } = context.request.body || {}\n\n await registerPasskey(context.state.user, response, name, challenge, siteOf(context))\n\n context.body = { verified: true }\n})\n\n/*\n * After a password sign-in on the screen, before check-in: an offer to add a passkey on this device\n * (ADR-0156 decision 5). The page moves on by itself where it has nothing to offer.\n */\nwebAuthnGlobalPrivateRouter.get('/auth/passkey-offer', async context => {\n await context.render('auth-page', {\n pageElement: 'auth-passkey-offer',\n elementScript: '/auth/passkey-offer.js',\n data: {\n username: context.state.user.username,\n redirectTo: sameOriginRedirectPath(context.query.redirect_to, context),\n disableUserFavoredLanguage,\n languages\n }\n })\n})\n\n// Signing in\nwebAuthnGlobalPublicRouter.get('/auth/signin-webauthn/challenge', async context => {\n const options = await signinOptions(siteOf(context))\n\n rememberChallenge(context, options.challenge)\n context.body = options\n})\n\n/* The body is `{ response, redirectTo }`. */\nwebAuthnGlobalPublicRouter.post('/auth/signin-webauthn', async context => {\n const challenge = takeChallenge(context)\n const { response, redirectTo } = context.request.body || {}\n const { domain } = context.state\n\n const { token } = await signinWithPasskey(response, challenge, siteOf(context), context)\n setAccessTokenCookie(context, token)\n\n /* A two-step exchange run by fetch in the browser cannot follow a 3xx, so the next address is data. */\n const redirectURL = `/auth/checkin${domain ? '/' + domain.subdomain : ''}?redirect_to=${encodeURIComponent(redirectTo || '/')}`\n\n context.body = { redirectURL, verified: true }\n})\n"]}
1
+ {"version":3,"file":"webauthn-router.js","sourceRoot":"","sources":["../../server/router/webauthn-router.ts"],"names":[],"mappings":"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","sourcesContent":["import Router from 'koa-router'\nimport { appPackage, config } from '@things-factory/env'\n\nimport {\n registerPasskey,\n registrationOptions,\n rememberChallenge,\n reverifyOptions,\n reverifyWithPasskey,\n signinOptions,\n signinWithPasskey,\n siteOf,\n takeChallenge\n} from '../controllers/passkey.js'\nimport { confirmIdentity } from '../controllers/confirm-identity.js'\nimport { AuthError } from '../errors/auth-error.js'\nimport { verifyPassword } from '../controllers/signin.js'\nimport { confirmedUntil, forgetConfirmation } from '../service/identity-confirmation/identity-confirmation.js'\nimport { setAccessTokenCookie } from '../utils/access-token-cookie.js'\nimport { sameOriginRedirectPath } from '../utils/same-origin-redirect.js'\n\nexport const webAuthnGlobalPublicRouter = new Router()\nexport const webAuthnGlobalPrivateRouter = new Router()\n\nconst { name: rpName } = appPackage as any\n\nconst disableUserFavoredLanguage = config.get('i18n/disableUserFavoredLanguage', false)\nconst languages = config.get('i18n/languages', false)\n\n/*\n * A refusal throws `AuthError`; `authenticate401Middleware` answers it with 401 and the refusal in\n * the request's language as the body. The screens read that body as the message.\n */\n\n// Confirming it is the signed-in person - only their own passkeys can answer\nwebAuthnGlobalPrivateRouter.get('/auth/verify-webauthn/challenge', async context => {\n const options = await reverifyOptions(context.state.user, siteOf(context))\n\n if (!options) {\n context.status = 400\n context.body = { error: 'No biometric credentials registered for this user' }\n return\n }\n\n rememberChallenge(context, options.challenge)\n context.body = options\n})\n\n/* A passkey that answers is also the recent confirmation a door may ask for (ADR-0168). */\nwebAuthnGlobalPrivateRouter.post('/auth/verify-webauthn', async context => {\n const challenge = takeChallenge(context)\n await confirmIdentity('passkey', context, user => reverifyWithPasskey(user, context.request.body, challenge, siteOf(context)))\n\n context.body = { verified: true, message: 'Biometric authentication successful' }\n})\n\n/* The same confirmation by password - the body is `{ password }` (ADR-0168). */\nwebAuthnGlobalPrivateRouter.post('/auth/confirm-identity', async context => {\n const { password } = context.request.body || {}\n await confirmIdentity('password', context, user => verifyPassword(user, String(password ?? ''), context))\n\n context.body = { confirmed: true }\n})\n\n/* Until when the confirmation holds - a screen puts away what it shows at that moment. Null when there is none. */\nwebAuthnGlobalPrivateRouter.get('/auth/confirm-identity', async context => {\n context.body = { confirmedUntil: confirmedUntil(context, context.state.user?.id)?.toISOString() ?? null }\n})\n\n/* Letting the confirmation go before it ends by itself. */\nwebAuthnGlobalPrivateRouter.delete('/auth/confirm-identity', async context => {\n forgetConfirmation(context)\n context.body = { confirmed: false }\n})\n\n// Adding a passkey for the signed-in person\nwebAuthnGlobalPrivateRouter.get('/auth/register-webauthn/challenge', async context => {\n const options = await registrationOptions(context.state.user, rpName, siteOf(context))\n\n rememberChallenge(context, options.challenge)\n context.body = options\n})\n\n/* The body is `{ response, name }` - the browser's answer, and the label the screen proposes. */\nwebAuthnGlobalPrivateRouter.post('/auth/verify-registration', async context => {\n const challenge = takeChallenge(context)\n const { response, name } = context.request.body || {}\n\n await registerPasskey(context.state.user, response, name, challenge, siteOf(context))\n\n context.body = { verified: true }\n})\n\n/*\n * After a password sign-in on the screen, before check-in: an offer to add a passkey on this device\n * (ADR-0156 decision 5). The page moves on by itself where it has nothing to offer.\n */\nwebAuthnGlobalPrivateRouter.get('/auth/passkey-offer', async context => {\n await context.render('auth-page', {\n pageElement: 'auth-passkey-offer',\n elementScript: '/auth/passkey-offer.js',\n data: {\n username: context.state.user.username,\n redirectTo: sameOriginRedirectPath(context.query.redirect_to, context),\n disableUserFavoredLanguage,\n languages\n }\n })\n})\n\n// Signing in\nwebAuthnGlobalPublicRouter.get('/auth/signin-webauthn/challenge', async context => {\n const options = await signinOptions(siteOf(context))\n\n rememberChallenge(context, options.challenge)\n context.body = options\n})\n\n/*\n * The sign-in screen posts this as a form, the way it posts a password: `response` is the browser's\n * answer as JSON text, `redirectTo` where to go after. So a refusal takes the password's way too -\n * `authenticate401Middleware` answers the page with the one that follows from the code (a locked\n * account to the activate page, which sends the unlock mail again), never a page inside a fetch body.\n */\nwebAuthnGlobalPublicRouter.post('/auth/signin-webauthn', async context => {\n const challenge = takeChallenge(context)\n const { response, redirectTo } = context.request.body || {}\n const { domain } = context.state\n\n const { token } = await signinWithPasskey(passkeyAnswerOf(response), challenge, siteOf(context), context)\n setAccessTokenCookie(context, token)\n\n context.redirect(`/auth/checkin${domain ? '/' + domain.subdomain : ''}?redirect_to=${encodeURIComponent(redirectTo || '/')}`)\n})\n\n/* The browser's answer from the form field. Text that is not one is a failed verification, like any other bad answer. */\nfunction passkeyAnswerOf(field: unknown) {\n try {\n return JSON.parse(String(field))\n } catch {\n throw new AuthError({ errorCode: AuthError.ERROR_CODES.AUTHN_VERIFICATION_FAILED, detail: { reason: 'unreadable answer' } })\n }\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { EntityManager } from 'typeorm';
2
+ export interface WorkDoor {
3
+ /** The translation key that names the work - `work.<module>.<what>`. */
4
+ work: string;
5
+ /** The GraphQL mutation fields that do it. */
6
+ fields: readonly string[];
7
+ }
8
+ /** Declares a module's mutations that are a piece of work. A field is one work only. */
9
+ export declare function registerWorkDoors(doors: readonly WorkDoor[]): void;
10
+ /** The work a mutation field is declared as, if any. */
11
+ export declare const workOfField: (field: string) => string;
12
+ export interface WorkDone {
13
+ /** When the request was made. */
14
+ at: Date;
15
+ /** The work's translation key. */
16
+ work: string;
17
+ /** The request it was done in. */
18
+ requestId: string;
19
+ }
20
+ /** Each declared piece of work a person did in [from, to) - one per request and work, the requests that went through. */
21
+ export declare function workDoneBy(tx: EntityManager, domain: {
22
+ id: string;
23
+ }, actorId: string, from: Date, to: Date): Promise<WorkDone[]>;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.workOfField = void 0;
4
+ exports.registerWorkDoors = registerWorkDoors;
5
+ exports.workDoneBy = workDoneBy;
6
+ const typeorm_1 = require("typeorm");
7
+ const audit_action_js_1 = require("./audit-action.js");
8
+ const audit_request_js_1 = require("./audit-request.js");
9
+ const WORK = new Map();
10
+ /** Declares a module's mutations that are a piece of work. A field is one work only. */
11
+ function registerWorkDoors(doors) {
12
+ for (const door of doors)
13
+ for (const field of door.fields) {
14
+ const held = WORK.get(field);
15
+ if (held && held !== door.work)
16
+ throw new Error(`The mutation "${field}" is declared as the work "${held}" and "${door.work}".`);
17
+ WORK.set(field, door.work);
18
+ }
19
+ }
20
+ /** The work a mutation field is declared as, if any. */
21
+ const workOfField = (field) => WORK.get(field);
22
+ exports.workOfField = workOfField;
23
+ /** Each declared piece of work a person did in [from, to) - one per request and work, the requests that went through. */
24
+ async function workDoneBy(tx, domain, actorId, from, to) {
25
+ if (!WORK.size)
26
+ return [];
27
+ const requests = await tx.getRepository(audit_request_js_1.AuditRequest).find({
28
+ where: { domain: { id: domain.id }, actor: { id: actorId }, operationType: 'mutation', createdAt: (0, typeorm_1.Between)(from, new Date(to.getTime() - 1)) },
29
+ order: { createdAt: 'ASC' }
30
+ });
31
+ const declared = requests
32
+ .map(request => ({ request, works: [...new Set(String(request.fields ?? '').split(',').map(field => WORK.get(field.trim())).filter(Boolean))] }))
33
+ .filter(one => one.works.length);
34
+ if (!declared.length)
35
+ return [];
36
+ const results = await tx.getRepository(audit_action_js_1.AuditAction).find({ where: { requestId: (0, typeorm_1.In)(declared.map(one => one.request.id)), kind: 'door.result' } });
37
+ const went = new Set(results.filter(one => one.outcome === 'ok').map(one => one.requestId));
38
+ const failed = new Set(results.filter(one => one.outcome === 'error').map(one => one.requestId));
39
+ return declared
40
+ .filter(one => went.has(one.request.id) && !failed.has(one.request.id))
41
+ .flatMap(one => one.works.map(work => ({ at: one.request.createdAt, work, requestId: one.request.id })));
42
+ }
43
+ //# sourceMappingURL=audit-work.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-work.js","sourceRoot":"","sources":["../../../server/service/audit/audit-work.ts"],"names":[],"mappings":"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","sourcesContent":["import { Between, EntityManager, In } from 'typeorm'\n\nimport { AuditAction } from './audit-action.js'\nimport { AuditRequest } from './audit-request.js'\n\n/*\n * Work done through the system's doors (ADR-0185 decision 6, Q5) - read from the audit, never kept twice. A module\n * declares which of its mutations are a piece of work and under what name (\"the bank lines kept\", \"the payroll worked\n * on\"); a report of one's week reads, from the audit, how many times a person did each on each day. A mutation no\n * module declared - a save of one's own draft, a read - is not work here; nor is one that failed.\n *\n * The name is a translation key of the declaring module: the screen says it in the reader's words.\n */\n\nexport interface WorkDoor {\n /** The translation key that names the work - `work.<module>.<what>`. */\n work: string\n /** The GraphQL mutation fields that do it. */\n fields: readonly string[]\n}\n\nconst WORK = new Map<string, string>()\n\n/** Declares a module's mutations that are a piece of work. A field is one work only. */\nexport function registerWorkDoors(doors: readonly WorkDoor[]) {\n for (const door of doors)\n for (const field of door.fields) {\n const held = WORK.get(field)\n if (held && held !== door.work) throw new Error(`The mutation \"${field}\" is declared as the work \"${held}\" and \"${door.work}\".`)\n WORK.set(field, door.work)\n }\n}\n\n/** The work a mutation field is declared as, if any. */\nexport const workOfField = (field: string) => WORK.get(field)\n\nexport interface WorkDone {\n /** When the request was made. */\n at: Date\n /** The work's translation key. */\n work: string\n /** The request it was done in. */\n requestId: string\n}\n\n/** Each declared piece of work a person did in [from, to) - one per request and work, the requests that went through. */\nexport async function workDoneBy(tx: EntityManager, domain: { id: string }, actorId: string, from: Date, to: Date): Promise<WorkDone[]> {\n if (!WORK.size) return []\n const requests = await tx.getRepository(AuditRequest).find({\n where: { domain: { id: domain.id }, actor: { id: actorId }, operationType: 'mutation', createdAt: Between(from, new Date(to.getTime() - 1)) } as any,\n order: { createdAt: 'ASC' } as any\n })\n const declared = requests\n .map(request => ({ request, works: [...new Set(String(request.fields ?? '').split(',').map(field => WORK.get(field.trim())).filter(Boolean))] as string[] }))\n .filter(one => one.works.length)\n if (!declared.length) return []\n const results = await tx.getRepository(AuditAction).find({ where: { requestId: In(declared.map(one => one.request.id)), kind: 'door.result' } as any })\n const went = new Set(results.filter(one => one.outcome === 'ok').map(one => one.requestId))\n const failed = new Set(results.filter(one => one.outcome === 'error').map(one => one.requestId))\n return declared\n .filter(one => went.has(one.request.id) && !failed.has(one.request.id))\n .flatMap(one => one.works.map(work => ({ at: one.request.createdAt, work, requestId: one.request.id })))\n}\n"]}
@@ -22,6 +22,7 @@ export * from './audit/audit-action.js';
22
22
  export { registerAuditKind } from './audit/audit-kinds.js';
23
23
  export { recordAuditAction, noteAuditAction, flushAudit, type AuditActionInput } from './audit/audit-recorder.js';
24
24
  export { purgeExpiredAudit, startAuditRetention } from './audit/audit-retention.js';
25
+ export { registerWorkDoors, workOfField, workDoneBy, type WorkDoor, type WorkDone } from './audit/audit-work.js';
25
26
  export * from './web-auth-credential/web-auth-credential.js';
26
27
  export * from './domain-link/domain-link.js';
27
28
  export * from './domain-owner/domain-owner.js';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.schema = exports.subscribers = exports.entities = exports.startAuditRetention = exports.purgeExpiredAudit = exports.flushAudit = exports.noteAuditAction = exports.recordAuditAction = exports.registerAuditKind = exports.privilegeRejection = exports.privilegeOfField = exports.declarePrivileges = void 0;
3
+ exports.schema = exports.subscribers = exports.entities = exports.workDoneBy = exports.workOfField = exports.registerWorkDoors = exports.startAuditRetention = exports.purgeExpiredAudit = exports.flushAudit = exports.noteAuditAction = exports.recordAuditAction = exports.registerAuditKind = exports.privilegeRejection = exports.privilegeOfField = exports.declarePrivileges = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  /* IMPORT ENTITIES AND RESOLVERS */
6
6
  const index_js_1 = require("./access-request/index.js");
@@ -61,6 +61,10 @@ Object.defineProperty(exports, "flushAudit", { enumerable: true, get: function (
61
61
  var audit_retention_js_1 = require("./audit/audit-retention.js");
62
62
  Object.defineProperty(exports, "purgeExpiredAudit", { enumerable: true, get: function () { return audit_retention_js_1.purgeExpiredAudit; } });
63
63
  Object.defineProperty(exports, "startAuditRetention", { enumerable: true, get: function () { return audit_retention_js_1.startAuditRetention; } });
64
+ var audit_work_js_1 = require("./audit/audit-work.js");
65
+ Object.defineProperty(exports, "registerWorkDoors", { enumerable: true, get: function () { return audit_work_js_1.registerWorkDoors; } });
66
+ Object.defineProperty(exports, "workOfField", { enumerable: true, get: function () { return audit_work_js_1.workOfField; } });
67
+ Object.defineProperty(exports, "workDoneBy", { enumerable: true, get: function () { return audit_work_js_1.workDoneBy; } });
64
68
  tslib_1.__exportStar(require("./web-auth-credential/web-auth-credential.js"), exports);
65
69
  tslib_1.__exportStar(require("./domain-link/domain-link.js"), exports);
66
70
  tslib_1.__exportStar(require("./domain-owner/domain-owner.js"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,mCAAmC;AACnC,wDAAkH;AAClH,8DAGwC;AACxC,uDAA+G;AAC/G,qDAAwE;AACxE,mDAAqG;AACrG,qDAA2G;AAC3G,0DAAkF;AAClF,sDAA2G;AAC3G,+CAIyB;AACzB,6DAAsE;AACtE,+FAAsG;AACtG,kDAA+F;AAC/F,2DAAiF;AACjF,oDAAqG;AACrG,+EAA2G;AAC3G,qDAA6C;AAC7C,+CAAsF;AACtF,wDAA6E;AAC7E,+CAAsF;AACtF,6DAAqF;AACrF,8DAA+H;AAC/H,sDAAwG;AACxG,uDAA4G;AAE5G,yBAAyB;AACzB,yFAA8D;AAC9D,2EAAgD;AAChD,uEAA4C;AAC5C,mEAAwC;AACxC,mEAAwC;AACxC,yDAA8B;AAC9B,wEAA6C;AAC7C,gHAAgH;AAChH,6EAAwG;AAA/F,2HAAA,iBAAiB,OAAA;AAAE,0HAAA,gBAAgB,OAAA;AAC5C,2FAA2F;AAC3F,6EAAuE;AAA9D,4HAAA,kBAAkB,OAAA;AAG3B,2EAAgD;AAChD,uEAA4C;AAC5C,iFAAsD;AACtD,yDAA8B;AAC9B,+DAAoC;AACpC,yEAA8C;AAC9C,uEAA4C;AAC5C,iFAAsD;AACtD,qFAA0D;AAC1D,mEAAwC;AACxC,kEAAuC;AACvC,yDAA0D;AAAjD,mHAAA,iBAAiB,OAAA;AAC1B,+DAAiH;AAAxG,sHAAA,iBAAiB,OAAA;AAAE,oHAAA,eAAe,OAAA;AAAE,+GAAA,UAAU,OAAA;AACvD,iEAAmF;AAA1E,uHAAA,iBAAiB,OAAA;AAAE,yHAAA,mBAAmB,OAAA;AAC/C,uFAA4D;AAC5D,uEAA4C;AAC5C,yEAA8C;AAC9C,6EAAkD;AAElD,kBAAkB;AAClB,6EAAkD;AAClD,yEAA8C;AAC9C,6EAAkD;AAClD,uFAA4D;AAC5D,qEAA0C;AAC1C,yEAA8C;AAC9C,+DAAoC;AACpC,+DAAoC;AACpC,6EAAkD;AAClD,mFAAwD;AAE3C,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,mBAA0B;IAC7B,GAAG,mBAAoB;IACvB,GAAG,mBAAmB;IACtB,GAAG,mBAAiB;IACpB,GAAG,oBAAiB;IACpB,GAAG,oBAAY;IACf,GAAG,oBAAY;IACf,GAAG,oBAAe;IAClB,GAAG,mBAAmB;IACtB,GAAG,oBAAuB;IAC1B,GAAG,oBAAyB;IAC5B,GAAG,mBAAa;IAChB,GAAG,oBAAyB;IAC5B,GAAG,oBAAkB;IACrB,GAAG,oBAAmB;IACtB,GAAG,mBAAqB;CACzB,CAAA;AAED,8EAA8E;AACjE,QAAA,WAAW,GAAG,CAAC,GAAG,sBAAgB,CAAC,CAAA;AAEnC,QAAA,MAAM,GAAG;IACpB,QAAQ,EAAE;QACR,0BAA0B,EAA1B,mDAA0B;QAC1B,4BAA4B,EAA5B,8CAA4B;QAC5B,mCAAmC,EAAnC,8DAAmC;KACpC;IAED,6FAA6F;IAC7F,UAAU,EAAV,2BAAU;IAEV,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,oBAA2B;QAC9B,GAAG,oBAAqB;QACxB,GAAG,oBAAoB;QACvB,GAAG,oBAAkB;QACrB,GAAG,qBAAkB;QACrB,GAAG,qBAAa;QAChB,GAAG,qBAAqB;QACxB,GAAG,qBAAa;QAChB,GAAG,qBAAgB;QACnB,GAAG,oBAAmB;QACtB,GAAG,oBAAkB;QACrB,GAAG,oBAAuB;QAC1B,GAAG,oBAAc;QACjB,GAAG,qBAAkB;QACrB,GAAG,qBAAoB;QACvB,GAAG,oBAAsB;QACzB,GAAG,qBAA0B;KAC9B;IACD,UAAU,EAAE;QACV,SAAS,EAAE,mDAA0B;KACtC;CACF,CAAA","sourcesContent":["/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as AccessRequestEntities, resolvers as AccessRequestResolvers } from './access-request/index.js'\nimport {\n entities as UsersAuthProvidersEntities,\n resolvers as UsersAuthProvidersResolvers\n} from './users-auth-providers/index.js'\nimport { entities as AuthProviderEntities, resolvers as AuthProviderResolvers } from './auth-provider/index.js'\nimport { resolvers as AppbindingResolver } from './app-binding/index.js'\nimport { entities as ApplianceEntities, resolvers as ApplianceResolvers } from './appliance/index.js'\nimport { entities as ApplicationEntities, resolvers as ApplicationResolvers } from './application/index.js'\nimport { resolvers as DomainGeneratorResolver } from './domain-generator/index.js'\nimport { entities as GrantedRoleEntities, resolvers as GrantedRoleResolver } from './granted-role/index.js'\nimport {\n entities as AuditEntities,\n resolvers as AuditResolvers,\n subscribers as AuditSubscribers\n} from './audit/index.js'\nimport { auditTargetDirectiveTypeDefs } from './audit/audit-target.js'\nimport { recentConfirmationDirectiveTypeDefs } from './identity-confirmation/identity-confirmation.js'\nimport { entities as PartnerEntities, resolvers as PartnerResolvers } from './partner/index.js'\nimport { entities as PasswordHistoryEntities } from './password-history/index.js'\nimport { entities as PrivilegeEntities, resolvers as PrivilegeResolvers } from './privilege/index.js'\nimport { privilegeDirectiveResolver, privilegeDirectiveTypeDefs } from './privilege/privilege-directive.js'\nimport { openFields } from './open-fields.js'\nimport { entities as RoleEntities, resolvers as RoleResolvers } from './role/index.js'\nimport { resolvers as RoleTemplateResolvers } from './role-template/index.js'\nimport { entities as UserEntities, resolvers as UserResolvers } from './user/index.js'\nimport { entities as VerificationTokenEntities } from './verification-token/index.js'\nimport { entities as WebAuthCredentialEntities, resolvers as WebAuthCredentialResolvers } from './web-auth-credential/index.js'\nimport { entities as DomainLinkEntities, resolvers as DomainLinkResolver } from './domain-link/index.js'\nimport { entities as DomainOwnerEntities, resolvers as DomainOwnerResolvers } from './domain-owner/index.js'\n\n/* EXPORT ENTITY TYPES */\nexport * from './users-auth-providers/users-auth-providers.js'\nexport * from './auth-provider/auth-provider.js'\nexport * from './application/application.js'\nexport * from './appliance/appliance.js'\nexport * from './privilege/privilege.js'\nexport * from './role/role.js'\nexport * from './privilege/privilege-axis.js'\n/* What a field asks for, by name — for another entrance to the same door (operato-twin ADR-0072 decision 5). */\nexport { declarePrivileges, privilegeOfField, type FieldGate } from './privilege/privilege-directive.js'\n/* Other entrances report AUTH's refusal without copying its cause or localized wording. */\nexport { privilegeRejection } from './privilege/privilege-rejection.js'\n/* How a module declares the fields it leaves open — see `privilege/open-field-rule.ts`. */\nexport { type OpenFieldsDeclaration } from './privilege/open-field-rule.js'\nexport * from './role-template/role-template.js'\nexport * from './role-template/role-task.js'\nexport * from './role-template/role-template-types.js'\nexport * from './user/user.js'\nexport * from './partner/partner.js'\nexport * from './granted-role/granted-role.js'\nexport * from './app-binding/app-binding.js'\nexport * from './password-history/password-history.js'\nexport * from './verification-token/verification-token.js'\nexport * from './audit/audit-request.js'\nexport * from './audit/audit-action.js'\nexport { registerAuditKind } from './audit/audit-kinds.js'\nexport { recordAuditAction, noteAuditAction, flushAudit, type AuditActionInput } from './audit/audit-recorder.js'\nexport { purgeExpiredAudit, startAuditRetention } from './audit/audit-retention.js'\nexport * from './web-auth-credential/web-auth-credential.js'\nexport * from './domain-link/domain-link.js'\nexport * from './domain-owner/domain-owner.js'\nexport * from './access-request/access-request.js'\n\n/* EXPORT TYPES */\nexport * from './app-binding/app-binding-types.js'\nexport * from './appliance/appliance-types.js'\nexport * from './application/application-types.js'\nexport * from './domain-generator/domain-generator-types.js'\nexport * from './partner/partner-types.js'\nexport * from './privilege/privilege-types.js'\nexport * from './role/role-types.js'\nexport * from './user/user-types.js'\nexport * from './domain-link/domain-link-types.js'\nexport * from './access-request/access-request-types.js'\n\nexport const entities = [\n /* ENTITIES */\n ...UsersAuthProvidersEntities,\n ...AuthProviderEntities,\n ...ApplicationEntities,\n ...ApplianceEntities,\n ...PrivilegeEntities,\n ...RoleEntities,\n ...UserEntities,\n ...PartnerEntities,\n ...GrantedRoleEntities,\n ...PasswordHistoryEntities,\n ...VerificationTokenEntities,\n ...AuditEntities,\n ...WebAuthCredentialEntities,\n ...DomainLinkEntities,\n ...DomainOwnerEntities,\n ...AccessRequestEntities\n]\n\n/* The audit of who may do what, written where it is saved (ADR-0141 §3.3). */\nexport const subscribers = [...AuditSubscribers]\n\nexport const schema = {\n typeDefs: {\n privilegeDirectiveTypeDefs,\n auditTargetDirectiveTypeDefs,\n recentConfirmationDirectiveTypeDefs\n },\n\n /* The fields that carry no @privilege, and why — `open-fields.ts`, read by the directive. */\n openFields,\n\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...UsersAuthProvidersResolvers,\n ...AuthProviderResolvers,\n ...ApplicationResolvers,\n ...ApplianceResolvers,\n ...PrivilegeResolvers,\n ...RoleResolvers,\n ...RoleTemplateResolvers,\n ...UserResolvers,\n ...PartnerResolvers,\n ...GrantedRoleResolver,\n ...AppbindingResolver,\n ...DomainGeneratorResolver,\n ...AuditResolvers,\n ...DomainLinkResolver,\n ...DomainOwnerResolvers,\n ...AccessRequestResolvers,\n ...WebAuthCredentialResolvers\n ],\n directives: {\n privilege: privilegeDirectiveResolver\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,mCAAmC;AACnC,wDAAkH;AAClH,8DAGwC;AACxC,uDAA+G;AAC/G,qDAAwE;AACxE,mDAAqG;AACrG,qDAA2G;AAC3G,0DAAkF;AAClF,sDAA2G;AAC3G,+CAIyB;AACzB,6DAAsE;AACtE,+FAAsG;AACtG,kDAA+F;AAC/F,2DAAiF;AACjF,oDAAqG;AACrG,+EAA2G;AAC3G,qDAA6C;AAC7C,+CAAsF;AACtF,wDAA6E;AAC7E,+CAAsF;AACtF,6DAAqF;AACrF,8DAA+H;AAC/H,sDAAwG;AACxG,uDAA4G;AAE5G,yBAAyB;AACzB,yFAA8D;AAC9D,2EAAgD;AAChD,uEAA4C;AAC5C,mEAAwC;AACxC,mEAAwC;AACxC,yDAA8B;AAC9B,wEAA6C;AAC7C,gHAAgH;AAChH,6EAAwG;AAA/F,2HAAA,iBAAiB,OAAA;AAAE,0HAAA,gBAAgB,OAAA;AAC5C,2FAA2F;AAC3F,6EAAuE;AAA9D,4HAAA,kBAAkB,OAAA;AAG3B,2EAAgD;AAChD,uEAA4C;AAC5C,iFAAsD;AACtD,yDAA8B;AAC9B,+DAAoC;AACpC,yEAA8C;AAC9C,uEAA4C;AAC5C,iFAAsD;AACtD,qFAA0D;AAC1D,mEAAwC;AACxC,kEAAuC;AACvC,yDAA0D;AAAjD,mHAAA,iBAAiB,OAAA;AAC1B,+DAAiH;AAAxG,sHAAA,iBAAiB,OAAA;AAAE,oHAAA,eAAe,OAAA;AAAE,+GAAA,UAAU,OAAA;AACvD,iEAAmF;AAA1E,uHAAA,iBAAiB,OAAA;AAAE,yHAAA,mBAAmB,OAAA;AAC/C,uDAAgH;AAAvG,kHAAA,iBAAiB,OAAA;AAAE,4GAAA,WAAW,OAAA;AAAE,2GAAA,UAAU,OAAA;AACnD,uFAA4D;AAC5D,uEAA4C;AAC5C,yEAA8C;AAC9C,6EAAkD;AAElD,kBAAkB;AAClB,6EAAkD;AAClD,yEAA8C;AAC9C,6EAAkD;AAClD,uFAA4D;AAC5D,qEAA0C;AAC1C,yEAA8C;AAC9C,+DAAoC;AACpC,+DAAoC;AACpC,6EAAkD;AAClD,mFAAwD;AAE3C,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,mBAA0B;IAC7B,GAAG,mBAAoB;IACvB,GAAG,mBAAmB;IACtB,GAAG,mBAAiB;IACpB,GAAG,oBAAiB;IACpB,GAAG,oBAAY;IACf,GAAG,oBAAY;IACf,GAAG,oBAAe;IAClB,GAAG,mBAAmB;IACtB,GAAG,oBAAuB;IAC1B,GAAG,oBAAyB;IAC5B,GAAG,mBAAa;IAChB,GAAG,oBAAyB;IAC5B,GAAG,oBAAkB;IACrB,GAAG,oBAAmB;IACtB,GAAG,mBAAqB;CACzB,CAAA;AAED,8EAA8E;AACjE,QAAA,WAAW,GAAG,CAAC,GAAG,sBAAgB,CAAC,CAAA;AAEnC,QAAA,MAAM,GAAG;IACpB,QAAQ,EAAE;QACR,0BAA0B,EAA1B,mDAA0B;QAC1B,4BAA4B,EAA5B,8CAA4B;QAC5B,mCAAmC,EAAnC,8DAAmC;KACpC;IAED,6FAA6F;IAC7F,UAAU,EAAV,2BAAU;IAEV,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,oBAA2B;QAC9B,GAAG,oBAAqB;QACxB,GAAG,oBAAoB;QACvB,GAAG,oBAAkB;QACrB,GAAG,qBAAkB;QACrB,GAAG,qBAAa;QAChB,GAAG,qBAAqB;QACxB,GAAG,qBAAa;QAChB,GAAG,qBAAgB;QACnB,GAAG,oBAAmB;QACtB,GAAG,oBAAkB;QACrB,GAAG,oBAAuB;QAC1B,GAAG,oBAAc;QACjB,GAAG,qBAAkB;QACrB,GAAG,qBAAoB;QACvB,GAAG,oBAAsB;QACzB,GAAG,qBAA0B;KAC9B;IACD,UAAU,EAAE;QACV,SAAS,EAAE,mDAA0B;KACtC;CACF,CAAA","sourcesContent":["/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as AccessRequestEntities, resolvers as AccessRequestResolvers } from './access-request/index.js'\nimport {\n entities as UsersAuthProvidersEntities,\n resolvers as UsersAuthProvidersResolvers\n} from './users-auth-providers/index.js'\nimport { entities as AuthProviderEntities, resolvers as AuthProviderResolvers } from './auth-provider/index.js'\nimport { resolvers as AppbindingResolver } from './app-binding/index.js'\nimport { entities as ApplianceEntities, resolvers as ApplianceResolvers } from './appliance/index.js'\nimport { entities as ApplicationEntities, resolvers as ApplicationResolvers } from './application/index.js'\nimport { resolvers as DomainGeneratorResolver } from './domain-generator/index.js'\nimport { entities as GrantedRoleEntities, resolvers as GrantedRoleResolver } from './granted-role/index.js'\nimport {\n entities as AuditEntities,\n resolvers as AuditResolvers,\n subscribers as AuditSubscribers\n} from './audit/index.js'\nimport { auditTargetDirectiveTypeDefs } from './audit/audit-target.js'\nimport { recentConfirmationDirectiveTypeDefs } from './identity-confirmation/identity-confirmation.js'\nimport { entities as PartnerEntities, resolvers as PartnerResolvers } from './partner/index.js'\nimport { entities as PasswordHistoryEntities } from './password-history/index.js'\nimport { entities as PrivilegeEntities, resolvers as PrivilegeResolvers } from './privilege/index.js'\nimport { privilegeDirectiveResolver, privilegeDirectiveTypeDefs } from './privilege/privilege-directive.js'\nimport { openFields } from './open-fields.js'\nimport { entities as RoleEntities, resolvers as RoleResolvers } from './role/index.js'\nimport { resolvers as RoleTemplateResolvers } from './role-template/index.js'\nimport { entities as UserEntities, resolvers as UserResolvers } from './user/index.js'\nimport { entities as VerificationTokenEntities } from './verification-token/index.js'\nimport { entities as WebAuthCredentialEntities, resolvers as WebAuthCredentialResolvers } from './web-auth-credential/index.js'\nimport { entities as DomainLinkEntities, resolvers as DomainLinkResolver } from './domain-link/index.js'\nimport { entities as DomainOwnerEntities, resolvers as DomainOwnerResolvers } from './domain-owner/index.js'\n\n/* EXPORT ENTITY TYPES */\nexport * from './users-auth-providers/users-auth-providers.js'\nexport * from './auth-provider/auth-provider.js'\nexport * from './application/application.js'\nexport * from './appliance/appliance.js'\nexport * from './privilege/privilege.js'\nexport * from './role/role.js'\nexport * from './privilege/privilege-axis.js'\n/* What a field asks for, by name — for another entrance to the same door (operato-twin ADR-0072 decision 5). */\nexport { declarePrivileges, privilegeOfField, type FieldGate } from './privilege/privilege-directive.js'\n/* Other entrances report AUTH's refusal without copying its cause or localized wording. */\nexport { privilegeRejection } from './privilege/privilege-rejection.js'\n/* How a module declares the fields it leaves open — see `privilege/open-field-rule.ts`. */\nexport { type OpenFieldsDeclaration } from './privilege/open-field-rule.js'\nexport * from './role-template/role-template.js'\nexport * from './role-template/role-task.js'\nexport * from './role-template/role-template-types.js'\nexport * from './user/user.js'\nexport * from './partner/partner.js'\nexport * from './granted-role/granted-role.js'\nexport * from './app-binding/app-binding.js'\nexport * from './password-history/password-history.js'\nexport * from './verification-token/verification-token.js'\nexport * from './audit/audit-request.js'\nexport * from './audit/audit-action.js'\nexport { registerAuditKind } from './audit/audit-kinds.js'\nexport { recordAuditAction, noteAuditAction, flushAudit, type AuditActionInput } from './audit/audit-recorder.js'\nexport { purgeExpiredAudit, startAuditRetention } from './audit/audit-retention.js'\nexport { registerWorkDoors, workOfField, workDoneBy, type WorkDoor, type WorkDone } from './audit/audit-work.js'\nexport * from './web-auth-credential/web-auth-credential.js'\nexport * from './domain-link/domain-link.js'\nexport * from './domain-owner/domain-owner.js'\nexport * from './access-request/access-request.js'\n\n/* EXPORT TYPES */\nexport * from './app-binding/app-binding-types.js'\nexport * from './appliance/appliance-types.js'\nexport * from './application/application-types.js'\nexport * from './domain-generator/domain-generator-types.js'\nexport * from './partner/partner-types.js'\nexport * from './privilege/privilege-types.js'\nexport * from './role/role-types.js'\nexport * from './user/user-types.js'\nexport * from './domain-link/domain-link-types.js'\nexport * from './access-request/access-request-types.js'\n\nexport const entities = [\n /* ENTITIES */\n ...UsersAuthProvidersEntities,\n ...AuthProviderEntities,\n ...ApplicationEntities,\n ...ApplianceEntities,\n ...PrivilegeEntities,\n ...RoleEntities,\n ...UserEntities,\n ...PartnerEntities,\n ...GrantedRoleEntities,\n ...PasswordHistoryEntities,\n ...VerificationTokenEntities,\n ...AuditEntities,\n ...WebAuthCredentialEntities,\n ...DomainLinkEntities,\n ...DomainOwnerEntities,\n ...AccessRequestEntities\n]\n\n/* The audit of who may do what, written where it is saved (ADR-0141 §3.3). */\nexport const subscribers = [...AuditSubscribers]\n\nexport const schema = {\n typeDefs: {\n privilegeDirectiveTypeDefs,\n auditTargetDirectiveTypeDefs,\n recentConfirmationDirectiveTypeDefs\n },\n\n /* The fields that carry no @privilege, and why — `open-fields.ts`, read by the directive. */\n openFields,\n\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...UsersAuthProvidersResolvers,\n ...AuthProviderResolvers,\n ...ApplicationResolvers,\n ...ApplianceResolvers,\n ...PrivilegeResolvers,\n ...RoleResolvers,\n ...RoleTemplateResolvers,\n ...UserResolvers,\n ...PartnerResolvers,\n ...GrantedRoleResolver,\n ...AppbindingResolver,\n ...DomainGeneratorResolver,\n ...AuditResolvers,\n ...DomainLinkResolver,\n ...DomainOwnerResolvers,\n ...AccessRequestResolvers,\n ...WebAuthCredentialResolvers\n ],\n directives: {\n privilege: privilegeDirectiveResolver\n }\n}\n"]}