nestjs-ddd-cli 3.2.2 → 3.3.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.
- package/README.md +118 -9
- package/ddd.schema.json +11 -1
- package/dist/commands/doctor-enhanced.d.ts +1 -0
- package/dist/commands/doctor-enhanced.js +94 -79
- package/dist/commands/doctor-enhanced.js.map +1 -1
- package/dist/commands/doctor.d.ts +9 -0
- package/dist/commands/doctor.js +68 -21
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-all.js +54 -28
- package/dist/commands/generate-all.js.map +1 -1
- package/dist/commands/generate-controller.d.ts +1 -0
- package/dist/commands/generate-controller.js +71 -0
- package/dist/commands/generate-controller.js.map +1 -0
- package/dist/commands/generate-domain-service.d.ts +1 -1
- package/dist/commands/generate-domain-service.js +6 -4
- package/dist/commands/generate-domain-service.js.map +1 -1
- package/dist/commands/generate-dto.d.ts +4 -0
- package/dist/commands/generate-dto.js +162 -0
- package/dist/commands/generate-dto.js.map +1 -0
- package/dist/commands/generate-entity.js +7 -2
- package/dist/commands/generate-entity.js.map +1 -1
- package/dist/commands/generate-event.js +10 -4
- package/dist/commands/generate-event.js.map +1 -1
- package/dist/commands/generate-migration-deployment.d.ts +15 -0
- package/dist/commands/generate-migration-deployment.js +326 -0
- package/dist/commands/generate-migration-deployment.js.map +1 -0
- package/dist/commands/generate-migration-deployment.spec.d.ts +1 -0
- package/dist/commands/generate-migration-deployment.spec.js +337 -0
- package/dist/commands/generate-migration-deployment.spec.js.map +1 -0
- package/dist/commands/generate-module.js +4 -2
- package/dist/commands/generate-module.js.map +1 -1
- package/dist/commands/generate-query.js +23 -4
- package/dist/commands/generate-query.js.map +1 -1
- package/dist/commands/generate-repository.d.ts +1 -1
- package/dist/commands/generate-repository.js +17 -34
- package/dist/commands/generate-repository.js.map +1 -1
- package/dist/commands/generate-service.js +19 -4
- package/dist/commands/generate-service.js.map +1 -1
- package/dist/commands/generate-usecase.js +12 -31
- package/dist/commands/generate-usecase.js.map +1 -1
- package/dist/commands/generate-value-object.js +3 -14
- package/dist/commands/generate-value-object.js.map +1 -1
- package/dist/commands/init-project.d.ts +3 -0
- package/dist/commands/init-project.js +19 -9
- package/dist/commands/init-project.js.map +1 -1
- package/dist/commands/interactive-scaffold.js +10 -0
- package/dist/commands/interactive-scaffold.js.map +1 -1
- package/dist/commands/migration.d.ts +3 -0
- package/dist/commands/migration.js +83 -48
- package/dist/commands/migration.js.map +1 -1
- package/dist/commands/recipe.d.ts +2 -0
- package/dist/commands/recipe.js +229 -85
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipes/banklink-connector-contract.recipe.d.ts +1 -0
- package/dist/commands/recipes/banklink-connector-contract.recipe.js +161 -0
- package/dist/commands/recipes/banklink-connector-contract.recipe.js.map +1 -0
- package/dist/commands/recipes/bounded-json-http.recipe.d.ts +2 -0
- package/dist/commands/recipes/bounded-json-http.recipe.js +53 -0
- package/dist/commands/recipes/bounded-json-http.recipe.js.map +1 -0
- package/dist/commands/recipes/business-reference-identifiers.recipe.d.ts +1 -0
- package/dist/commands/recipes/business-reference-identifiers.recipe.js +223 -0
- package/dist/commands/recipes/business-reference-identifiers.recipe.js.map +1 -0
- package/dist/commands/recipes/event-backbone.recipe.d.ts +1 -0
- package/dist/commands/recipes/event-backbone.recipe.js +1118 -0
- package/dist/commands/recipes/event-backbone.recipe.js.map +1 -0
- package/dist/commands/recipes/external-projection-worker.recipe.d.ts +6 -0
- package/dist/commands/recipes/external-projection-worker.recipe.js +211 -0
- package/dist/commands/recipes/external-projection-worker.recipe.js.map +1 -0
- package/dist/commands/recipes/index.d.ts +11 -0
- package/dist/commands/recipes/index.js +11 -0
- package/dist/commands/recipes/index.js.map +1 -1
- package/dist/commands/recipes/jest-cjs-compat.recipe.d.ts +3 -0
- package/dist/commands/recipes/jest-cjs-compat.recipe.js +130 -0
- package/dist/commands/recipes/jest-cjs-compat.recipe.js.map +1 -0
- package/dist/commands/recipes/joi-env.recipe.js +1 -1
- package/dist/commands/recipes/kafka-consumer.recipe.d.ts +1 -0
- package/dist/commands/recipes/kafka-consumer.recipe.js +65 -0
- package/dist/commands/recipes/kafka-consumer.recipe.js.map +1 -0
- package/dist/commands/recipes/oauth2-client-credentials.recipe.d.ts +1 -0
- package/dist/commands/recipes/oauth2-client-credentials.recipe.js +60 -0
- package/dist/commands/recipes/oauth2-client-credentials.recipe.js.map +1 -0
- package/dist/commands/recipes/oauth2-token-introspection.recipe.d.ts +1 -0
- package/dist/commands/recipes/oauth2-token-introspection.recipe.js +67 -0
- package/dist/commands/recipes/oauth2-token-introspection.recipe.js.map +1 -0
- package/dist/commands/recipes/oidc-bff-session.recipe.d.ts +1 -0
- package/dist/commands/recipes/oidc-bff-session.recipe.js +57 -0
- package/dist/commands/recipes/oidc-bff-session.recipe.js.map +1 -0
- package/dist/commands/recipes/oidc-dashboard.recipe.d.ts +1 -0
- package/dist/commands/recipes/oidc-dashboard.recipe.js +463 -0
- package/dist/commands/recipes/oidc-dashboard.recipe.js.map +1 -0
- package/dist/commands/recipes/oidc-resource-server.recipe.d.ts +1 -0
- package/dist/commands/recipes/oidc-resource-server.recipe.js +85 -0
- package/dist/commands/recipes/oidc-resource-server.recipe.js.map +1 -0
- package/dist/commands/recipes/platform-context.recipe.d.ts +1 -0
- package/dist/commands/recipes/platform-context.recipe.js +229 -0
- package/dist/commands/recipes/platform-context.recipe.js.map +1 -0
- package/dist/commands/recipes/platform-parc-authorization.recipe.d.ts +1 -0
- package/dist/commands/recipes/platform-parc-authorization.recipe.js +339 -0
- package/dist/commands/recipes/platform-parc-authorization.recipe.js.map +1 -0
- package/dist/commands/recipes/platform-parc-bound-authorization.recipe.d.ts +1 -0
- package/dist/commands/recipes/platform-parc-bound-authorization.recipe.js +56 -0
- package/dist/commands/recipes/platform-parc-bound-authorization.recipe.js.map +1 -0
- package/dist/commands/recipes/platform-service-access-request-context.recipe.d.ts +1 -0
- package/dist/commands/recipes/platform-service-access-request-context.recipe.js +103 -0
- package/dist/commands/recipes/platform-service-access-request-context.recipe.js.map +1 -0
- package/dist/commands/recipes/platform-service-runtime.recipe.d.ts +1 -0
- package/dist/commands/recipes/platform-service-runtime.recipe.js +415 -0
- package/dist/commands/recipes/platform-service-runtime.recipe.js.map +1 -0
- package/dist/index.js +77 -9
- package/dist/index.js.map +1 -1
- package/dist/templates/ai-context/CLAUDE.md.hbs +39 -3
- package/dist/templates/ai-context/conventions.md.hbs +13 -8
- package/dist/templates/command/create-command.hbs +8 -3
- package/dist/templates/command/delete-command.hbs +1 -1
- package/dist/templates/command/update-command.hbs +1 -1
- package/dist/templates/controller/application-controller.hbs +7 -0
- package/dist/templates/controller/controller.hbs +6 -0
- package/dist/templates/dto/create-dto.hbs +17 -5
- package/dist/templates/dto/filter-dto.hbs +1 -1
- package/dist/templates/dto/response-dto.hbs +1 -1
- package/dist/templates/entity/entity.hbs +4 -0
- package/dist/templates/mapper/mapper.hbs +5 -1
- package/dist/templates/orm-entity/orm-entity.hbs +9 -1
- package/dist/templates/prisma/prisma-mapper.hbs +6 -0
- package/dist/templates/prisma/prisma-repository.hbs +57 -5
- package/dist/templates/prisma/prisma-schema.hbs +2 -0
- package/dist/templates/query/get-all.query.hbs +10 -2
- package/dist/templates/recipes/bounded-json-http/README.md.hbs +36 -0
- package/dist/templates/recipes/external-projection-worker/README.md.hbs +157 -0
- package/dist/templates/recipes/external-projection-worker/canonical-json.ts.hbs +123 -0
- package/dist/templates/recipes/external-projection-worker/enqueuer.ts.hbs +167 -0
- package/dist/templates/recipes/external-projection-worker/index.ts.hbs +6 -0
- package/dist/templates/recipes/external-projection-worker/migration.ts.hbs +88 -0
- package/dist/templates/recipes/external-projection-worker/module.ts.hbs +36 -0
- package/dist/templates/recipes/external-projection-worker/store.ts.hbs +354 -0
- package/dist/templates/recipes/external-projection-worker/types.ts.hbs +134 -0
- package/dist/templates/recipes/external-projection-worker/worker.ts.hbs +296 -0
- package/dist/templates/recipes/kafka-consumer/README.md.hbs +50 -0
- package/dist/templates/recipes/kafka-consumer/kafka-consumer.ts.hbs +135 -0
- package/dist/templates/recipes/kafka-consumer/migration.ts.hbs +17 -0
- package/dist/templates/recipes/oauth2-client-credentials/README.md.hbs +40 -0
- package/dist/templates/recipes/oauth2-client-credentials/client.spec.ts.hbs +234 -0
- package/dist/templates/recipes/oauth2-client-credentials/client.ts.hbs +210 -0
- package/dist/templates/recipes/oauth2-client-credentials/index.ts.hbs +2 -0
- package/dist/templates/recipes/oauth2-client-credentials/module.ts.hbs +58 -0
- package/dist/templates/recipes/oauth2-token-introspection/README.md.hbs +158 -0
- package/dist/templates/recipes/oauth2-token-introspection/client.spec.ts.hbs +350 -0
- package/dist/templates/recipes/oauth2-token-introspection/client.ts.hbs +241 -0
- package/dist/templates/recipes/oauth2-token-introspection/http-client.spec.ts.hbs +411 -0
- package/dist/templates/recipes/oauth2-token-introspection/http-client.ts.hbs +343 -0
- package/dist/templates/recipes/oauth2-token-introspection/index.ts.hbs +3 -0
- package/dist/templates/recipes/oauth2-token-introspection/module.ts.hbs +58 -0
- package/dist/templates/recipes/oidc-bff-session/README.md.hbs +96 -0
- package/dist/templates/recipes/oidc-bff-session/client.test.ts.hbs +663 -0
- package/dist/templates/recipes/oidc-bff-session/client.ts.hbs +635 -0
- package/dist/templates/recipes/oidc-bff-session/index.ts.hbs +3 -0
- package/dist/templates/recipes/oidc-bff-session/store.integration.test.ts.hbs +480 -0
- package/dist/templates/recipes/oidc-bff-session/store.test.ts.hbs +87 -0
- package/dist/templates/recipes/oidc-bff-session/store.ts.hbs +549 -0
- package/dist/templates/recipes/oidc-bff-session/valkey.test.ts.hbs +158 -0
- package/dist/templates/recipes/oidc-bff-session/valkey.ts.hbs +148 -0
- package/dist/templates/recipes/oidc-resource-server/README.md.hbs +74 -0
- package/dist/templates/recipes/oidc-resource-server/index.ts.hbs +2 -0
- package/dist/templates/recipes/oidc-resource-server/module.ts.hbs +51 -0
- package/dist/templates/recipes/oidc-resource-server/verifier.spec.ts.hbs +186 -0
- package/dist/templates/recipes/oidc-resource-server/verifier.ts.hbs +440 -0
- package/dist/templates/recipes/platform-parc-bound-authorization/README.md.hbs +92 -0
- package/dist/templates/recipes/platform-parc-bound-authorization/client.ts.hbs +142 -0
- package/dist/templates/recipes/platform-service-access-request-context/docs.md.hbs +61 -0
- package/dist/templates/recipes/platform-service-access-request-context/env.example.hbs +7 -0
- package/dist/templates/recipes/platform-service-access-request-context/index.ts.hbs +7 -0
- package/dist/templates/recipes/platform-service-access-request-context/request-context-headers.ts.hbs +61 -0
- package/dist/templates/recipes/platform-service-access-request-context/request-context-introspection.parser.ts.hbs +132 -0
- package/dist/templates/recipes/platform-service-access-request-context/request-context-introspection.types.ts.hbs +40 -0
- package/dist/templates/recipes/platform-service-access-request-context/service-access-request-context.client.ts.hbs +45 -0
- package/dist/templates/recipes/platform-service-access-request-context/service-access-request-context.config.ts.hbs +142 -0
- package/dist/templates/recipes/platform-service-access-request-context/service-access-request-context.guard.ts.hbs +77 -0
- package/dist/templates/recipes/platform-service-access-request-context/service-access-request-context.module.ts.hbs +17 -0
- package/dist/templates/repository/repository.hbs +42 -4
- package/dist/templates/resolver/graphql-input.hbs +23 -6
- package/dist/templates/resolver/resolver.hbs +4 -0
- package/dist/templates/service/domain-service.hbs +2 -2
- package/dist/templates/test/controller.spec.hbs +5 -1
- package/dist/templates/test/prisma-repository.spec.hbs +192 -0
- package/dist/templates/test/repository.spec.hbs +40 -1
- package/dist/templates/test/usecase.spec.hbs +23 -4
- package/dist/templates/usecase/application-usecase.hbs +17 -0
- package/dist/templates/usecase/create-usecase.hbs +34 -3
- package/dist/templates/usecase/update-usecase.hbs +15 -1
- package/dist/utils/config.utils.d.ts +2 -0
- package/dist/utils/config.utils.js +14 -2
- package/dist/utils/config.utils.js.map +1 -1
- package/dist/utils/dependency.utils.d.ts +16 -2
- package/dist/utils/dependency.utils.js +100 -12
- package/dist/utils/dependency.utils.js.map +1 -1
- package/dist/utils/field.utils.d.ts +6 -0
- package/dist/utils/field.utils.js +50 -8
- package/dist/utils/field.utils.js.map +1 -1
- package/dist/utils/field.utils.spec.d.ts +1 -0
- package/dist/utils/field.utils.spec.js +38 -0
- package/dist/utils/field.utils.spec.js.map +1 -0
- package/dist/utils/file.utils.d.ts +23 -1
- package/dist/utils/file.utils.js +37 -1
- package/dist/utils/file.utils.js.map +1 -1
- package/dist/utils/naming.utils.js +5 -4
- package/dist/utils/naming.utils.js.map +1 -1
- package/dist/utils/static-recipe.utils.d.ts +4 -0
- package/dist/utils/static-recipe.utils.js +148 -0
- package/dist/utils/static-recipe.utils.js.map +1 -0
- package/package.json +12 -5
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.applyOidcResourceServerRecipe = applyOidcResourceServerRecipe;
|
|
37
|
+
const path = __importStar(require("node:path"));
|
|
38
|
+
const fs = __importStar(require("fs-extra"));
|
|
39
|
+
const file_utils_1 = require("../../utils/file.utils");
|
|
40
|
+
const files = [
|
|
41
|
+
['verifier.ts.hbs', 'src/shared/auth/oidc-resource-server/oidc-access-token-verifier.ts'],
|
|
42
|
+
[
|
|
43
|
+
'verifier.spec.ts.hbs',
|
|
44
|
+
'src/shared/auth/oidc-resource-server/oidc-access-token-verifier.spec.ts',
|
|
45
|
+
],
|
|
46
|
+
['module.ts.hbs', 'src/shared/auth/oidc-resource-server/oidc-resource-server.module.ts'],
|
|
47
|
+
['index.ts.hbs', 'src/shared/auth/oidc-resource-server/index.ts'],
|
|
48
|
+
['README.md.hbs', 'docs/auth/oidc-resource-server.md'],
|
|
49
|
+
];
|
|
50
|
+
async function assertTarget(root, file) {
|
|
51
|
+
let cursor = file.target;
|
|
52
|
+
while (cursor !== root) {
|
|
53
|
+
if (await fs.pathExists(cursor)) {
|
|
54
|
+
const stat = await fs.lstat(cursor);
|
|
55
|
+
if (stat.isSymbolicLink())
|
|
56
|
+
throw new Error(`Refusing symlink recipe target: ${cursor}`);
|
|
57
|
+
}
|
|
58
|
+
cursor = path.dirname(cursor);
|
|
59
|
+
}
|
|
60
|
+
if ((await fs.pathExists(file.target)) &&
|
|
61
|
+
(await fs.readFile(file.target, 'utf8')) !== file.content) {
|
|
62
|
+
throw new Error(`OIDC resource recipe target already differs: ${file.target}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function applyOidcResourceServerRecipe(basePath, dryRun = false) {
|
|
66
|
+
const root = path.resolve(basePath);
|
|
67
|
+
const templateRoot = path.join(__dirname, '../../templates/recipes/oidc-resource-server');
|
|
68
|
+
const planned = await Promise.all(files.map(async ([source, target]) => ({
|
|
69
|
+
target: path.join(root, target),
|
|
70
|
+
content: await (0, file_utils_1.readTemplate)(path.join(templateRoot, source)),
|
|
71
|
+
})));
|
|
72
|
+
// Check every target before creating any directory or writing any file.
|
|
73
|
+
for (const file of planned) {
|
|
74
|
+
await assertTarget(root, file);
|
|
75
|
+
}
|
|
76
|
+
for (const file of planned) {
|
|
77
|
+
if (dryRun)
|
|
78
|
+
console.log(`Would generate: ${file.target}`);
|
|
79
|
+
else if (!(await fs.pathExists(file.target))) {
|
|
80
|
+
await fs.ensureDir(path.dirname(file.target));
|
|
81
|
+
await fs.writeFile(file.target, file.content, { flag: 'wx' });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=oidc-resource-server.recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-resource-server.recipe.js","sourceRoot":"","sources":["../../../src/commands/recipes/oidc-resource-server.recipe.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,sEAuBC;AA1DD,gDAAkC;AAClC,6CAA+B;AAC/B,uDAAsD;AAEtD,MAAM,KAAK,GAAG;IACZ,CAAC,iBAAiB,EAAE,oEAAoE,CAAC;IACzF;QACE,sBAAsB;QACtB,yEAAyE;KAC1E;IACD,CAAC,eAAe,EAAE,qEAAqE,CAAC;IACxF,CAAC,cAAc,EAAE,+CAA+C,CAAC;IACjE,CAAC,eAAe,EAAE,mCAAmC,CAAC;CAC9C,CAAC;AAEX,KAAK,UAAU,YAAY,CACzB,IAAY,EACZ,IAAyC;IAEzC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACzB,OAAO,MAAM,KAAK,IAAI,EAAE,CAAC;QACvB,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,IAAI,CAAC,cAAc,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IACD,IACE,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,EACzD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,6BAA6B,CACjD,QAAgB,EAChB,MAAM,GAAG,KAAK;IAEd,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,8CAA8C,CAAC,CAAC;IAC1F,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QAC/B,OAAO,EAAE,MAAM,IAAA,yBAAY,EAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;KAC7D,CAAC,CAAC,CACJ,CAAC;IACF,wEAAwE;IACxE,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;aACrD,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function applyPlatformContextRecipe(basePath: string): Promise<void>;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.applyPlatformContextRecipe = applyPlatformContextRecipe;
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
+
const file_utils_1 = require("../../utils/file.utils");
|
|
43
|
+
async function applyPlatformContextRecipe(basePath) {
|
|
44
|
+
const contextPath = path.join(basePath, 'src/shared/platform-context');
|
|
45
|
+
const docsPath = path.join(basePath, 'docs/platform');
|
|
46
|
+
await (0, file_utils_1.ensureDir)(contextPath);
|
|
47
|
+
await (0, file_utils_1.ensureDir)(docsPath);
|
|
48
|
+
await (0, file_utils_1.writeFile)(path.join(contextPath, 'platform-context.types.ts'), typesContent);
|
|
49
|
+
await (0, file_utils_1.writeFile)(path.join(contextPath, 'platform-context.factory.ts'), factoryContent);
|
|
50
|
+
await (0, file_utils_1.writeFile)(path.join(contextPath, 'platform-context.service.ts'), serviceContent);
|
|
51
|
+
await (0, file_utils_1.writeFile)(path.join(contextPath, 'platform-context.module.ts'), moduleContent);
|
|
52
|
+
await (0, file_utils_1.writeFile)(path.join(contextPath, 'index.ts'), indexContent);
|
|
53
|
+
await (0, file_utils_1.writeFile)(path.join(docsPath, 'platform-context.md'), docsContent);
|
|
54
|
+
console.log(chalk_1.default.green(' ✓ Canonical actor and machine context contract'));
|
|
55
|
+
console.log(chalk_1.default.green(' ✓ Correlation, causation, and idempotency metadata'));
|
|
56
|
+
console.log(chalk_1.default.green(' ✓ Async request-context propagation'));
|
|
57
|
+
console.log(chalk_1.default.yellow(' Build this context only from a verified broker or service principal; never trust caller identity headers.'));
|
|
58
|
+
}
|
|
59
|
+
const typesContent = `export interface PlatformActorContext {
|
|
60
|
+
subjectId: string;
|
|
61
|
+
businessId?: string;
|
|
62
|
+
applicationId?: string;
|
|
63
|
+
sessionId?: string;
|
|
64
|
+
tokenId?: string;
|
|
65
|
+
authenticatedBy: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PlatformMachineContext {
|
|
69
|
+
serviceName: string;
|
|
70
|
+
clientId?: string;
|
|
71
|
+
serviceInstanceId?: string;
|
|
72
|
+
grantId?: string;
|
|
73
|
+
credentialId?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface VerifiedPlatformPrincipal {
|
|
77
|
+
actor?: PlatformActorContext;
|
|
78
|
+
machine?: PlatformMachineContext;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface PlatformRequestContext extends VerifiedPlatformPrincipal {
|
|
82
|
+
requestId: string;
|
|
83
|
+
correlationId: string;
|
|
84
|
+
causationId?: string;
|
|
85
|
+
idempotencyKey?: string;
|
|
86
|
+
receivedAt: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface PlatformActionContext {
|
|
90
|
+
service: string;
|
|
91
|
+
capability: string;
|
|
92
|
+
action: string;
|
|
93
|
+
resourceType?: string;
|
|
94
|
+
resourceId?: string;
|
|
95
|
+
businessId?: string;
|
|
96
|
+
applicationId?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface PlatformAuthorizationInput {
|
|
100
|
+
request: PlatformRequestContext;
|
|
101
|
+
target: PlatformActionContext;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface PlatformAccessDecision {
|
|
105
|
+
authority: "service-access" | "parc" | "owner-service";
|
|
106
|
+
allowed: boolean;
|
|
107
|
+
decisionReference: string;
|
|
108
|
+
decisionId?: string;
|
|
109
|
+
decidedAt: string;
|
|
110
|
+
policyVersion?: string;
|
|
111
|
+
reasonCode?: string;
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
114
|
+
const factoryContent = `import { randomUUID } from "crypto";
|
|
115
|
+
import {
|
|
116
|
+
PlatformRequestContext,
|
|
117
|
+
VerifiedPlatformPrincipal,
|
|
118
|
+
} from "./platform-context.types";
|
|
119
|
+
|
|
120
|
+
export interface CreatePlatformRequestContextInput {
|
|
121
|
+
principal: VerifiedPlatformPrincipal;
|
|
122
|
+
requestId?: string;
|
|
123
|
+
correlationId?: string;
|
|
124
|
+
causationId?: string;
|
|
125
|
+
idempotencyKey?: string;
|
|
126
|
+
receivedAt?: Date;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function createPlatformRequestContext(
|
|
130
|
+
input: CreatePlatformRequestContextInput,
|
|
131
|
+
): PlatformRequestContext {
|
|
132
|
+
assertVerifiedPrincipal(input.principal);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...input.principal,
|
|
136
|
+
requestId: input.requestId || randomUUID(),
|
|
137
|
+
correlationId: input.correlationId || randomUUID(),
|
|
138
|
+
causationId: cleanOptional(input.causationId),
|
|
139
|
+
idempotencyKey: cleanOptional(input.idempotencyKey),
|
|
140
|
+
receivedAt: (input.receivedAt || new Date()).toISOString(),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function assertVerifiedPrincipal(principal: VerifiedPlatformPrincipal): void {
|
|
145
|
+
const actorSubject = cleanOptional(principal.actor?.subjectId);
|
|
146
|
+
const machineName = cleanOptional(principal.machine?.serviceName);
|
|
147
|
+
|
|
148
|
+
if (!actorSubject && !machineName) {
|
|
149
|
+
throw new Error("A verified actor or machine principal is required");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (principal.actor && !cleanOptional(principal.actor.authenticatedBy)) {
|
|
153
|
+
throw new Error("Actor authentication provenance is required");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function cleanOptional(value: string | undefined): string | undefined {
|
|
158
|
+
const cleaned = value?.trim();
|
|
159
|
+
return cleaned || undefined;
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
const serviceContent = `import { Injectable } from "@nestjs/common";
|
|
163
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
164
|
+
import { PlatformRequestContext } from "./platform-context.types";
|
|
165
|
+
|
|
166
|
+
@Injectable()
|
|
167
|
+
export class PlatformContextService {
|
|
168
|
+
private readonly storage = new AsyncLocalStorage<PlatformRequestContext>();
|
|
169
|
+
|
|
170
|
+
run<T>(context: PlatformRequestContext, callback: () => T): T {
|
|
171
|
+
return this.storage.run(context, callback);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
current(): PlatformRequestContext | undefined {
|
|
175
|
+
return this.storage.getStore();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
required(): PlatformRequestContext {
|
|
179
|
+
const context = this.current();
|
|
180
|
+
if (!context) {
|
|
181
|
+
throw new Error("Platform request context is not available");
|
|
182
|
+
}
|
|
183
|
+
return context;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
`;
|
|
187
|
+
const moduleContent = `import { Global, Module } from "@nestjs/common";
|
|
188
|
+
import { PlatformContextService } from "./platform-context.service";
|
|
189
|
+
|
|
190
|
+
@Global()
|
|
191
|
+
@Module({
|
|
192
|
+
providers: [PlatformContextService],
|
|
193
|
+
exports: [PlatformContextService],
|
|
194
|
+
})
|
|
195
|
+
export class PlatformContextModule {}
|
|
196
|
+
`;
|
|
197
|
+
const indexContent = `export * from "./platform-context.types";
|
|
198
|
+
export * from "./platform-context.factory";
|
|
199
|
+
export * from "./platform-context.service";
|
|
200
|
+
export * from "./platform-context.module";
|
|
201
|
+
`;
|
|
202
|
+
const docsContent = `# Platform Request Context
|
|
203
|
+
|
|
204
|
+
This contract carries trusted actor, business, application, and machine identity
|
|
205
|
+
between authentication, Service Access, PARC, owner services, and Relay.
|
|
206
|
+
|
|
207
|
+
## Authority
|
|
208
|
+
|
|
209
|
+
- ZITADEL authenticates and issues the token.
|
|
210
|
+
- Identity Manager resolves the canonical subject.
|
|
211
|
+
- Business Entity resolves canonical business and membership context.
|
|
212
|
+
- Service Access decides service and capability grants.
|
|
213
|
+
- PARC decides action and resource permissions.
|
|
214
|
+
- The owner service enforces its domain invariants and owns the mutation.
|
|
215
|
+
|
|
216
|
+
## Trust Boundary
|
|
217
|
+
|
|
218
|
+
Construct \`VerifiedPlatformPrincipal\` only after signature, issuer, audience,
|
|
219
|
+
expiry, and subject validation. Do not populate actor, business, application, or
|
|
220
|
+
machine identity from caller-selected query parameters or custom identity
|
|
221
|
+
headers. Edge adapters may forward a signed internal context, but the receiving
|
|
222
|
+
service must verify that signature and its intended audience before use.
|
|
223
|
+
|
|
224
|
+
Both Service Access and PARC must allow privileged platform mutations. Their
|
|
225
|
+
decision references and policy versions belong in the owner audit record. Correlation,
|
|
226
|
+
causation, and idempotency metadata must continue into transactional outbox
|
|
227
|
+
events and Relay delivery receipts.
|
|
228
|
+
`;
|
|
229
|
+
//# sourceMappingURL=platform-context.recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-context.recipe.js","sourceRoot":"","sources":["../../../src/commands/recipes/platform-context.recipe.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,gEAsBC;AA1BD,2CAA6B;AAC7B,kDAA0B;AAC1B,uDAA8D;AAEvD,KAAK,UAAU,0BAA0B,CAAC,QAAgB;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,6BAA6B,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAEtD,MAAM,IAAA,sBAAS,EAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,IAAA,sBAAS,EAAC,QAAQ,CAAC,CAAC;IAE1B,MAAM,IAAA,sBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,2BAA2B,CAAC,EAAE,YAAY,CAAC,CAAC;IACnF,MAAM,IAAA,sBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,6BAA6B,CAAC,EAAE,cAAc,CAAC,CAAC;IACvF,MAAM,IAAA,sBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,6BAA6B,CAAC,EAAE,cAAc,CAAC,CAAC;IACvF,MAAM,IAAA,sBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,4BAA4B,CAAC,EAAE,aAAa,CAAC,CAAC;IACrF,MAAM,IAAA,sBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC;IAClE,MAAM,IAAA,sBAAS,EAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,WAAW,CAAC,CAAC;IAEzE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,MAAM,CACV,6GAA6G,CAC9G,CACF,CAAC;AACJ,CAAC;AAED,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDpB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CtB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBtB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;;;CASrB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;CAIpB,CAAC;AAEF,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function applyPlatformParcAuthorizationRecipe(basePath: string): Promise<void>;
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.applyPlatformParcAuthorizationRecipe = applyPlatformParcAuthorizationRecipe;
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
+
const file_utils_1 = require("../../utils/file.utils");
|
|
43
|
+
const platform_context_recipe_1 = require("./platform-context.recipe");
|
|
44
|
+
async function applyPlatformParcAuthorizationRecipe(basePath) {
|
|
45
|
+
await (0, platform_context_recipe_1.applyPlatformContextRecipe)(basePath);
|
|
46
|
+
const authorizationPath = path.join(basePath, 'src/shared/authorization/platform-parc-authorization');
|
|
47
|
+
const docsPath = path.join(basePath, 'docs/platform');
|
|
48
|
+
await (0, file_utils_1.ensureDir)(authorizationPath);
|
|
49
|
+
await (0, file_utils_1.ensureDir)(docsPath);
|
|
50
|
+
await (0, file_utils_1.writeFile)(path.join(authorizationPath, 'parc-authorization.types.ts'), typesContent);
|
|
51
|
+
await (0, file_utils_1.writeFile)(path.join(authorizationPath, 'require-parc-authorization.decorator.ts'), decoratorContent);
|
|
52
|
+
await (0, file_utils_1.writeFile)(path.join(authorizationPath, 'parc-authorization.client.ts'), clientContent);
|
|
53
|
+
await (0, file_utils_1.writeFile)(path.join(authorizationPath, 'platform-parc-authorization.guard.ts'), guardContent);
|
|
54
|
+
await (0, file_utils_1.writeFile)(path.join(authorizationPath, 'platform-parc-authorization.module.ts'), moduleContent);
|
|
55
|
+
await (0, file_utils_1.writeFile)(path.join(authorizationPath, 'index.ts'), indexContent);
|
|
56
|
+
await (0, file_utils_1.writeFile)(path.join(docsPath, 'platform-parc-authorization.md'), docsContent);
|
|
57
|
+
const envExamplePath = path.join(basePath, '.env.example');
|
|
58
|
+
const fallbackExamplePath = path.join(basePath, '.env.platform-parc-authorization.example');
|
|
59
|
+
const targetExamplePath = (await (0, file_utils_1.fileExists)(envExamplePath))
|
|
60
|
+
? fallbackExamplePath
|
|
61
|
+
: envExamplePath;
|
|
62
|
+
await (0, file_utils_1.writeFile)(targetExamplePath, envExampleContent);
|
|
63
|
+
console.log(chalk_1.default.green(' ✓ Platform request context contract'));
|
|
64
|
+
console.log(chalk_1.default.green(' ✓ PARC capability decorator and orchestration guard'));
|
|
65
|
+
console.log(chalk_1.default.green(' ✓ Fail-closed PARC decision client and audit receipt'));
|
|
66
|
+
console.log(chalk_1.default.yellow(' PARC authorizes the requested capability; owner services still enforce and transact their business invariants.'));
|
|
67
|
+
}
|
|
68
|
+
const typesContent = `import { PlatformRequestContext } from "../../platform-context";
|
|
69
|
+
|
|
70
|
+
export interface ParcAuthorizationTarget {
|
|
71
|
+
service: string;
|
|
72
|
+
capability: string;
|
|
73
|
+
action?: string;
|
|
74
|
+
businessId?: string;
|
|
75
|
+
applicationId?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ParcDecisionCheckRequest {
|
|
79
|
+
subjectId: string;
|
|
80
|
+
businessId: string;
|
|
81
|
+
clientAppId: string;
|
|
82
|
+
service: string;
|
|
83
|
+
permission: string;
|
|
84
|
+
action?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ParcDecisionResponse {
|
|
88
|
+
allowed: boolean;
|
|
89
|
+
decisionReference: string;
|
|
90
|
+
decisionId?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface ParcAccessDecisionReceipt extends ParcDecisionResponse {
|
|
94
|
+
authority: "parc";
|
|
95
|
+
allowed: true;
|
|
96
|
+
decidedAt: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface RequestWithParcAuthorization {
|
|
100
|
+
platformContext?: PlatformRequestContext;
|
|
101
|
+
parcAccessDecisionReceipt?: ParcAccessDecisionReceipt;
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
const decoratorContent = `import { SetMetadata } from "@nestjs/common";
|
|
105
|
+
import { ParcAuthorizationTarget } from "./parc-authorization.types";
|
|
106
|
+
|
|
107
|
+
export const PARC_AUTHORIZATION_TARGET = "platform:parc-authorization-target";
|
|
108
|
+
|
|
109
|
+
export const RequireParcAuthorization = (target: ParcAuthorizationTarget) =>
|
|
110
|
+
SetMetadata(PARC_AUTHORIZATION_TARGET, Object.freeze({ ...target }));
|
|
111
|
+
`;
|
|
112
|
+
const clientContent = `import { ForbiddenException, Injectable } from "@nestjs/common";
|
|
113
|
+
import {
|
|
114
|
+
ParcAccessDecisionReceipt,
|
|
115
|
+
ParcAuthorizationTarget,
|
|
116
|
+
ParcDecisionCheckRequest,
|
|
117
|
+
ParcDecisionResponse,
|
|
118
|
+
RequestWithParcAuthorization,
|
|
119
|
+
} from "./parc-authorization.types";
|
|
120
|
+
|
|
121
|
+
@Injectable()
|
|
122
|
+
export class ParcAuthorizationClient {
|
|
123
|
+
async check(
|
|
124
|
+
request: RequestWithParcAuthorization,
|
|
125
|
+
target: ParcAuthorizationTarget,
|
|
126
|
+
): Promise<ParcAccessDecisionReceipt> {
|
|
127
|
+
const actor = request.platformContext?.actor;
|
|
128
|
+
// IAM authority requires PARC's bound relationship path. This legacy
|
|
129
|
+
// endpoint cannot carry its realm, session or current relationship proof.
|
|
130
|
+
if (actor?.authenticatedBy === "iam-orchestrator") {
|
|
131
|
+
throw this.denied();
|
|
132
|
+
}
|
|
133
|
+
const authorizationRequest: ParcDecisionCheckRequest = {
|
|
134
|
+
subjectId: this.requiredString(actor?.subjectId),
|
|
135
|
+
businessId: this.requiredString(target.businessId ?? actor?.businessId),
|
|
136
|
+
clientAppId: this.requiredString(target.applicationId ?? actor?.applicationId),
|
|
137
|
+
service: this.requiredString(target.service),
|
|
138
|
+
permission: this.requiredString(target.capability),
|
|
139
|
+
action: this.optionalString(target.action),
|
|
140
|
+
};
|
|
141
|
+
const baseUrl = this.requiredConfig("PARC_URL").replace(/\\/+$/, "");
|
|
142
|
+
const internalApiKey = this.requiredConfig("PARC_INTERNAL_API_KEY");
|
|
143
|
+
const timeoutMs = this.timeoutMs();
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const response = await fetch(baseUrl + "/v1/decisions/check", {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: {
|
|
149
|
+
Accept: "application/json",
|
|
150
|
+
"Content-Type": "application/json",
|
|
151
|
+
"x-internal-api-key": internalApiKey,
|
|
152
|
+
},
|
|
153
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
154
|
+
body: JSON.stringify(authorizationRequest),
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
throw new Error("PARC decision request failed");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const decision = this.parseDecision(await response.json());
|
|
162
|
+
if (!decision.allowed) {
|
|
163
|
+
throw new Error("PARC denied the requested capability");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
authority: "parc",
|
|
168
|
+
allowed: true,
|
|
169
|
+
decisionReference: decision.decisionReference,
|
|
170
|
+
...(decision.decisionId ? { decisionId: decision.decisionId } : {}),
|
|
171
|
+
decidedAt: new Date().toISOString(),
|
|
172
|
+
};
|
|
173
|
+
} catch {
|
|
174
|
+
throw this.denied();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private parseDecision(payload: unknown): ParcDecisionResponse {
|
|
179
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
180
|
+
throw this.denied();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const record = payload as Record<string, unknown>;
|
|
184
|
+
if (typeof record.allowed !== "boolean") {
|
|
185
|
+
throw this.denied();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const decisionReference = this.requiredString(record.decisionReference);
|
|
189
|
+
let decisionId: string | undefined;
|
|
190
|
+
if (record.decisionId !== undefined) {
|
|
191
|
+
decisionId = this.requiredString(record.decisionId);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
allowed: record.allowed,
|
|
196
|
+
decisionReference,
|
|
197
|
+
...(decisionId ? { decisionId } : {}),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private requiredConfig(name: "PARC_URL" | "PARC_INTERNAL_API_KEY"): string {
|
|
202
|
+
return this.requiredString(process.env[name]);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private timeoutMs(): number {
|
|
206
|
+
const configured = this.optionalString(process.env.PARC_TIMEOUT_MS);
|
|
207
|
+
if (!configured) {
|
|
208
|
+
return 3000;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const timeoutMs = Number(configured);
|
|
212
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
213
|
+
throw this.denied();
|
|
214
|
+
}
|
|
215
|
+
return timeoutMs;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private requiredString(value: unknown): string {
|
|
219
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
220
|
+
throw this.denied();
|
|
221
|
+
}
|
|
222
|
+
return value.trim();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private optionalString(value: unknown): string | undefined {
|
|
226
|
+
if (value === undefined) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
return this.requiredString(value);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private denied(): ForbiddenException {
|
|
233
|
+
return new ForbiddenException("PARC authorization denied");
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`;
|
|
237
|
+
const guardContent = `import {
|
|
238
|
+
CanActivate,
|
|
239
|
+
ExecutionContext,
|
|
240
|
+
ForbiddenException,
|
|
241
|
+
Injectable,
|
|
242
|
+
} from "@nestjs/common";
|
|
243
|
+
import { Reflector } from "@nestjs/core";
|
|
244
|
+
import { ParcAuthorizationClient } from "./parc-authorization.client";
|
|
245
|
+
import { PARC_AUTHORIZATION_TARGET } from "./require-parc-authorization.decorator";
|
|
246
|
+
import {
|
|
247
|
+
ParcAuthorizationTarget,
|
|
248
|
+
RequestWithParcAuthorization,
|
|
249
|
+
} from "./parc-authorization.types";
|
|
250
|
+
|
|
251
|
+
@Injectable()
|
|
252
|
+
export class PlatformParcAuthorizationGuard implements CanActivate {
|
|
253
|
+
constructor(
|
|
254
|
+
private readonly reflector: Reflector,
|
|
255
|
+
private readonly client: ParcAuthorizationClient,
|
|
256
|
+
) {}
|
|
257
|
+
|
|
258
|
+
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
259
|
+
const request = context.switchToHttp().getRequest<RequestWithParcAuthorization>();
|
|
260
|
+
const target = this.reflector.getAllAndOverride<ParcAuthorizationTarget>(
|
|
261
|
+
PARC_AUTHORIZATION_TARGET,
|
|
262
|
+
[context.getHandler(), context.getClass()],
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
if (!target) {
|
|
266
|
+
throw new ForbiddenException("PARC authorization target is required");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const receipt = await this.client.check(request, target);
|
|
270
|
+
request.parcAccessDecisionReceipt = receipt;
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
`;
|
|
275
|
+
const moduleContent = `import { Module } from "@nestjs/common";
|
|
276
|
+
import { PlatformContextModule } from "../../platform-context";
|
|
277
|
+
import { ParcAuthorizationClient } from "./parc-authorization.client";
|
|
278
|
+
import { PlatformParcAuthorizationGuard } from "./platform-parc-authorization.guard";
|
|
279
|
+
|
|
280
|
+
@Module({
|
|
281
|
+
imports: [PlatformContextModule],
|
|
282
|
+
providers: [ParcAuthorizationClient, PlatformParcAuthorizationGuard],
|
|
283
|
+
exports: [ParcAuthorizationClient, PlatformParcAuthorizationGuard],
|
|
284
|
+
})
|
|
285
|
+
export class PlatformParcAuthorizationModule {}
|
|
286
|
+
`;
|
|
287
|
+
const indexContent = `export * from "./parc-authorization.types";
|
|
288
|
+
export * from "./require-parc-authorization.decorator";
|
|
289
|
+
export * from "./parc-authorization.client";
|
|
290
|
+
export * from "./platform-parc-authorization.guard";
|
|
291
|
+
export * from "./platform-parc-authorization.module";
|
|
292
|
+
`;
|
|
293
|
+
const envExampleContent = `PARC_URL=
|
|
294
|
+
PARC_INTERNAL_API_KEY=
|
|
295
|
+
PARC_TIMEOUT_MS=3000
|
|
296
|
+
`;
|
|
297
|
+
const docsContent = `# Platform PARC Authorization
|
|
298
|
+
|
|
299
|
+
Apply this guard only after trusted authentication and platform-context
|
|
300
|
+
construction. The guard reads the decorator target, delegates the decision to
|
|
301
|
+
PARC, and attaches the successful receipt at
|
|
302
|
+
\`request.parcAccessDecisionReceipt\`. It does not read identity from headers or
|
|
303
|
+
query parameters and it does not contain owner business rules.
|
|
304
|
+
|
|
305
|
+
## Usage
|
|
306
|
+
|
|
307
|
+
Import \`PlatformParcAuthorizationModule\`, then decorate a controller or handler:
|
|
308
|
+
|
|
309
|
+
\`\`\`typescript
|
|
310
|
+
@RequireParcAuthorization({
|
|
311
|
+
service: "owner-service",
|
|
312
|
+
capability: "records.write",
|
|
313
|
+
action: "create",
|
|
314
|
+
})
|
|
315
|
+
@UseGuards(PlatformParcAuthorizationGuard)
|
|
316
|
+
\`\`\`
|
|
317
|
+
|
|
318
|
+
The trusted actor subject comes from \`request.platformContext.actor.subjectId\`.
|
|
319
|
+
This legacy decision transport rejects \`iam-orchestrator\` actors before sending
|
|
320
|
+
any request. IAM authority requires PARC's bound decision integration with its
|
|
321
|
+
realm, session and current relationship evidence; changing the actor label or
|
|
322
|
+
falling back to this endpoint is not supported.
|
|
323
|
+
The target may narrow business and application scope; otherwise the actor's
|
|
324
|
+
trusted platform context supplies them. Missing context, required scope, PARC
|
|
325
|
+
configuration, transport success, or a valid allow receipt denies access.
|
|
326
|
+
|
|
327
|
+
## Ownership And Audit
|
|
328
|
+
|
|
329
|
+
\`PARC_INTERNAL_API_KEY\` authenticates this service to PARC transport. It is not
|
|
330
|
+
the user's authorization and must never be treated as an allow decision. PARC
|
|
331
|
+
decides the requested service capability and optional action; it does not own
|
|
332
|
+
business truth.
|
|
333
|
+
|
|
334
|
+
Owner invariants still apply after PARC allows access. The owner service must
|
|
335
|
+
record \`decisionReference\` in the same owner transaction as the protected
|
|
336
|
+
mutation and its outbox/audit record. The optional \`decisionId\` is retained
|
|
337
|
+
only for compatibility; \`decisionReference\` is the required audit reference.
|
|
338
|
+
`;
|
|
339
|
+
//# sourceMappingURL=platform-parc-authorization.recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-parc-authorization.recipe.js","sourceRoot":"","sources":["../../../src/commands/recipes/platform-parc-authorization.recipe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function applyPlatformParcBoundAuthorizationRecipe(basePath: string, dryRun?: boolean): Promise<void>;
|