oak-domain 5.0.0 → 5.0.1

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.
@@ -574,7 +574,7 @@ function outputIntializeDev(cwd, dependencies, briefNames, sourceFile, printer,
574
574
  * @param printer
575
575
  * @param filename
576
576
  */
577
- function outputFeatureIndex(dependencies, briefNames, sourceFile, printer, filename) {
577
+ function outputFeatureIndex(dependencies, briefNames, sourceFile, printer, filename, isModule) {
578
578
  const { statements } = sourceFile;
579
579
  let statements2 = [];
580
580
  if (dependencies.length > 0) {
@@ -605,6 +605,20 @@ function outputFeatureIndex(dependencies, briefNames, sourceFile, printer, filen
605
605
  ...importStatements,
606
606
  ...statements.slice(5)
607
607
  ];
608
+ if (isModule) {
609
+ statements2.push(factory.createFunctionDeclaration([
610
+ factory.createToken(ts.SyntaxKind.ExportKeyword),
611
+ factory.createToken(ts.SyntaxKind.AsyncKeyword)
612
+ ], undefined, factory.createIdentifier("initialize"), [
613
+ factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("ED"), factory.createTypeReferenceNode(factory.createIdentifier("EntityDict"), undefined), undefined)
614
+ ], [
615
+ factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("features"), undefined, factory.createIntersectionTypeNode([
616
+ factory.createTypeReferenceNode(factory.createIdentifier("FeatureDict"), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]),
617
+ factory.createTypeReferenceNode(factory.createIdentifier("BasicFeatures"), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]),
618
+ ...briefNames.map((ele) => factory.createTypeReferenceNode(factory.createIdentifier(`${(0, string_1.firstLetterUpperCase)(ele)}FeatureDict`), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]))
619
+ ]), undefined)
620
+ ], undefined, factory.createBlock([], true)));
621
+ }
608
622
  }
609
623
  else {
610
624
  statements2 = [...statements];
@@ -786,12 +800,47 @@ function tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer) {
786
800
  injectDataIndexFile(join(cwd, 'src', 'data', 'index.ts'), injectDataIndexFileBriefNames, printer);
787
801
  }
788
802
  }
803
+ /**
804
+ * 对于module类型的项目,在feature/index.ts中注入initialize函数
805
+ * @param cwd
806
+ * @param dependencies
807
+ * @param briefNames
808
+ */
809
+ function injectInitializeToFeatureIndex(cwd, dependencies, briefNames, printer) {
810
+ const featureIndexFile = join(cwd, 'src', 'features', 'index.ts');
811
+ const sourceFile = ts.createSourceFile('index.ts', (0, fs_1.readFileSync)(featureIndexFile, 'utf-8'), ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
812
+ const { statements } = sourceFile;
813
+ const initializeStmt = statements.find((stmt) => ts.isFunctionDeclaration(stmt) && ts.isIdentifier(stmt.name) && stmt.name.text === 'initialize');
814
+ if (!initializeStmt) {
815
+ const statements2 = [
816
+ ...(dependencies.map((dep, idx) => factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("FeatureDict"), factory.createIdentifier(`${(0, string_1.firstLetterUpperCase)(briefNames[idx])}FeatureDict`))])), factory.createStringLiteral(dep), undefined))),
817
+ ...statements,
818
+ factory.createFunctionDeclaration([
819
+ factory.createToken(ts.SyntaxKind.ExportKeyword),
820
+ factory.createToken(ts.SyntaxKind.AsyncKeyword)
821
+ ], undefined, factory.createIdentifier("initialize"), [
822
+ factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("ED"), factory.createTypeReferenceNode(factory.createIdentifier("EntityDict"), undefined), undefined)
823
+ ], [
824
+ factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("features"), undefined, factory.createIntersectionTypeNode([
825
+ factory.createTypeReferenceNode(factory.createIdentifier("FeatureDict"), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]),
826
+ factory.createTypeReferenceNode(factory.createIdentifier("BasicFeatures"), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]),
827
+ ...briefNames.map((ele) => factory.createTypeReferenceNode(factory.createIdentifier(`${(0, string_1.firstLetterUpperCase)(ele)}FeatureDict`), [factory.createTypeReferenceNode(factory.createIdentifier("ED"), undefined)]))
828
+ ]), undefined)
829
+ ], undefined, factory.createBlock([], true))
830
+ ];
831
+ const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements2), sourceFile);
832
+ (0, fs_1.writeFileSync)(featureIndexFile, result, { flag: 'w' });
833
+ console.log(`注入${featureIndexFile}文件成功,用户可以自己修正initialize函数的参数和逻辑`);
834
+ }
835
+ }
789
836
  /**
790
837
  * 本函数用于构建src/initialize.dev, src/initialize.prod, src/initializeFeatures, src/context/FrontendContext, src/contextBackendContext
791
838
  * 这些和dependency相关的项目文件
792
839
  */
