@things-factory/integration-base 10.1.154 → 10.1.155
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/dist-server/controllers/scenario-controller.js +1 -2
- package/dist-server/controllers/scenario-controller.js.map +1 -1
- package/dist-server/engine/connection-manager.js +1 -2
- package/dist-server/engine/connection-manager.js.map +1 -1
- package/dist-server/engine/index.d.ts +0 -1
- package/dist-server/engine/index.js +1 -3
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/service/connection/connection-mutation.js +2 -3
- package/dist-server/service/connection/connection-mutation.js.map +1 -1
- package/dist-server/service/connection/connection-query.js +2 -3
- package/dist-server/service/connection/connection-query.js.map +1 -1
- package/dist-server/service/connection/connection-secrets.js +1 -2
- package/dist-server/service/connection/connection-secrets.js.map +1 -1
- package/dist-server/service/connection/connection-subscription.js +1 -2
- package/dist-server/service/connection/connection-subscription.js.map +1 -1
- package/dist-server/service/connection/connection.js +1 -2
- package/dist-server/service/connection/connection.js.map +1 -1
- package/dist-server/service/domain-attribute/domain-attribute-query.js +2 -4
- package/dist-server/service/domain-attribute/domain-attribute-query.js.map +1 -1
- package/dist-server/service/scenario/scenario-query.js +2 -3
- package/dist-server/service/scenario/scenario-query.js.map +1 -1
- package/dist-server/service/scenario/scenario-version-query.js +4 -5
- package/dist-server/service/scenario/scenario-version-query.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-type.js +2 -3
- package/dist-server/service/scenario-instance/scenario-instance-type.js.map +1 -1
- package/dist-server/service/secret-hint.d.ts +0 -12
- package/dist-server/service/secret-hint.js +0 -26
- package/dist-server/service/secret-hint.js.map +1 -1
- package/dist-server/service/step/step-query.js +2 -3
- package/dist-server/service/step/step-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/dist-server/utils/domain-inheritance.d.ts +0 -29
- package/dist-server/utils/domain-inheritance.js +0 -98
- package/dist-server/utils/domain-inheritance.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-subscription.js","sourceRoot":"","sources":["../../../server/service/connection/connection-subscription.ts"],"names":[],"mappings":";;;;AAAA,+CAA2C;AAC3C,+CAAgE;AAChE,qCAA4B;AAE5B,
|
|
1
|
+
{"version":3,"file":"connection-subscription.js","sourceRoot":"","sources":["../../../server/service/connection/connection-subscription.ts"],"names":[],"mappings":"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","sourcesContent":["import { filter, pipe } from 'graphql-yoga'\nimport { Arg, Resolver, Root, Subscription } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository, Log, pubsub, getDomainIdsWithAncestors } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionState } from './connection-type'\n\nconst debug = require('debug')('things-factory:integration:connection-subscription')\n\n@Resolver(Connection)\nexport class ConnectionSubscription {\n @Subscription({\n description: 'Subscribes to the state changes of connections.',\n subscribe: async ({ args, context, info }) => {\n const { domain, user } = context.state\n const { name } = args\n const subdomain = domain?.subdomain\n\n debug('subscribe', subdomain)\n if (!domain) {\n throw new Error('domain required.')\n }\n\n if (!user.domains?.find(d => d.subdomain === subdomain) && !(await process.superUserGranted(domain, user))) {\n throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)\n }\n\n // ancestor 도메인 ids 를 한 번만 계산하여 재사용 (subscribe 는 sync 라 lazy memoize)\n let ancestorIdsPromise: Promise<string[]> | null = null\n const resolveAncestorIds = () =>\n (ancestorIdsPromise ||= getDomainIdsWithAncestors(domain))\n\n process.nextTick(async () => {\n const domainIds = await resolveAncestorIds()\n var where: any = { domain: { id: In(domainIds) } }\n if (name) {\n where['name'] = name\n }\n\n var connections = await getRepository(Connection).find({\n where,\n relations: ['domain', 'edge']\n })\n\n connections.forEach(connection => {\n pubsub.publish('connection-state', {\n connectionState: {\n ...connection,\n domain /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED,\n timestamp: new Date()\n }\n })\n })\n })\n\n return pipe(\n pubsub.subscribe('connection-state'),\n filter(async (payload: { connectionState: ConnectionState }) => {\n const { domain: pdomain, name: pname } = payload.connectionState\n const domainIds = await resolveAncestorIds()\n\n return (!name || name === pname) && domainIds.includes(pdomain?.id)\n })\n )\n }\n })\n connectionState(\n @Root() payload: { connectionState: ConnectionState },\n @Arg('name', { nullable: true }) name: string\n ): ConnectionState {\n return payload.connectionState\n }\n\n @Subscription({\n description: 'Subscribes to log messages from connections.',\n subscribe: async ({ args, context, info }) => {\n const { domain, user } = context.state\n const { level } = args\n\n const subdomain = domain?.subdomain\n\n debug('subscribe', subdomain)\n\n if (!domain) {\n throw new Error('domain required')\n }\n\n if (!user.domains?.find(d => d.subdomain === subdomain) && !(await process.superUserGranted(domain, user))) {\n throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)\n }\n\n return pipe(\n pubsub.subscribe('connection-log'),\n filter(async (payload: { log: Log }) => {\n // TODO support domain filtering\n const { /* source, */ level: plevel } = payload.log\n // const { domain: pdomain } = source\n\n // if (subdomain !== pdomain?.subdomain) {\n // return false\n // }\n\n if (level && level !== plevel) {\n return false\n }\n\n return true\n })\n )\n }\n })\n connectionLog(@Root() payload: { log: Log }, @Arg('level', { nullable: true }) level: string): Log {\n return payload.log\n }\n}\n"]}
|
|
@@ -10,7 +10,6 @@ const shell_1 = require("@things-factory/shell");
|
|
|
10
10
|
const engine_1 = require("../../engine");
|
|
11
11
|
const integration_runtime_1 = require("../../engine/integration-runtime");
|
|
12
12
|
const proxy_connector_1 = require("../../engine/connector/proxy-connector");
|
|
13
|
-
const domain_inheritance_1 = require("../../utils/domain-inheritance");
|
|
14
13
|
const ORMCONFIG = env_1.config.get('ormconfig', {});
|
|
15
14
|
const DATABASE_TYPE = ORMCONFIG.type;
|
|
16
15
|
var ConnectionStatus;
|
|
@@ -96,7 +95,7 @@ let Connection = class Connection {
|
|
|
96
95
|
const envVarKey = `Connection::${this.name}::${key}`;
|
|
97
96
|
const domain = await (0, shell_1.getRepository)(shell_1.Domain).findOne({ where: { id: this.domainId } });
|
|
98
97
|
if (domain) {
|
|
99
|
-
const value = await (0,
|
|
98
|
+
const value = await (0, shell_1.lookupDomainEnvVar)(domain, envVarKey);
|
|
100
99
|
if (value !== undefined) {
|
|
101
100
|
// params 에 명시값이 있는데 EnvVar 가 override 한 경우 진단 로그
|
|
102
101
|
const paramValue = this.params?.[key];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../server/service/connection/connection.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, ObjectType, registerEnumType } from 'type-graphql'\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\n\nimport { User, Appliance } from '@things-factory/auth-base'\nimport { config } from '@things-factory/env'\nimport { Domain, EnvVar, ScalarObject, encryptJsonTransformer, getRepository } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine'\nimport { IntegrationRuntime } from '../../engine/integration-runtime'\nimport { ProxyConnector } from '../../engine/connector/proxy-connector'\nimport { lookupDomainEnvVar } from '../../utils/domain-inheritance'\n\nconst ORMCONFIG = config.get('ormconfig', {})\nconst DATABASE_TYPE = ORMCONFIG.type\n\nexport enum ConnectionStatus {\n CONNECTED = 'CONNECTED', // Represents an active, established connection.\n DISCONNECTED = 'DISCONNECTED' // Represents a terminated or inactive connection.\n}\n\nregisterEnumType(ConnectionStatus, {\n name: 'ConnectionStatus',\n description: 'Enumeration of possible states for a connection.'\n})\n\n/**\n * 자식 도메인이 부모의 Connection 정의를 inherit 할 때 동작.\n * - ISOLATE: 자식별로 새 instance 생성. cookies/세션·EnvVar 자격증명 격리. HeadlessConnector\n * 같은 stateful connector 의 자연 default.\n * - SHARE: 부모의 단일 instance 를 자식들이 공유. cookies/params 공통. 공용 외부 API\n * (stateless) connector 의 자연 default.\n *\n * null 이면 Connector.inheritanceMode default 적용, 그것도 없으면 ISOLATE.\n */\nexport enum ConnectionInheritanceMode {\n ISOLATE = 'isolate',\n SHARE = 'share'\n}\n\nregisterEnumType(ConnectionInheritanceMode, {\n name: 'ConnectionInheritanceMode',\n description:\n 'Child domain inheritance mode — ISOLATE: per-child instance with isolated session/credentials. SHARE: single parent instance reused by all children.'\n})\n\n@Entity()\n@Index('ix_connection_0', (connection: Connection) => [connection.domain, connection.name], { unique: true })\n@ObjectType({ description: 'Represents a configured connection to an external system or service.' })\nexport class Connection {\n /**\n * Unique identifier for the connection, generated in UUID format.\n */\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier for the connection.' })\n readonly id: string\n\n /**\n * Many-to-One relationship with the Domain entity.\n */\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain to which this connection belongs.' })\n domain: Domain\n\n /**\n * Stores the ID of the associated Domain.\n */\n @RelationId((connection: Connection) => connection.domain)\n domainId: string\n\n /**\n * The name of the connection.\n */\n @Column()\n @Field({ description: 'The name of the connection.' })\n name: string\n\n /**\n * Optional description for the connection.\n */\n @Column({\n nullable: true\n })\n @Field({ nullable: true, description: 'A detailed description of the connection.' })\n description: string\n\n /**\n * The type of the connection.\n */\n @Column()\n @Field({ nullable: true, description: 'The type of the connection (e.g., tcp, http, mqtt).' })\n type: string\n\n /**\n * Many-to-One relationship with the Appliance entity which delegate the connection. Optional field.\n */\n @ManyToOne(type => Appliance, { nullable: true })\n @Field({ nullable: true, description: 'The edge appliance that delegates this connection, if any.' })\n edge: Appliance\n\n /**\n * Stores the ID of the Appliance who delegate the connection.\n */\n @RelationId((connection: Connection) => connection.edge)\n edgeId: string\n\n /**\n * The endpoint for the connection.\n */\n @Column()\n @Field({ nullable: true, description: 'The endpoint URL or address for the connection.' })\n endpoint: string\n\n /**\n * Whether to automatically connect when the application starts\n */\n @Column({ nullable: true })\n @Field({\n nullable: true,\n description: 'Whether to automatically connect when the application starts'\n })\n active: boolean\n\n /**\n * Indicates whether the connection should be created on-demand when needed.\n */\n @Column({ default: false })\n @Field({\n nullable: true,\n description: 'When true, connection is created on-demand when needed and cleaned up after use.'\n })\n onDemand: boolean\n\n /**\n * 자식 도메인이 부모 도메인의 Connection 정의를 inherit 할 때의 인스턴스 정책.\n *\n * - `ISOLATE`: 자식 도메인마다 새 인스턴스 생성. cookies/세션 상태와 useDomainAttribute\n * 기반 자격증명이 자식 도메인 단위로 격리됨. 자식별 다른 자격증명·세션이 필요한 stateful\n * connector (예: HeadlessConnector — Allbaro / KISCON 등) 의 자연 default.\n *\n * - `SHARE`: 자식 도메인이 부모의 단일 인스턴스를 그대로 공유. cookies/세션/params 모두\n * 부모 인스턴스의 것이 자식에도 그대로 적용. useDomainAttribute 기반 자식 EnvVar\n * override 는 무효화됨. 공용 자원 (단일 브로커·서버) 또는 stateless connector\n * (HTTP, GraphQL) 의 자연 default.\n *\n * - `null`: Connector 가 선언한 default 적용. Connector 도 default 가 없으면 ISOLATE\n * 폴백 (격리·안전 우선).\n *\n * 우선순위: Connection.inheritanceMode → Connector.inheritanceMode → ISOLATE.\n *\n * **호환성**: 본 컬럼은 platform v10 시점에 도입. 그 이전에 만들어진 모든 Connection\n * 레코드는 NULL 값으로 들어가 위 폴백 체인에 따라 ISOLATE 가 적용되어 기존 거동\n * (자식별 격리 인스턴스 생성) 이 그대로 유지됨. SHARE 는 명시적으로 켜야만 발동되는\n * opt-in.\n *\n * **데이터 격리 주의**: SHARE 를 켤 경우 자식 도메인들은 같은 인스턴스의 cookies/세션을\n * 공유함. 자식 도메인별로 다른 외부 자격증명을 사용하려는 경우 SHARE 는 부적절.\n */\n @Column({ type: 'varchar', nullable: true })\n @Field(type => ConnectionInheritanceMode, {\n nullable: true,\n description:\n 'Inheritance mode for child domains. ISOLATE = per-child instance with isolated session. SHARE = shared parent instance. null = use Connector default (falls back to ISOLATE).'\n })\n inheritanceMode?: ConnectionInheritanceMode\n\n /**\n * The status of the connection, using the ConnectionStatus type.\n */\n @Field({ nullable: true, description: 'The current status of the connection (e.g., CONNECTED, DISCONNECTED).' })\n state: ConnectionStatus\n\n /**\n * Additional parameters for the connection, stored as a JSON string.\n *\n * [Caution]\n * 이 컬럼타입은 postgres 데이터베이스에서는 varchar 타입을 유지한다.\n * 이는 데이터베이스 타입을 변경하면 기존 데이터가 손실될 수 있기 때문이다.\n */\n // 비밀값은 이 칸에 두지 않는다 (ADR-0112). spec 이 `type: 'secret'` 인 칸은 쓰기에서 거절되고\n // EnvVar `Connection::<name>::<param>`(늘 암호문) 에 둔다. 읽기에서도 빠진다 — connection-secrets.ts.\n // 그래서 이 칸 전체를 암호화하지 않는다.\n @Column({\n type: DATABASE_TYPE == 'postgres' ? 'varchar' : 'simple-json',\n nullable: true,\n transformer:\n DATABASE_TYPE == 'postgres'\n ? {\n to: (value: any) => JSON.stringify(value),\n from: (value: string) => {\n try {\n return JSON.parse(value)\n } catch (error) {\n return null\n }\n }\n }\n : undefined\n })\n @Field(type => ScalarObject, { nullable: true, description: 'A key-value map of parameters for the connection.' })\n params: { [key: string]: any }\n\n /**\n * The date and time when the connection was created.\n */\n @CreateDateColumn()\n @Field({ nullable: true, description: 'The timestamp when the connection was created.' })\n createdAt: Date\n\n /**\n * The date and time when the connection was last updated.\n */\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'The timestamp when the connection was last updated.' })\n updatedAt: Date\n\n /**\n * Many-to-One relationship with the User entity who created the connection. Optional field.\n */\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true, description: 'The user who created the connection.' })\n creator: User\n\n /**\n * Stores the ID of the User who created the connection.\n */\n @RelationId((connection: Connection) => connection.creator)\n creatorId: string\n\n /**\n * Many-to-One relationship with the User entity who last updated the connection.\n * Optional field.\n */\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true, description: 'The user who last updated the connection.' })\n updater: User\n\n /**\n * Stores the ID of the User who last updated the connection.\n *\n */\n @RelationId((connection: Connection) => connection.updater)\n updaterId: string\n\n /**\n * Runtime marker — DB 컬럼이 아니라 메모리 전용 플래그.\n *\n * 자식 도메인이 자기 Connection 레코드 없이 부모의 정의를 inherit 할 때,\n * `ConnectionManager.getConnectionEntityByName` 의 parent fallback 분기가\n * 부모 entity 의 clone 에 이 marker (= 부모의 domainId) 를 부착한다.\n *\n * `getConnectionInstanceByName` 가 이 marker 가 truthy 인 entity 를 보면\n * onDemand 플래그와 동일하게 자식 도메인용 instance 를 자동 생성한다 — 운영자가\n * 부모 record 의 onDemand 를 별도로 켤 필요 없이 inheritance 가 자연스럽게 동작.\n *\n * inheritanceMode = ISOLATE 인 경우에만 부착.\n */\n __inheritedFrom?: string\n\n /**\n * Runtime marker — DB 컬럼이 아니라 메모리 전용 플래그. SHARE 모드의 짝.\n *\n * 자식 도메인이 부모의 Connection 정의를 inherit 할 때, inheritanceMode = SHARE 면\n * 자식이 부모의 단일 instance 를 그대로 사용. parent fallback 분기가 부모 entity 를\n * 그대로 반환하면서 이 marker (= 부모의 domainId) 를 부착.\n *\n * `getConnectionInstanceByName` 가 이 marker 를 보면 자식 instance 자동 생성 없이\n * `connections[__sharedFrom][name]` 를 그대로 반환 — 부모·자식이 같은 instance.\n *\n * inheritanceMode = SHARE 인 경우에만 부착. `__inheritedFrom` 과 mutually exclusive.\n */\n __sharedFrom?: string\n\n /**\n * Asynchronous method to establish the connection.\n *\n */\n async connect() {\n /* Every connect — at boot, from the screen, from a scenario — comes through here. */\n IntegrationRuntime.assertEnabled(`connecting \"${this.name}\"`)\n const { type, edge } = this\n const connector = edge ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n\n await connector.connect({\n ...this,\n params: await this.getResolvedParameters() // 🔐 해결된 파라미터 사용\n })\n }\n\n /**\n * @brief Asynchronous method to disconnect the connection.\n *\n */\n async disconnect() {\n try {\n const { type, edge } = this\n const connector = edge ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n await connector.disconnect(this)\n } finally {\n }\n }\n\n /**\n * Gets a parameter value with EnvVar override support.\n *\n * **Priority (`useDomainAttribute: true` 인 필드)**:\n * 1. **EnvVar** — ancestor closest-wins (자식 도메인이 가장 가까움)\n * 2. **params** 명시값 (parent Connection 의 default 역할)\n * 3. defaultValue\n *\n * **Priority (`useDomainAttribute: false` 또는 미지정 필드)**:\n * 1. **params** 명시값\n * 2. defaultValue\n *\n * 의미론: `useDomainAttribute: true` 는 \"이 필드는 도메인별 override 가능\" 선언.\n * 따라서 EnvVar 가 본 소스, params 는 모든 자손에 동일 적용되는 default.\n * 자식 도메인 EnvVar override 가 자연스럽게 동작 (시공사 → 프로젝트 자격증명 차별화 등).\n *\n * @param key - The parameter key\n * @param defaultValue - Optional default value\n * @returns The parameter value or default value\n */\n async getParameter(key: string, defaultValue?: any): Promise<any> {\n const connector = ConnectionManager.getConnector(this.type)\n const paramSpec = connector?.parameterSpec?.find(spec => spec.name === key)\n\n // 1. useDomainAttribute 필드는 EnvVar 우선 조회 (ancestor closest-wins)\n if (paramSpec?.useDomainAttribute) {\n const envVarKey = `Connection::${this.name}::${key}`\n const domain = await getRepository(Domain).findOne({ where: { id: this.domainId } })\n if (domain) {\n const value = await lookupDomainEnvVar(domain, envVarKey)\n if (value !== undefined) {\n // params 에 명시값이 있는데 EnvVar 가 override 한 경우 진단 로그\n const paramValue = this.params?.[key]\n if (paramValue !== null && paramValue !== undefined && paramValue !== '') {\n ConnectionManager.logger.info(\n `[domain-attr] Connection '${this.name}'.${key}: params default overridden by EnvVar (domain='${domain.subdomain || domain.id}')`\n )\n }\n return value\n }\n }\n }\n\n // 2. params 명시값 (default 역할)\n if (this.params?.[key] !== null && this.params?.[key] !== undefined && this.params?.[key] !== '') {\n return this.params[key]\n }\n\n // 3. defaultValue\n return defaultValue\n }\n\n /**\n * Gets all parameters with resolved values (params + Domain attributes).\n *\n * @returns Object with all resolved parameter values\n */\n async getResolvedParameters(): Promise<{ [key: string]: any }> {\n const resolved = {}\n\n const connector = ConnectionManager.getConnector(this.type)\n const paramSpecs = connector?.parameterSpec || []\n\n for (const spec of paramSpecs) {\n const key = spec.name\n resolved[key] = await this.getParameter(key)\n }\n\n return resolved\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../server/service/connection/connection.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, ObjectType, registerEnumType } from 'type-graphql'\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn\n} from 'typeorm'\n\nimport { User, Appliance } from '@things-factory/auth-base'\nimport { config } from '@things-factory/env'\nimport {\n Domain,\n EnvVar,\n ScalarObject,\n encryptJsonTransformer,\n getRepository,\n lookupDomainEnvVar\n} from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine'\nimport { IntegrationRuntime } from '../../engine/integration-runtime'\nimport { ProxyConnector } from '../../engine/connector/proxy-connector'\n\nconst ORMCONFIG = config.get('ormconfig', {})\nconst DATABASE_TYPE = ORMCONFIG.type\n\nexport enum ConnectionStatus {\n CONNECTED = 'CONNECTED', // Represents an active, established connection.\n DISCONNECTED = 'DISCONNECTED' // Represents a terminated or inactive connection.\n}\n\nregisterEnumType(ConnectionStatus, {\n name: 'ConnectionStatus',\n description: 'Enumeration of possible states for a connection.'\n})\n\n/**\n * 자식 도메인이 부모의 Connection 정의를 inherit 할 때 동작.\n * - ISOLATE: 자식별로 새 instance 생성. cookies/세션·EnvVar 자격증명 격리. HeadlessConnector\n * 같은 stateful connector 의 자연 default.\n * - SHARE: 부모의 단일 instance 를 자식들이 공유. cookies/params 공통. 공용 외부 API\n * (stateless) connector 의 자연 default.\n *\n * null 이면 Connector.inheritanceMode default 적용, 그것도 없으면 ISOLATE.\n */\nexport enum ConnectionInheritanceMode {\n ISOLATE = 'isolate',\n SHARE = 'share'\n}\n\nregisterEnumType(ConnectionInheritanceMode, {\n name: 'ConnectionInheritanceMode',\n description:\n 'Child domain inheritance mode — ISOLATE: per-child instance with isolated session/credentials. SHARE: single parent instance reused by all children.'\n})\n\n@Entity()\n@Index('ix_connection_0', (connection: Connection) => [connection.domain, connection.name], { unique: true })\n@ObjectType({ description: 'Represents a configured connection to an external system or service.' })\nexport class Connection {\n /**\n * Unique identifier for the connection, generated in UUID format.\n */\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier for the connection.' })\n readonly id: string\n\n /**\n * Many-to-One relationship with the Domain entity.\n */\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain to which this connection belongs.' })\n domain: Domain\n\n /**\n * Stores the ID of the associated Domain.\n */\n @RelationId((connection: Connection) => connection.domain)\n domainId: string\n\n /**\n * The name of the connection.\n */\n @Column()\n @Field({ description: 'The name of the connection.' })\n name: string\n\n /**\n * Optional description for the connection.\n */\n @Column({\n nullable: true\n })\n @Field({ nullable: true, description: 'A detailed description of the connection.' })\n description: string\n\n /**\n * The type of the connection.\n */\n @Column()\n @Field({ nullable: true, description: 'The type of the connection (e.g., tcp, http, mqtt).' })\n type: string\n\n /**\n * Many-to-One relationship with the Appliance entity which delegate the connection. Optional field.\n */\n @ManyToOne(type => Appliance, { nullable: true })\n @Field({ nullable: true, description: 'The edge appliance that delegates this connection, if any.' })\n edge: Appliance\n\n /**\n * Stores the ID of the Appliance who delegate the connection.\n */\n @RelationId((connection: Connection) => connection.edge)\n edgeId: string\n\n /**\n * The endpoint for the connection.\n */\n @Column()\n @Field({ nullable: true, description: 'The endpoint URL or address for the connection.' })\n endpoint: string\n\n /**\n * Whether to automatically connect when the application starts\n */\n @Column({ nullable: true })\n @Field({\n nullable: true,\n description: 'Whether to automatically connect when the application starts'\n })\n active: boolean\n\n /**\n * Indicates whether the connection should be created on-demand when needed.\n */\n @Column({ default: false })\n @Field({\n nullable: true,\n description: 'When true, connection is created on-demand when needed and cleaned up after use.'\n })\n onDemand: boolean\n\n /**\n * 자식 도메인이 부모 도메인의 Connection 정의를 inherit 할 때의 인스턴스 정책.\n *\n * - `ISOLATE`: 자식 도메인마다 새 인스턴스 생성. cookies/세션 상태와 useDomainAttribute\n * 기반 자격증명이 자식 도메인 단위로 격리됨. 자식별 다른 자격증명·세션이 필요한 stateful\n * connector (예: HeadlessConnector — Allbaro / KISCON 등) 의 자연 default.\n *\n * - `SHARE`: 자식 도메인이 부모의 단일 인스턴스를 그대로 공유. cookies/세션/params 모두\n * 부모 인스턴스의 것이 자식에도 그대로 적용. useDomainAttribute 기반 자식 EnvVar\n * override 는 무효화됨. 공용 자원 (단일 브로커·서버) 또는 stateless connector\n * (HTTP, GraphQL) 의 자연 default.\n *\n * - `null`: Connector 가 선언한 default 적용. Connector 도 default 가 없으면 ISOLATE\n * 폴백 (격리·안전 우선).\n *\n * 우선순위: Connection.inheritanceMode → Connector.inheritanceMode → ISOLATE.\n *\n * **호환성**: 본 컬럼은 platform v10 시점에 도입. 그 이전에 만들어진 모든 Connection\n * 레코드는 NULL 값으로 들어가 위 폴백 체인에 따라 ISOLATE 가 적용되어 기존 거동\n * (자식별 격리 인스턴스 생성) 이 그대로 유지됨. SHARE 는 명시적으로 켜야만 발동되는\n * opt-in.\n *\n * **데이터 격리 주의**: SHARE 를 켤 경우 자식 도메인들은 같은 인스턴스의 cookies/세션을\n * 공유함. 자식 도메인별로 다른 외부 자격증명을 사용하려는 경우 SHARE 는 부적절.\n */\n @Column({ type: 'varchar', nullable: true })\n @Field(type => ConnectionInheritanceMode, {\n nullable: true,\n description:\n 'Inheritance mode for child domains. ISOLATE = per-child instance with isolated session. SHARE = shared parent instance. null = use Connector default (falls back to ISOLATE).'\n })\n inheritanceMode?: ConnectionInheritanceMode\n\n /**\n * The status of the connection, using the ConnectionStatus type.\n */\n @Field({ nullable: true, description: 'The current status of the connection (e.g., CONNECTED, DISCONNECTED).' })\n state: ConnectionStatus\n\n /**\n * Additional parameters for the connection, stored as a JSON string.\n *\n * [Caution]\n * 이 컬럼타입은 postgres 데이터베이스에서는 varchar 타입을 유지한다.\n * 이는 데이터베이스 타입을 변경하면 기존 데이터가 손실될 수 있기 때문이다.\n */\n // 비밀값은 이 칸에 두지 않는다 (ADR-0112). spec 이 `type: 'secret'` 인 칸은 쓰기에서 거절되고\n // EnvVar `Connection::<name>::<param>`(늘 암호문) 에 둔다. 읽기에서도 빠진다 — connection-secrets.ts.\n // 그래서 이 칸 전체를 암호화하지 않는다.\n @Column({\n type: DATABASE_TYPE == 'postgres' ? 'varchar' : 'simple-json',\n nullable: true,\n transformer:\n DATABASE_TYPE == 'postgres'\n ? {\n to: (value: any) => JSON.stringify(value),\n from: (value: string) => {\n try {\n return JSON.parse(value)\n } catch (error) {\n return null\n }\n }\n }\n : undefined\n })\n @Field(type => ScalarObject, { nullable: true, description: 'A key-value map of parameters for the connection.' })\n params: { [key: string]: any }\n\n /**\n * The date and time when the connection was created.\n */\n @CreateDateColumn()\n @Field({ nullable: true, description: 'The timestamp when the connection was created.' })\n createdAt: Date\n\n /**\n * The date and time when the connection was last updated.\n */\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'The timestamp when the connection was last updated.' })\n updatedAt: Date\n\n /**\n * Many-to-One relationship with the User entity who created the connection. Optional field.\n */\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true, description: 'The user who created the connection.' })\n creator: User\n\n /**\n * Stores the ID of the User who created the connection.\n */\n @RelationId((connection: Connection) => connection.creator)\n creatorId: string\n\n /**\n * Many-to-One relationship with the User entity who last updated the connection.\n * Optional field.\n */\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true, description: 'The user who last updated the connection.' })\n updater: User\n\n /**\n * Stores the ID of the User who last updated the connection.\n *\n */\n @RelationId((connection: Connection) => connection.updater)\n updaterId: string\n\n /**\n * Runtime marker — DB 컬럼이 아니라 메모리 전용 플래그.\n *\n * 자식 도메인이 자기 Connection 레코드 없이 부모의 정의를 inherit 할 때,\n * `ConnectionManager.getConnectionEntityByName` 의 parent fallback 분기가\n * 부모 entity 의 clone 에 이 marker (= 부모의 domainId) 를 부착한다.\n *\n * `getConnectionInstanceByName` 가 이 marker 가 truthy 인 entity 를 보면\n * onDemand 플래그와 동일하게 자식 도메인용 instance 를 자동 생성한다 — 운영자가\n * 부모 record 의 onDemand 를 별도로 켤 필요 없이 inheritance 가 자연스럽게 동작.\n *\n * inheritanceMode = ISOLATE 인 경우에만 부착.\n */\n __inheritedFrom?: string\n\n /**\n * Runtime marker — DB 컬럼이 아니라 메모리 전용 플래그. SHARE 모드의 짝.\n *\n * 자식 도메인이 부모의 Connection 정의를 inherit 할 때, inheritanceMode = SHARE 면\n * 자식이 부모의 단일 instance 를 그대로 사용. parent fallback 분기가 부모 entity 를\n * 그대로 반환하면서 이 marker (= 부모의 domainId) 를 부착.\n *\n * `getConnectionInstanceByName` 가 이 marker 를 보면 자식 instance 자동 생성 없이\n * `connections[__sharedFrom][name]` 를 그대로 반환 — 부모·자식이 같은 instance.\n *\n * inheritanceMode = SHARE 인 경우에만 부착. `__inheritedFrom` 과 mutually exclusive.\n */\n __sharedFrom?: string\n\n /**\n * Asynchronous method to establish the connection.\n *\n */\n async connect() {\n /* Every connect — at boot, from the screen, from a scenario — comes through here. */\n IntegrationRuntime.assertEnabled(`connecting \"${this.name}\"`)\n const { type, edge } = this\n const connector = edge ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n\n await connector.connect({\n ...this,\n params: await this.getResolvedParameters() // 🔐 해결된 파라미터 사용\n })\n }\n\n /**\n * @brief Asynchronous method to disconnect the connection.\n *\n */\n async disconnect() {\n try {\n const { type, edge } = this\n const connector = edge ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n await connector.disconnect(this)\n } finally {\n }\n }\n\n /**\n * Gets a parameter value with EnvVar override support.\n *\n * **Priority (`useDomainAttribute: true` 인 필드)**:\n * 1. **EnvVar** — ancestor closest-wins (자식 도메인이 가장 가까움)\n * 2. **params** 명시값 (parent Connection 의 default 역할)\n * 3. defaultValue\n *\n * **Priority (`useDomainAttribute: false` 또는 미지정 필드)**:\n * 1. **params** 명시값\n * 2. defaultValue\n *\n * 의미론: `useDomainAttribute: true` 는 \"이 필드는 도메인별 override 가능\" 선언.\n * 따라서 EnvVar 가 본 소스, params 는 모든 자손에 동일 적용되는 default.\n * 자식 도메인 EnvVar override 가 자연스럽게 동작 (시공사 → 프로젝트 자격증명 차별화 등).\n *\n * @param key - The parameter key\n * @param defaultValue - Optional default value\n * @returns The parameter value or default value\n */\n async getParameter(key: string, defaultValue?: any): Promise<any> {\n const connector = ConnectionManager.getConnector(this.type)\n const paramSpec = connector?.parameterSpec?.find(spec => spec.name === key)\n\n // 1. useDomainAttribute 필드는 EnvVar 우선 조회 (ancestor closest-wins)\n if (paramSpec?.useDomainAttribute) {\n const envVarKey = `Connection::${this.name}::${key}`\n const domain = await getRepository(Domain).findOne({ where: { id: this.domainId } })\n if (domain) {\n const value = await lookupDomainEnvVar(domain, envVarKey)\n if (value !== undefined) {\n // params 에 명시값이 있는데 EnvVar 가 override 한 경우 진단 로그\n const paramValue = this.params?.[key]\n if (paramValue !== null && paramValue !== undefined && paramValue !== '') {\n ConnectionManager.logger.info(\n `[domain-attr] Connection '${this.name}'.${key}: params default overridden by EnvVar (domain='${domain.subdomain || domain.id}')`\n )\n }\n return value\n }\n }\n }\n\n // 2. params 명시값 (default 역할)\n if (this.params?.[key] !== null && this.params?.[key] !== undefined && this.params?.[key] !== '') {\n return this.params[key]\n }\n\n // 3. defaultValue\n return defaultValue\n }\n\n /**\n * Gets all parameters with resolved values (params + Domain attributes).\n *\n * @returns Object with all resolved parameter values\n */\n async getResolvedParameters(): Promise<{ [key: string]: any }> {\n const resolved = {}\n\n const connector = ConnectionManager.getConnector(this.type)\n const paramSpecs = connector?.parameterSpec || []\n\n for (const spec of paramSpecs) {\n const key = spec.name\n resolved[key] = await this.getParameter(key)\n }\n\n return resolved\n }\n}\n"]}
|
|
@@ -5,9 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const typeorm_1 = require("typeorm");
|
|
7
7
|
const shell_1 = require("@things-factory/shell");
|
|
8
|
-
const domain_inheritance_1 = require("../../utils/domain-inheritance");
|
|
9
8
|
const domain_attribute_type_1 = require("./domain-attribute-type");
|
|
10
|
-
const secret_hint_1 = require("../secret-hint");
|
|
11
9
|
const secret_keys_1 = require("./secret-keys");
|
|
12
10
|
/**
|
|
13
11
|
* EnvVar 키들의 해소 상태를 일괄 조회.
|
|
@@ -32,7 +30,7 @@ let DomainAttributeQuery = class DomainAttributeQuery {
|
|
|
32
30
|
if (!domain || !Array.isArray(keys) || keys.length === 0) {
|
|
33
31
|
return (keys || []).map(key => ({ key, status: 'absent', hasValue: false }));
|
|
34
32
|
}
|
|
35
|
-
const ids = await (0,
|
|
33
|
+
const ids = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
36
34
|
const idIndex = new Map(ids.map((id, idx) => [id, idx]));
|
|
37
35
|
const rows = await (0, shell_1.getRepository)(shell_1.EnvVar).find({
|
|
38
36
|
where: { domain: { id: (0, typeorm_1.In)(ids) }, name: (0, typeorm_1.In)(keys), active: true },
|
|
@@ -61,7 +59,7 @@ let DomainAttributeQuery = class DomainAttributeQuery {
|
|
|
61
59
|
sourceDomainId: hit.domainId,
|
|
62
60
|
sourceDomainName: hit.domain?.name,
|
|
63
61
|
value: secrets.has(key) ? undefined : hit.value ?? undefined,
|
|
64
|
-
valueHint: secrets.has(key) ? (0,
|
|
62
|
+
valueHint: secrets.has(key) ? (0, shell_1.secretHint)(hit.value) : undefined,
|
|
65
63
|
hasValue: hit.value !== null && hit.value !== undefined && hit.value !== ''
|
|
66
64
|
};
|
|
67
65
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-attribute-query.js","sourceRoot":"","sources":["../../../server/service/domain-attribute/domain-attribute-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAwD;AACxD,qCAA4B;AAE5B,
|
|
1
|
+
{"version":3,"file":"domain-attribute-query.js","sourceRoot":"","sources":["../../../server/service/domain-attribute/domain-attribute-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Query, Arg, Ctx } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { Domain, EnvVar, getRepository, getDomainIdsWithAncestors, secretHint } from '@things-factory/shell'\n\nimport { EnvVarResolution } from './domain-attribute-type'\nimport { secretEnvVarKeys } from './secret-keys'\n\n/**\n * EnvVar 키들의 해소 상태를 일괄 조회.\n *\n * Connection 파라미터 화면, Step 파라미터 편집기에서 useDomainAttribute params 의\n * 4-상태(이 도메인 / 상속 / 미설정) 를 한 번에 가져오기 위한 query.\n *\n * 동작:\n * 1. 현재 도메인부터 루트까지 ancestor id 를 closest-first 로 모은다.\n * 2. 입력 keys 에 매칭되는 EnvVar 중 가장 가까운 도메인 값을 선택한다.\n * 3. 키별로 결과를 만들되, 어디에도 없으면 status='absent'.\n *\n * 멀티-키 단일 쿼리 — N 키를 N 쿼리로 보내지 않도록.\n *\n * 비밀값은 돌려주지 않는다 (ADR-0112). 키가 가리키는 spec 이 `type: 'secret'` 이거나 spec 을\n * 찾을 수 없으면 `value` 를 비우고 `hasValue` 만 준다 — 비밀번호를 옮겨 둔 EnvVar 가 이 쿼리로\n * 다시 나가지 않도록. 비밀이 아닌 칸은 편집기가 기존 값을 채워 열 수 있게 그대로 준다.\n */\n@Resolver()\nexport class DomainAttributeQuery {\n @Query(returns => [EnvVarResolution], {\n description: 'Resolves a batch of EnvVar keys with ancestor closest-wins inheritance.'\n })\n async envVarResolutions(\n @Arg('keys', () => [String]) keys: string[],\n @Ctx() context: ResolverContext\n ): Promise<EnvVarResolution[]> {\n const { domain } = context.state\n if (!domain || !Array.isArray(keys) || keys.length === 0) {\n return (keys || []).map(key => ({ key, status: 'absent', hasValue: false }))\n }\n\n const ids = await getDomainIdsWithAncestors(domain)\n const idIndex = new Map<string, number>(ids.map((id, idx) => [id, idx]))\n\n const rows = await getRepository(EnvVar).find({\n where: { domain: { id: In(ids) }, name: In(keys), active: true },\n relations: ['domain']\n })\n\n // key → 가장 가까운 도메인의 EnvVar row 선택\n const closestByKey = new Map<string, EnvVar>()\n for (const row of rows) {\n const cur = closestByKey.get(row.name)\n const curRank = cur ? idIndex.get(cur.domainId) ?? Number.MAX_SAFE_INTEGER : Number.MAX_SAFE_INTEGER\n const newRank = idIndex.get(row.domainId) ?? Number.MAX_SAFE_INTEGER\n if (!cur || newRank < curRank) {\n closestByKey.set(row.name, row)\n }\n }\n\n const secrets = await secretEnvVarKeys(keys, ids)\n\n return keys.map(key => {\n const hit = closestByKey.get(key)\n if (!hit) return { key, status: 'absent', hasValue: false }\n\n const isLocal = hit.domainId === domain.id\n return {\n key,\n status: isLocal ? 'local' : 'inherited',\n envVarId: hit.id,\n sourceDomainId: hit.domainId,\n sourceDomainName: hit.domain?.name,\n value: secrets.has(key) ? undefined : hit.value ?? undefined,\n valueHint: secrets.has(key) ? secretHint(hit.value) : undefined,\n hasValue: hit.value !== null && hit.value !== undefined && hit.value !== ''\n }\n })\n }\n}\n"]}
|
|
@@ -12,14 +12,13 @@ const scenario_1 = require("./scenario");
|
|
|
12
12
|
const scenario_type_1 = require("./scenario-type");
|
|
13
13
|
const connection_1 = require("../connection/connection");
|
|
14
14
|
const resolve_steps_1 = require("./resolve-steps");
|
|
15
|
-
const domain_inheritance_1 = require("../../utils/domain-inheritance");
|
|
16
15
|
/**
|
|
17
16
|
* @description Provides GraphQL resolvers for the Scenario entity.
|
|
18
17
|
*/
|
|
19
18
|
let ScenarioQuery = class ScenarioQuery {
|
|
20
19
|
async scenario(id, context) {
|
|
21
20
|
const { domain } = context.state;
|
|
22
|
-
const domainIds = await (0,
|
|
21
|
+
const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
23
22
|
const scenario = await (0, shell_1.getRepository)(scenario_1.Scenario).findOne({ where: { id } });
|
|
24
23
|
if (scenario && domainIds.includes(scenario.domainId)) {
|
|
25
24
|
return scenario;
|
|
@@ -27,7 +26,7 @@ let ScenarioQuery = class ScenarioQuery {
|
|
|
27
26
|
}
|
|
28
27
|
async scenarios(params, context) {
|
|
29
28
|
const { domain } = context.state;
|
|
30
|
-
const domainIds = await (0,
|
|
29
|
+
const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
31
30
|
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
32
31
|
repository: (0, shell_1.getRepository)(scenario_1.Scenario),
|
|
33
32
|
params,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-query.js","sourceRoot":"","sources":["../../../server/service/scenario/scenario-query.ts"],"names":[],"mappings":";;;;AAAA,+CAA8F;AAE9F,yDAAsD;AACtD,
|
|
1
|
+
{"version":3,"file":"scenario-query.js","sourceRoot":"","sources":["../../../server/service/scenario/scenario-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User, Role } from '@things-factory/auth-base'\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n getDomainIdsWithAncestors\n} from '@things-factory/shell'\n\nimport { ScenarioEngine } from '../../engine'\nimport { ScenarioInstance, ScenarioInstanceStatus } from '../scenario-instance/scenario-instance-type'\nimport { Step } from '../step/step-type'\nimport { Scenario } from './scenario'\nimport { ScenarioList } from './scenario-type'\nimport { Connection } from '../connection/connection'\nimport { resolveScenarioSteps } from './resolve-steps'\n\n/**\n * @description Provides GraphQL resolvers for the Scenario entity.\n */\n@Resolver(Scenario)\nexport class ScenarioQuery {\n @Directive('@privilege(category: \"scenario\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Scenario, { description: 'Fetches a single scenario by its ID.' })\n async scenario(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Scenario> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const scenario = await getRepository(Scenario).findOne({ where: { id } })\n if (scenario && domainIds.includes(scenario.domainId)) {\n return scenario\n }\n }\n\n @Directive('@privilege(category: \"scenario\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ScenarioList, { description: 'Fetches a paginated list of scenarios.' })\n async scenarios(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ScenarioList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Scenario),\n params,\n // 도메인 필터링은 ancestor 기반으로 직접 적용\n domain: undefined,\n searchables: ['name', 'description', 'type']\n })\n\n queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {\n ancestorDomainIds: domainIds\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() scenario: Scenario) {\n return await getRepository(Domain).findOneBy({ id: scenario.domainId })\n }\n\n @FieldResolver(type => User)\n async updater(@Root() scenario: Scenario): Promise<User> {\n return await getRepository(User).findOneBy({ id: scenario.updaterId })\n }\n\n @FieldResolver(type => User)\n async creator(@Root() scenario: Scenario): Promise<User> {\n return await getRepository(User).findOneBy({ id: scenario.creatorId })\n }\n\n @FieldResolver(type => [Step])\n async steps(@Root() scenario: Scenario, @Ctx() _context: ResolverContext): Promise<Step[]> {\n // [버전관리 / Option A] draft(작업본) 스텝을 반환.\n // - scenario.steps(JSON) 있으면 사용, 없으면 레거시 Step 테이블에서 읽음(하위호환).\n // 에디터는 draft 를 편집하므로 여기서 draft 를 노출한다(운영 실행은 released 스냅샷 사용).\n return await resolveScenarioSteps(scenario)\n }\n\n @FieldResolver(type => [Connection])\n async connectionNames(@Root() scenario: Scenario, @Ctx() _context: ResolverContext) {\n const steps = await resolveScenarioSteps(scenario)\n return steps.map(step => step.connection).filter(Boolean)\n }\n\n @FieldResolver(type => [Connection])\n async publishTags(@Root() scenario: Scenario, @Ctx() _context: ResolverContext) {\n const steps = await resolveScenarioSteps(scenario)\n return steps.filter(step => step.task == 'publish').map(step => step.params?.tag).filter(Boolean)\n }\n\n @FieldResolver(type => String, { nullable: true })\n async state(@Root() scenario: Scenario, @Ctx() context: ResolverContext): Promise<string> {\n const { domain } = context.state\n\n var instance = ScenarioEngine.getScenarioInstance(domain, scenario.name)\n return instance && ScenarioInstanceStatus[instance.context?.state]\n }\n\n @FieldResolver(type => [ScenarioInstance], { nullable: true })\n async instances(@Root() scenario: Scenario, @Ctx() context: ResolverContext): Promise<ScenarioInstance[]> {\n const { domain } = context.state\n\n return ScenarioEngine.getScenarioInstances(domain, scenario.name)\n }\n\n @FieldResolver(type => Role)\n async role(@Root() scenario: Scenario) {\n return scenario.roleId && (await getRepository(Role).findOneBy({ id: scenario.roleId }))\n }\n}\n"]}
|
|
@@ -5,7 +5,6 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const typeorm_1 = require("typeorm");
|
|
7
7
|
const shell_1 = require("@things-factory/shell");
|
|
8
|
-
const domain_inheritance_1 = require("../../utils/domain-inheritance");
|
|
9
8
|
const scenario_1 = require("./scenario");
|
|
10
9
|
const scenario_history_1 = require("./scenario-history");
|
|
11
10
|
const resolve_steps_1 = require("./resolve-steps");
|
|
@@ -17,7 +16,7 @@ const scenario_version_diff_1 = require("./scenario-version-diff");
|
|
|
17
16
|
let ScenarioVersionQuery = class ScenarioVersionQuery {
|
|
18
17
|
async scenarioVersions(id, context) {
|
|
19
18
|
const { domain } = context.state;
|
|
20
|
-
const domainIds = await (0,
|
|
19
|
+
const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
21
20
|
return await (0, shell_1.getRepository)(scenario_history_1.ScenarioHistory).find({
|
|
22
21
|
where: { originalId: id, domain: { id: (0, typeorm_1.In)(domainIds) } },
|
|
23
22
|
relations: ['updater', 'creator'],
|
|
@@ -27,7 +26,7 @@ let ScenarioVersionQuery = class ScenarioVersionQuery {
|
|
|
27
26
|
}
|
|
28
27
|
async scenarioPublished(id, context) {
|
|
29
28
|
const { domain } = context.state;
|
|
30
|
-
const domainIds = await (0,
|
|
29
|
+
const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
31
30
|
return await (0, shell_1.getRepository)(scenario_history_1.ScenarioHistory).findOne({
|
|
32
31
|
where: { originalId: id, domain: { id: (0, typeorm_1.In)(domainIds) } },
|
|
33
32
|
relations: ['updater', 'creator'],
|
|
@@ -36,7 +35,7 @@ let ScenarioVersionQuery = class ScenarioVersionQuery {
|
|
|
36
35
|
}
|
|
37
36
|
async scenarioVersion(id, version, context) {
|
|
38
37
|
const { domain } = context.state;
|
|
39
|
-
const domainIds = await (0,
|
|
38
|
+
const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
40
39
|
return await (0, shell_1.getRepository)(scenario_history_1.ScenarioHistory).findOne({
|
|
41
40
|
where: { originalId: id, version, domain: { id: (0, typeorm_1.In)(domainIds) } },
|
|
42
41
|
relations: ['updater', 'creator']
|
|
@@ -44,7 +43,7 @@ let ScenarioVersionQuery = class ScenarioVersionQuery {
|
|
|
44
43
|
}
|
|
45
44
|
async scenarioVersionDiff(id, version, context, toVersion) {
|
|
46
45
|
const { domain } = context.state;
|
|
47
|
-
const domainIds = await (0,
|
|
46
|
+
const domainIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
48
47
|
const historyRepo = (0, shell_1.getRepository)(scenario_history_1.ScenarioHistory);
|
|
49
48
|
const base = await historyRepo.findOne({
|
|
50
49
|
where: { originalId: id, version, domain: { id: (0, typeorm_1.In)(domainIds) } }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-version-query.js","sourceRoot":"","sources":["../../../server/service/scenario/scenario-version-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAwE;AACxE,qCAA4B;AAE5B,
|
|
1
|
+
{"version":3,"file":"scenario-version-query.js","sourceRoot":"","sources":["../../../server/service/scenario/scenario-version-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Int, Query, Resolver } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository, getDomainIdsWithAncestors } from '@things-factory/shell'\n\nimport { Scenario } from './scenario'\nimport { ScenarioHistory } from './scenario-history'\nimport { resolveScenarioSteps } from './resolve-steps'\nimport { ScenarioVersionDiff } from './scenario-version-type'\nimport { diffScenarioMeta, diffScenarioSteps } from './scenario-version-diff'\n\n/**\n * 시나리오 버전(릴리즈 스냅샷) 조회 및 diff 리졸버.\n */\n@Resolver()\nexport class ScenarioVersionQuery {\n @Directive('@privilege(category: \"scenario\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [ScenarioHistory], {\n description: 'Fetches recent released versions (snapshots) of a scenario, newest first.'\n })\n async scenarioVersions(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ScenarioHistory[]> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(ScenarioHistory).find({\n where: { originalId: id, domain: { id: In(domainIds) } },\n relations: ['updater', 'creator'],\n order: { version: 'DESC' },\n take: 20\n })\n }\n\n @Directive('@privilege(category: \"scenario\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ScenarioHistory, {\n nullable: true,\n description: 'Fetches the most recently released version (snapshot) of a scenario.'\n })\n async scenarioPublished(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ScenarioHistory | null> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(ScenarioHistory).findOne({\n where: { originalId: id, domain: { id: In(domainIds) } },\n relations: ['updater', 'creator'],\n order: { version: 'DESC' }\n })\n }\n\n @Directive('@privilege(category: \"scenario\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ScenarioHistory, {\n nullable: true,\n description: 'Fetches a specific released version (snapshot) of a scenario by version number.'\n })\n async scenarioVersion(\n @Arg('id') id: string,\n @Arg('version', type => Int) version: number,\n @Ctx() context: ResolverContext\n ): Promise<ScenarioHistory | null> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n return await getRepository(ScenarioHistory).findOne({\n where: { originalId: id, version, domain: { id: In(domainIds) } },\n relations: ['updater', 'creator']\n })\n }\n\n @Directive('@privilege(category: \"scenario\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => ScenarioVersionDiff, {\n description:\n 'Computes the difference between a released version and either another released version or the current draft. ' +\n 'Omit toVersion to diff the base version against the current draft.'\n })\n async scenarioVersionDiff(\n @Arg('id') id: string,\n @Arg('version', type => Int) version: number,\n @Ctx() context: ResolverContext,\n @Arg('toVersion', type => Int, { nullable: true }) toVersion?: number\n ): Promise<ScenarioVersionDiff> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n const historyRepo = getRepository(ScenarioHistory)\n\n const base = await historyRepo.findOne({\n where: { originalId: id, version, domain: { id: In(domainIds) } }\n })\n if (!base) {\n throw new Error(`Scenario version (${id}:${version}) is not found`)\n }\n\n let target: any\n if (toVersion !== undefined && toVersion !== null) {\n target = await historyRepo.findOne({\n where: { originalId: id, version: toVersion, domain: { id: In(domainIds) } }\n })\n if (!target) {\n throw new Error(`Scenario version (${id}:${toVersion}) is not found`)\n }\n } else {\n // 현재 draft 와 비교\n const scenario = await getRepository(Scenario).findOne({ where: { id } })\n if (!scenario || !domainIds.includes(scenario.domainId)) {\n throw new Error(`Scenario (${id}) is not found`)\n }\n const draftSteps = await resolveScenarioSteps(scenario)\n target = { ...scenario, steps: draftSteps }\n }\n\n return {\n fromVersion: version,\n toVersion: toVersion ?? null,\n fieldDiffs: diffScenarioMeta(base, target),\n stepDiffs: diffScenarioSteps(base.steps as any[], target.steps as any[])\n }\n }\n}\n"]}
|
|
@@ -19,7 +19,6 @@ const publish_data_1 = require("../../controllers/publish-data");
|
|
|
19
19
|
const connection_manager_1 = require("../../engine/connection-manager");
|
|
20
20
|
const engine_1 = require("../../engine");
|
|
21
21
|
const edge_client_1 = require("../../engine/edge-client");
|
|
22
|
-
const domain_inheritance_1 = require("../../utils/domain-inheritance");
|
|
23
22
|
const secret_hint_1 = require("../secret-hint");
|
|
24
23
|
const debug = require('debug')('things-factory:integration-base:scenario-instance');
|
|
25
24
|
const { combine, errors, splat, printf } = winston_1.format;
|
|
@@ -570,7 +569,7 @@ async function resolveDomainAttributeParams(scenarioName, step, handler, domain,
|
|
|
570
569
|
if (!s?.useDomainAttribute || !s.name)
|
|
571
570
|
continue;
|
|
572
571
|
const envVarKey = `Step::${scenarioName}::${step.name}::${s.name}`;
|
|
573
|
-
const value = await (0,
|
|
572
|
+
const value = await (0, shell_1.lookupDomainEnvVar)(domain, envVarKey);
|
|
574
573
|
// 우선순위 (useDomainAttribute=true 필드):
|
|
575
574
|
// 1. EnvVar (ancestor closest-wins) — 자식 override 가능 — 본 소스
|
|
576
575
|
// 2. step.params 명시값 — default 역할
|
|
@@ -609,7 +608,7 @@ async function resolveDomainAttributeParams(scenarioName, step, handler, domain,
|
|
|
609
608
|
// EnvVar 도 없고 params 도 없음 — 광범위 진단 + 미해소
|
|
610
609
|
const allMatches = await (0, shell_1.getRepository)(shell_1.EnvVar).find({ where: { name: envVarKey }, relations: ['domain'] });
|
|
611
610
|
const others = allMatches.map((e) => `${e.domain?.subdomain || e.domain?.name}${e.active ? '' : '(inactive)'}`);
|
|
612
|
-
const ancestorIds = await (0,
|
|
611
|
+
const ancestorIds = await (0, shell_1.getDomainIdsWithAncestors)(domain);
|
|
613
612
|
const msg = `[domain-attr] step '${step.name}'.${s.name} 미해소 — EnvVar '${envVarKey}' 를 도메인 '${dn}' + ${ancestorIds.length}-개 ancestor 에서 찾지 못함. ` +
|
|
614
613
|
(others.length > 0
|
|
615
614
|
? `다른 도메인에는 존재함: [${others.join(', ')}] — 도메인 컨텍스트 확인 필요`
|