inanis 0.0.7-beta.15 → 0.0.7-beta.18

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.
@@ -256,10 +256,12 @@ export class DynamoDbTable {
256
256
  '#updatedAt': 'updatedAt'
257
257
  };
258
258
  for (let key in data) {
259
- let [mode, value] = data[key];
260
- ExpressionAttributeValues[`:${key}`] = value;
261
- ExpressionAttributeNames[`#${key}`] = key;
262
- UpdateExpressions.push(`#${key} = #${key} ${mode} :${key}`);
259
+ if (data[key] != null) {
260
+ let [mode, value] = data[key];
261
+ ExpressionAttributeValues[`:${key}`] = value;
262
+ ExpressionAttributeNames[`#${key}`] = key;
263
+ UpdateExpressions.push(`#${key} = #${key} ${mode} :${key}`);
264
+ }
263
265
  }
264
266
  await service.update({
265
267
  TableName: this.tableName,
@@ -279,7 +281,8 @@ export class DynamoDbTable {
279
281
  '#updatedAt': 'updatedAt'
280
282
  };
281
283
  for (let key in data) {
282
- ExpressionAttributeValues[`:${key}`] = data[key];
284
+ const value = data[key] == null ? null : data[key];
285
+ ExpressionAttributeValues[`:${key}`] = value;
283
286
  ExpressionAttributeNames[`#${key}`] = key;
284
287
  UpdateExpressions.push(`#${key} = :${key}`);
285
288
  }
@@ -304,7 +307,8 @@ export class DynamoDbTable {
304
307
  '#updatedAt': 'updatedAt'
305
308
  };
306
309
  for (let key in data) {
307
- ExpressionAttributeValues[`:${key}`] = data[key];
310
+ const value = data[key] == null ? null : data[key];
311
+ ExpressionAttributeValues[`:${key}`] = value;
308
312
  ExpressionAttributeNames[`#${key}`] = key;
309
313
  UpdateExpressions.push(`#${key} = :${key}`);
310
314
  }
@@ -58,6 +58,8 @@ export declare class DataModel<T extends DataModelConfig<any, any, any>, D exten
58
58
  data: D;
59
59
  constructor(config: T, data: T['_initData']);
60
60
  getPublic(): Pick<D, PublicKey>;
61
+ getCreateAt(): any;
62
+ getUpdateAt(): any;
61
63
  copy(): this;
62
64
  from(source: Partial<D> | DataModel<T, D, PublicKey>): void;
63
65
  save(reader?: (_data: D) => Partial<D>): Promise<void>;
@@ -96,6 +96,12 @@ export class DataModel {
96
96
  }
97
97
  return output;
98
98
  }
99
+ getCreateAt() {
100
+ return this.data.createdAt;
101
+ }
102
+ getUpdateAt() {
103
+ return this.data.updatedAt;
104
+ }
99
105
  copy() {
100
106
  const newData = structuredClone(this.data);
101
107
  const model = new DataModel(this._config, newData);
@@ -29,10 +29,10 @@ export class StreamRouterContext {
29
29
  name: `${this.method.action}@${this.method.router.path}`,
30
30
  interceptorMessage: (data) => data
31
31
  });
32
+ this.failMessages = this.method.failMessages;
32
33
  this.interaction.on('action', step => {
33
34
  this.interactionStepMessage = step.message;
34
35
  });
35
- // 綁定協助解構
36
36
  const methods = Object.getOwnPropertyNames(StreamRouterContext.prototype);
37
37
  for (let key of methods) {
38
38
  if (key !== 'on' && key !== 'constructor' && typeof this[key] === 'function') {
@@ -5,15 +5,6 @@ import { rootException } from '../exception.js';
5
5
  import { exportOpenApi } from './export-open-api.js';
6
6
  import { Router } from './router.js';
7
7
  import { toRouterName } from '../utils/string.js';
8
- import { streamifyResponse, isInAWS } from 'lambda-stream';
9
- if (isInAWS() === false) {
10
- global['awslambda'] = {
11
- streamifyResponse,
12
- HttpResponseStream: {
13
- from: () => null
14
- }
15
- };
16
- }
17
8
  const exception = rootException.checkout('APIManager');
18
9
  const getLambdaGroup = (manager, method, path) => {
19
10
  let sourcePath = `${method}@${path}`;
@@ -96,7 +87,8 @@ export class StreamAPIManager extends Event {
96
87
  return null;
97
88
  }
98
89
  getMethod(path, method) {
99
- let router = this.getRouter(path);
90
+ let targetPath = path.endsWith('-no-stream') ? path.slice(0, -10) : path;
91
+ let router = this.getRouter(targetPath);
100
92
  if (router == null) {
101
93
  return null;
102
94
  }
@@ -128,6 +120,7 @@ export class StreamAPIManager extends Event {
128
120
  const outputs = {};
129
121
  this.eachMethods((router, method) => {
130
122
  const appendHandleName = 'Stream';
123
+ const isOffline = !!this.params.serverless?.isOffline;
131
124
  const group = getLambdaGroup(this, method, router.path);
132
125
  const handlerName = group.handlerName + appendHandleName;
133
126
  if (outputs[handlerName] == null) {
@@ -142,7 +135,6 @@ export class StreamAPIManager extends Event {
142
135
  };
143
136
  responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
144
137
  let callPath = event.requestContext.resourcePath;
145
- let isOffline = !!this.params.serverless?.isOffline;
146
138
  if (isOffline) {
147
139
  callPath = '/' + callPath.split('/').slice(2).join('/');
148
140
  }
@@ -152,6 +144,50 @@ export class StreamAPIManager extends Event {
152
144
  }
153
145
  await method.outputs.lambdaHandler(event, responseStream);
154
146
  });
147
+ outputs[handlerName + 'NoStream'] = (event) => {
148
+ return new Promise((resolve) => {
149
+ let chunk = '';
150
+ const headers = {
151
+ 'Content-Type': 'text/plain; charset=UTF-8',
152
+ 'Access-Control-Allow-Origin': '*',
153
+ 'Access-Control-Allow-Credentials': 'true'
154
+ };
155
+ const streamEvent = new Event();
156
+ const responseStream = {
157
+ on: streamEvent.on.bind(streamEvent),
158
+ end: () => {
159
+ streamEvent.emit('close', {});
160
+ resolve({
161
+ headers,
162
+ statusCode: 200,
163
+ body: chunk
164
+ });
165
+ },
166
+ write: (data) => {
167
+ chunk += data;
168
+ }
169
+ };
170
+ let callPath = event.requestContext.resourcePath;
171
+ if (isOffline) {
172
+ callPath = '/' + callPath.split('/').slice(2).join('/');
173
+ }
174
+ let method = this.getMethod(callPath, event.httpMethod.toLocaleLowerCase());
175
+ if (method == null) {
176
+ throw exception.create('No Stream Method Found');
177
+ }
178
+ method
179
+ .outputs
180
+ .lambdaHandler(event, responseStream)
181
+ .catch(err => {
182
+ console.error(err);
183
+ resolve({
184
+ headers,
185
+ statusCode: 400,
186
+ body: 'unknown error'
187
+ });
188
+ });
189
+ });
190
+ };
155
191
  }
156
192
  });
157
193
  return outputs;
@@ -169,17 +205,30 @@ export class StreamAPIManager extends Event {
169
205
  memorySize: group.memorySize,
170
206
  events: []
171
207
  };
208
+ outputs[group.name + 'NoStream'] = {
209
+ handler: group.handler + 'NoStream',
210
+ memorySize: group.memorySize,
211
+ events: []
212
+ };
172
213
  if (params.handler) {
173
214
  let newGroup = params.handler(outputs[group.name]);
174
215
  if (newGroup) {
175
216
  outputs[group.name] = newGroup;
176
217
  }
218
+ let newNoStreamGroup = params.handler(outputs[group.name + 'NoStream']);
219
+ if (newNoStreamGroup) {
220
+ outputs[group.name + 'NoStream'] = newNoStreamGroup;
221
+ }
177
222
  }
178
223
  }
179
224
  const m = router.methods[method];
180
225
  const output = outputs[group.name];
226
+ const noStreamOutput = outputs[group.name + 'NoStream'];
181
227
  output.events.push({
182
- http: m.outputs.getServerlessHttp()
228
+ http: m.outputs.getServerlessHttp(true)
229
+ });
230
+ noStreamOutput.events.push({
231
+ http: m.outputs.getServerlessHttp(false)
183
232
  });
184
233
  });
185
234
  return toOutputData(outputs);
@@ -52,7 +52,7 @@ export declare class Method<Path extends string = any, Fails extends FailData =
52
52
  run(context: StreamRouterContext): Promise<void>;
53
53
  get outputs(): {
54
54
  lambdaHandler: (event: APIGatewayEvent, responseStream: ResponseStream) => Promise<void>;
55
- getServerlessHttp: () => Record<string, any>;
55
+ getServerlessHttp: (isStream: boolean) => Record<string, any>;
56
56
  openApiPathItem: () => {
57
57
  tags?: string[];
58
58
  summary?: string;
@@ -51,6 +51,7 @@ export class Method {
51
51
  await context.hook.notify('fail', {
52
52
  error
53
53
  });
54
+ throw error;
54
55
  }
55
56
  }
56
57
  // =================
@@ -62,14 +63,9 @@ export class Method {
62
63
  lambdaHandler: async (event, responseStream) => {
63
64
  await this.inanis._install();
64
65
  const context = await StreamRouterContext.fromAwsLambda(this, event, responseStream);
65
- try {
66
- await this.run(context);
67
- }
68
- catch (error) {
69
- console.log('response parse error:', error);
70
- }
66
+ await this.run(context);
71
67
  },
72
- getServerlessHttp: () => {
68
+ getServerlessHttp: (isStream) => {
73
69
  const http = {
74
70
  cors: {
75
71
  origin: '*',
@@ -80,12 +76,14 @@ export class Method {
80
76
  ...this.allowHeaders
81
77
  ]
82
78
  },
83
- path: this.router.path,
79
+ path: isStream === false ? this.router.path + '-no-stream' : this.router.path,
84
80
  method: this.action,
85
81
  authorizer: undefined,
86
- response: {
87
- transferMode: 'STREAM'
88
- }
82
+ response: isStream === false
83
+ ? undefined
84
+ : {
85
+ transferMode: 'STREAM'
86
+ }
89
87
  };
90
88
  if (this.router.nowAuthorizerExpression) {
91
89
  http.authorizer = this.router.nowAuthorizerExpression.name;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "inanis",
3
3
  "type": "module",
4
- "version": "0.0.7-beta.15",
4
+ "version": "0.0.7-beta.18",
5
5
  "description": "Micro Service Best Tools.",
6
6
  "main": "./dist/index.js",
7
7
  "scripts": {
8
8
  "test": "nyc mocha ./lib/**/*.test.ts ./lib/*.test.ts",
9
9
  "build": "eslint 'src/**/*.{ts,tsx}' --fix && tsc",
10
- "deploy": "ts-node ./deploy.ts"
10
+ "deploy": "esno ./deploy.ts"
11
11
  },
12
12
  "bin": {
13
13
  "ms-be-lib": "cli/index.js"
@@ -36,13 +36,13 @@
36
36
  "cross-env": "^10.0.0",
37
37
  "debug": "^4.4.1",
38
38
  "eslint": "^9.32.0",
39
+ "esno": "^4.8.0",
39
40
  "mocha": "^11.7.1",
40
41
  "nyc": "^17.1.0",
41
42
  "openapi-types": "^12.1.3",
42
43
  "semver": "^7.7.2",
43
44
  "supports-color": "^10.0.0",
44
45
  "ts-loader": "^9.5.2",
45
- "ts-node": "^10.9.2",
46
46
  "typescript": "^5.8.3",
47
47
  "typescript-eslint": "^8.38.0"
48
48
  },
@@ -65,7 +65,6 @@
65
65
  "json-schema-to-typescript": "^15.0.4",
66
66
  "json-to-pretty-yaml": "^1.2.2",
67
67
  "jsonwebtoken": "^9.0.2",
68
- "lambda-stream": "^0.6.0",
69
68
  "mime": "^4.1.0",
70
69
  "mongodb": "^7.0.0",
71
70
  "node-rsa": "^1.1.1",
@@ -78,4 +77,4 @@
78
77
  "zod": "^4.2.1"
79
78
  },
80
79
  "packageManager": "yarn@4.1.1"
81
- }
80
+ }