793
840
  function buildDependency(rebuild) {
794
841
  const cwd = process.cwd();
842
+ const webDir = join(cwd, 'web');
843
+ const isModule = !(0, fs_1.existsSync)(webDir); // 如果没有web目录,说明是module,不需要处理模块级别的文件注入
795
844
  const depConfigFile = join(cwd, 'src', 'configuration', 'dependency.ts');
796
845
  if (!(0, fs_1.existsSync)(depConfigFile)) {
797
846
  console.error(`${depConfigFile}不存在,无法构建启动文件`);
@@ -801,8 +850,8 @@ function buildDependency(rebuild) {
801
850
  const dependencies = depGraph.ascOrder;
802
851
  const briefNames = dependencies.map((dep, idx) => `${dep.split('-').map(ele => ele[0]).join('')}${idx}`);
803
852
  const templateFileList = [
804
- join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'initialize.dev.ts'),
805
- join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'initialize.prod.ts'),
853
+ join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'initialize.frontend.ts'),
854
+ join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'initialize.server.ts'),
806
855
  join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'initializeFeatures.ts'),
807
856
  join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'RuntimeCxt.ts'),
808
857
  join(cwd, 'node_modules', env_1.OAK_CLI_MODULE_NAME, 'templateFiles', 'DependentExceptions.ts'),
@@ -811,26 +860,28 @@ function buildDependency(rebuild) {
811
860
  ];
812
861
  const program = ts.createProgram(templateFileList, {});
813
862
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
814
- const initDevFile = join(cwd, 'src', 'initialize.dev.ts');
815
- if ((0, fs_1.existsSync)(initDevFile) && !rebuild) {
816
- console.log(`[${initDevFile}]文件已经存在,无需构建启动文件`);
817
- }
818
- else {
819
- outputIntializeDev(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[0]), printer, initDevFile);
820
- }
821
- const initProdFile = join(cwd, 'src', 'initialize.prod.ts');
822
- if ((0, fs_1.existsSync)(initProdFile) && !rebuild) {
823
- console.log(`[${initProdFile}]文件已经存在,无需构建启动文件`);
824
- }
825
- else {
826
- outputIntializeProd(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[1]), printer, initProdFile);
827
- }
828
- const initFeaturesFile = join(cwd, 'src', 'initializeFeatures.ts');
829
- if ((0, fs_1.existsSync)(initFeaturesFile) && !rebuild) {
830
- console.log(`[${initFeaturesFile}]文件已经存在,无需构建启动文件`);
831
- }
832
- else {
833
- outputIntializeFeatures(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[2]), printer, initFeaturesFile);
863
+ if (!isModule) {
864
+ const initDevFile = join(cwd, 'src', 'initialize.frontend.ts');
865
+ if ((0, fs_1.existsSync)(initDevFile) && !rebuild) {
866
+ console.log(`[${initDevFile}]文件已经存在,无需构建启动文件`);
867
+ }
868
+ else {
869
+ outputIntializeDev(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[0]), printer, initDevFile);
870
+ }
871
+ const initProdFile = join(cwd, 'src', 'initialize.server.ts');
872
+ if ((0, fs_1.existsSync)(initProdFile) && !rebuild) {
873
+ console.log(`[${initProdFile}]文件已经存在,无需构建启动文件`);
874
+ }
875
+ else {
876
+ outputIntializeProd(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[1]), printer, initProdFile);
877
+ }
878
+ const initFeaturesFile = join(cwd, 'src', 'initializeFeatures.ts');
879
+ if ((0, fs_1.existsSync)(initFeaturesFile) && !rebuild) {
880
+ console.log(`[${initFeaturesFile}]文件已经存在,无需构建启动文件`);
881
+ }
882
+ else {
883
+ outputIntializeFeatures(cwd, dependencies, briefNames, program.getSourceFile(templateFileList[2]), printer, initFeaturesFile);
884
+ }
834
885
  }
835
886
  const dependentContextFile = join(cwd, 'src', 'context', 'DependentContext.ts');
836
887
  if ((0, fs_1.existsSync)(dependentContextFile) && !rebuild) {
@@ -865,9 +916,11 @@ function buildDependency(rebuild) {
865
916
  console.log(`[${featureIndexFile}]文件已经存在,无需构建启动文件`);
866
917
  }
867
918
  else {
868
- outputFeatureIndex(dependencies, briefNames, program.getSourceFile(templateFileList[6]), printer, featureIndexFile);
919
+ outputFeatureIndex(dependencies, briefNames, program.getSourceFile(templateFileList[6]), printer, featureIndexFile, isModule);
869
920
  }
870
921
  // 把各个依赖项目的一些初始化的文件拷贝过去
871
- tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer);
922
+ if (!isModule) {
923
+ tryCopyModuleTemplateFiles(cwd, dependencies, briefNames, printer);
924
+ }
872
925
  }
873
926
  exports.default = buildDependency;
@@ -14,8 +14,8 @@ export declare abstract class AsyncContext<ED extends EntityDict> implements Con
14
14
  opResult: OperationResult<ED>;
15
15
  private message?;
16
16
  events: {
17
- commit: Array<() => Promise<void>>;
18
- rollback: Array<() => Promise<void>>;
17
+ commit: Array<(records: OpRecord<ED>[], cxtStr: string) => Promise<void>>;
18
+ rollback: Array<(records: OpRecord<ED>[], cxtStr: string) => Promise<void>>;
19
19
  };
20
20
  /**
21
21
  * 在返回结果前调用,对数据行进行一些预处理,比如将一些敏感的列隐藏
@@ -27,7 +27,7 @@ export declare abstract class AsyncContext<ED extends EntityDict> implements Con
27
27
  getScene(): string | undefined;
28
28
  setScene(scene?: string): void;
29
29
  private resetEvents;
30
- on(event: 'commit' | 'rollback', callback: () => Promise<void>): void;
30
+ on(event: 'commit' | 'rollback', callback: (records: OpRecord<ED>[], cxtStr: string) => Promise<void>): void;
31
31
  saveOpRecord<T extends keyof ED>(entity: T, operation: ED[T]['Operation']): void;
32
32
  /**
33
33
  * 一个context中不应该有并发的事务,这里将事务串行化,使用的时候千万要注意不要自己等自己
@@ -119,9 +119,12 @@ class AsyncContext {
119
119
  if (this.uuid) {
120
120
  await this.rowStore.commit(this.uuid);
121
121
  const { commit: commitEvents } = this.events;
122
- for (const e of commitEvents) {
122
+ /* for (const e of commitEvents) {
123
123
  await e();
124
- }
124
+ } */
125
+ // 提交时不能等在跨事务trigger上
126
+ const cxtStr = await this.toString();
127
+ commitEvents.forEach(evt => evt(this.opRecords, cxtStr));
125
128
  this.uuid = undefined;
126
129
  this.resetEvents();
127
130
  this.opRecords = [];
@@ -133,9 +136,9 @@ class AsyncContext {
133
136
  if (this.uuid) {
134
137
  await this.rowStore.rollback(this.uuid);
135
138
  const { rollback: rollbackEvents } = this.events;
136
- for (const e of rollbackEvents) {
137
- await e();
138
- }
139
+ // 回退时不能等在跨事务trigger上
140
+ const cxtStr = await this.toString();
141
+ rollbackEvents.forEach(evt => evt(this.opRecords, cxtStr));
139
142
  this.uuid = undefined;
140
143
  this.opRecords = [];
141
144
  this.opResult = {};
@@ -221,19 +221,22 @@ class TriggerExecutor {
221
221
  }
222
222
  }
223
223
  postCommitTrigger(entity, operation, trigger, context, option) {
224
- context.on('commit', async () => {
224
+ context.on('commit', async (opRecords, cxtStr) => {
225
225
  let ids = [];
226
- let cxtStr = await context.toString();
227
- const { opRecords } = context;
226
+ let cxtStr2 = cxtStr;
228
227
  const { data } = operation;
229
228
  if (operation.action === 'create') {
230
229
  if (data instanceof Array) {
231
230
  ids = data.map(ele => ele.id);
232
- cxtStr = data[0].$$triggerData$$?.cxtStr || await context.toString();
231
+ if (data[0].$$triggerData$$?.cxtStr) {
232
+ cxtStr2 = data[0].$$triggerData$$?.cxtStr;
233
+ }
233
234
  }
234
235
  else {
235
236
  ids = [data.id];
236
- cxtStr = data.$$triggerData$$?.cxtStr || await context.toString();
237
+ if (data.$$triggerData$$?.cxtStr) {
238
+ cxtStr2 = data.$$triggerData$$?.cxtStr;
239
+ }
237
240
  }
238
241
  }
239
242
  else {
@@ -242,7 +245,9 @@ class TriggerExecutor {
242
245
  * 若trigger是takeEasy,只会在事务提交时做一次,使用当前context应也无大问题
243
246
  * 暂时先这样设计,若当前提交事务中改变了cxt内容,也许会有问题。by Xc 20240319
244
247
  */
245
- cxtStr = data.$$triggerData$$?.cxtStr || await context.toString();
248
+ if (data.$$triggerData$$?.cxtStr) {
249
+ cxtStr2 = data.$$triggerData$$?.cxtStr;
250
+ }
246
251
  const record = opRecords.find(ele => ele.id === operation.id);
247
252
  // 目前框架在operation时,一定会将ids记录在operation当中(见CascadeStore中的doUpdateSingleRowAsync函数
248
253
  (0, assert_1.default)(record && record.a !== 'c');
@@ -250,7 +255,7 @@ class TriggerExecutor {
250
255
  ids = f.id.$in;
251
256
  }
252
257
  // 此时项目的上下文,和执行此trigger时的上下文可能不一致(rootMode),采用当时的上下文cxtStr来执行
253
- this.onVolatileTrigger(entity, trigger, ids, cxtStr, option);
258
+ this.onVolatileTrigger(entity, trigger, ids, cxtStr2, option);
254
259
  });
255
260
  }
256
261
  preOperation(entity, operation, context, option) {
@@ -335,6 +340,8 @@ class TriggerExecutor {
335
340
  const { fn } = trigger;
336
341
  const callback = await fn({ ids }, context, option);
337
342
  if (trigger.strict === 'makeSure') {
343
+ // 这里开root模式,否则还可能有权限问题
344
+ context.openRootMode();
338
345
  await context.operate(entity, {
339
346
  id: await (0, uuid_1.generateNewIdAsync)(),
340
347
  action: 'update',
@@ -1,14 +1,12 @@
1
1
  import { AuthDeduceRelationMap, EntityDict } from './Entity';
2
2
  import { EntityDict as BaseEntityDict } from "../base-app-domain";
3
- import { AsyncContext } from '../store/AsyncRowStore';
4
- import { SyncConfig } from "./Sync";
5
3
  import { AttrUpdateMatrix } from './EntityDesc';
6
4
  import { ActionDefDict } from './Action';
7
5
  import { StyleDict } from './Style';
8
6
  /**
9
7
  * 后台配置
10
8
  */
11
- export type ServerConfiguration<ED extends BaseEntityDict & EntityDict, Cxt extends AsyncContext<ED>> = {
9
+ export type ServerConfiguration = {
12
10
  database: {
13
11
  type: 'mysql';
14
12
  host: string;
@@ -22,7 +20,20 @@ export type ServerConfiguration<ED extends BaseEntityDict & EntityDict, Cxt exte
22
20
  workDir: {
23
21
  path: string;
24
22
  };
25
- sync?: SyncConfig<ED, Cxt>;
23
+ port: number;
24
+ hostname: string;
25
+ nginx?: {
26
+ ssl: boolean;
27
+ apiPath: string;
28
+ port?: number;
29
+ socketPath: string;
30
+ };
31
+ cors?: {
32
+ origin: string;
33
+ headers?: string[];
34
+ methods?: string[];
35
+ };
36
+ internalExceptionMask?: string;
26
37
  };
27
38
  /**
28
39
  * 前后台访问配置
@@ -351,83 +351,83 @@ function makeException(data) {
351
351
  break;
352
352
  }
353
353
  case 'OakUserException': {
354
- const e = new OakUserException(data.message);
354
+ e = new OakUserException(data.message);
355
355
  break;
356
356
  }
357
357
  case 'OakRowInconsistencyException': {
358
- const e = new OakRowInconsistencyException(data.data, data.message);
358
+ e = new OakRowInconsistencyException(data.data, data.message);
359
359
  break;
360
360
  }
361
361
  case 'OakInputIllegalException': {
362
- const e = new OakInputIllegalException(data.entity, data.attributes, data.message);
362
+ e = new OakInputIllegalException(data.entity, data.attributes, data.message);
363
363
  break;
364
364
  }
365
365
  case 'OakAttrCantUpdateException': {
366
- const e = new OakAttrCantUpdateException(data.entity, data.attributes, data.message);
366
+ e = new OakAttrCantUpdateException(data.entity, data.attributes, data.message);
367
367
  break;
368
368
  }
369
369
  case 'OakUserUnpermittedException': {
370
- const e = new OakUserUnpermittedException(data.entity, data.operation, data.message);
370
+ e = new OakUserUnpermittedException(data.entity, data.operation, data.message);
371
371
  break;
372
372
  }
373
373
  case 'OakUserInvisibleException': {
374
- const e = new OakUserInvisibleException(data.entity, data.operation, data.message);
374
+ e = new OakUserInvisibleException(data.entity, data.operation, data.message);
375
375
  break;
376
376
  }
377
377
  case 'OakUnloggedInException': {
378
- const e = new OakUnloggedInException(data.message);
378
+ e = new OakUnloggedInException(data.message);
379
379
  break;
380
380
  }
381
381
  case 'OakCongruentRowExists': {
382
- const e = new OakCongruentRowExists(data.entity, data.data, data.message);
382
+ e = new OakCongruentRowExists(data.entity, data.data, data.message);
383
383
  break;
384
384
  }
385
385
  case 'OakRowLockedException': {
386
- const e = new OakRowLockedException(data.message);
386
+ e = new OakRowLockedException(data.message);
387
387
  break;
388
388
  }
389
389
  case 'OakRowUnexistedException': {
390
- const e = new OakRowUnexistedException(data.rows);
390
+ e = new OakRowUnexistedException(data.rows);
391
391
  break;
392
392
  }
393
393
  case 'OakDeadlock': {
394
- const e = new OakDeadlock(data.message);
394
+ e = new OakDeadlock(data.message);
395
395
  break;
396
396
  }
397
397
  case 'OakDataException': {
398
- const e = new OakDataException(data.message);
398
+ e = new OakDataException(data.message);
399
399
  break;
400
400
  }
401
401
  case 'OakNoRelationDefException': {
402
- const e = new OakNoRelationDefException(data.entity, data.action, data.message);
402
+ e = new OakNoRelationDefException(data.entity, data.action, data.message);
403
403
  break;
404
404
  }
405
405
  case 'OakUniqueViolationException': {
406
- const e = new OakUniqueViolationException(data.rows, data.message);
406
+ e = new OakUniqueViolationException(data.rows, data.message);
407
407
  break;
408
408
  }
409
409
  case 'OakImportDataParseException': {
410
- const e = new OakImportDataParseException(data.message, data.line, data.header);
410
+ e = new OakImportDataParseException(data.message, data.line, data.header);
411
411
  break;
412
412
  }
413
413
  case 'OakPreConditionUnsetException': {
414
- const e = new OakPreConditionUnsetException(data.message, data.entity, data.code);
414
+ e = new OakPreConditionUnsetException(data.message, data.entity, data.code);
415
415
  break;
416
416
  }
417
417
  case 'OakAttrNotNullException': {
418
- const e = new OakAttrNotNullException(data.entity, data.attributes, data.message);
418
+ e = new OakAttrNotNullException(data.entity, data.attributes, data.message);
419
419
  break;
420
420
  }
421
421
  case 'OakExternalException': {
422
- const e = new OakExternalException(data.source, data.code, data.message, data.data);
422
+ e = new OakExternalException(data.source, data.code, data.message, data.data);
423
423
  break;
424
424
  }
425
425
  case 'OakNetworkException': {
426
- const e = new OakNetworkException(data.message);
426
+ e = new OakNetworkException(data.message);
427
427
  break;
428
428
  }
429
429
  case 'OakServerProxyException': {
430
- const e = new OakServerProxyException(data.message);
430
+ e = new OakServerProxyException(data.message);
431
431
  break;
432
432
  }
433
433
  default:
@@ -137,16 +137,9 @@ class SimpleConnector {
137
137
  const responseType = response.headers.get('Content-Type') ||
138
138
  response.headers.get('content-type');
139
139
  if (responseType?.toLocaleLowerCase().match(/application\/json/i)) {
140
- const { url, path, port, namespace } = await response.json();
141
- let url2 = url || this.serverUrl;
142
- if (port) {
143
- url2 += `:${port}`;
144
- }
145
- if (namespace) {
146
- url2 += namespace;
147
- }
140
+ const { url, path } = await response.json();
148
141
  return {
149
- url: url2,
142
+ url,
150
143
  path,
151
144
  };
152
145
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oak-domain",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "author": {
5
5
  "name": "XuChang"
6
6
  },