inanis 0.0.7-beta.14 → 0.0.7-beta.15
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/api/method.js +4 -2
- package/dist/build-tools/swagger-to-types.js +6 -0
- package/dist/document-db/index.js +1 -1
- package/dist/document-db/table-dynamo.js +5 -5
- package/dist/document-db/table-mongo.js +5 -5
- package/dist/document-db/table.d.ts +1 -1
- package/dist/modules/data-model.d.ts +2 -0
- package/dist/modules/data-model.js +9 -0
- package/dist/stream/context.d.ts +2 -2
- package/dist/stream/context.js +7 -2
- package/dist/stream/index.d.ts +4 -5
- package/dist/stream/index.js +18 -0
- package/dist/stream/method.d.ts +1 -1
- package/dist/stream/method.js +3 -2
- package/dist/stream/router.d.ts +4 -6
- package/dist/stream/router.js +0 -2
- package/dist/utils/json-schema.d.ts +3 -1
- package/dist/utils/json-schema.js +3 -1
- package/dist/utils/validate.js +1 -1
- package/package.json +3 -2
package/dist/api/method.js
CHANGED
|
@@ -144,6 +144,7 @@ export class Method {
|
|
|
144
144
|
if (event.headers['x-warm-up'] === '1') {
|
|
145
145
|
console.log('warm-up:', (new Date()).toISOString());
|
|
146
146
|
return resolve({
|
|
147
|
+
headers,
|
|
147
148
|
statusCode: 200,
|
|
148
149
|
body: JSON.stringify({
|
|
149
150
|
message: 'warm-up'
|
|
@@ -307,7 +308,8 @@ export class Method {
|
|
|
307
308
|
for (let key in attrs) {
|
|
308
309
|
const doc = docs.query?.[key] || {};
|
|
309
310
|
const schema = attrs[key];
|
|
310
|
-
const
|
|
311
|
+
const isNumber = schema.safeParse(0).success || schema.type === 'number';
|
|
312
|
+
const isOptional = schema.safeParse(null).success || schema.safeParse(undefined).success;
|
|
311
313
|
output.parameters.push({
|
|
312
314
|
in: 'query',
|
|
313
315
|
name: key,
|
|
@@ -315,7 +317,7 @@ export class Method {
|
|
|
315
317
|
example: doc.example,
|
|
316
318
|
required: !isOptional,
|
|
317
319
|
schema: {
|
|
318
|
-
type: 'string'
|
|
320
|
+
type: isNumber ? 'number' : 'string'
|
|
319
321
|
}
|
|
320
322
|
});
|
|
321
323
|
}
|
|
@@ -30,6 +30,9 @@ class OpenApiReader {
|
|
|
30
30
|
if (data.enum) {
|
|
31
31
|
output.enum = data.enum;
|
|
32
32
|
}
|
|
33
|
+
if (data.nullable) {
|
|
34
|
+
output.type = [data.type, 'null'];
|
|
35
|
+
}
|
|
33
36
|
if (data.description) {
|
|
34
37
|
output.description = descBeautify(`
|
|
35
38
|
${data.description}
|
|
@@ -47,6 +50,9 @@ class OpenApiReader {
|
|
|
47
50
|
};
|
|
48
51
|
for (let key in data.properties) {
|
|
49
52
|
let property = data.properties[key];
|
|
53
|
+
if (property.nullable && Array.isArray(output.required)) {
|
|
54
|
+
output.required = output.required.filter(e => e !== key);
|
|
55
|
+
}
|
|
50
56
|
if (output.properties) {
|
|
51
57
|
output.properties[key] = this.schemaToJsonSchema(property);
|
|
52
58
|
}
|
|
@@ -141,7 +141,7 @@ export class DocumentDbManager extends Hook {
|
|
|
141
141
|
AttributeName: 'expiredAt'
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
|
-
for (let [key, value] of Object.entries(table.params.
|
|
144
|
+
for (let [key, value] of Object.entries(table.params.indexes)) {
|
|
145
145
|
const attr = value;
|
|
146
146
|
keys.push(attr.primaryKey);
|
|
147
147
|
const KeySchema = [
|
|
@@ -69,7 +69,7 @@ export class DynamoDbTable {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
async getByIndexId(indexName, primary, secondary) {
|
|
72
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
72
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
73
73
|
let KeyConditionExpression = '#P = :P';
|
|
74
74
|
let ExpressionAttributeNames = {
|
|
75
75
|
'#P': primaryKey
|
|
@@ -95,7 +95,7 @@ export class DynamoDbTable {
|
|
|
95
95
|
return Items[0];
|
|
96
96
|
}
|
|
97
97
|
async listByIndexId(indexName, primary, secondary, options) {
|
|
98
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
98
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
99
99
|
let params = {
|
|
100
100
|
Limit: options.limit,
|
|
101
101
|
TableName: this.tableName,
|
|
@@ -152,7 +152,7 @@ export class DynamoDbTable {
|
|
|
152
152
|
return result;
|
|
153
153
|
}
|
|
154
154
|
async listByIndexIdWithTime(indexName, primary, secondary, before, options) {
|
|
155
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
155
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
156
156
|
let params = {
|
|
157
157
|
Limit: options.limit,
|
|
158
158
|
TableName: this.tableName,
|
|
@@ -193,7 +193,7 @@ export class DynamoDbTable {
|
|
|
193
193
|
return result;
|
|
194
194
|
}
|
|
195
195
|
async betweenByIndexId(indexName, primary, secondary, options) {
|
|
196
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
196
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
197
197
|
let params = {
|
|
198
198
|
Limit: options.limit,
|
|
199
199
|
TableName: this.tableName,
|
|
@@ -230,7 +230,7 @@ export class DynamoDbTable {
|
|
|
230
230
|
return Count;
|
|
231
231
|
}
|
|
232
232
|
async countByIndexId(indexName, primary) {
|
|
233
|
-
let { primaryKey } = this.params.
|
|
233
|
+
let { primaryKey } = this.params.indexes[indexName];
|
|
234
234
|
let params = {
|
|
235
235
|
Select: 'COUNT',
|
|
236
236
|
TableName: this.tableName,
|
|
@@ -72,7 +72,7 @@ export class MongoCollection {
|
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
74
|
async getByIndexId(indexName, primary, secondary) {
|
|
75
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
75
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
76
76
|
let { items } = await this.find({
|
|
77
77
|
[primaryKey]: primary,
|
|
78
78
|
[secondaryKey]: secondary
|
|
@@ -82,7 +82,7 @@ export class MongoCollection {
|
|
|
82
82
|
return items[0];
|
|
83
83
|
}
|
|
84
84
|
async listByIndexId(indexName, primary, secondary, options) {
|
|
85
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
85
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
86
86
|
let { nextKey, items } = await this.find({
|
|
87
87
|
[primaryKey]: primary,
|
|
88
88
|
[secondaryKey]: secondary
|
|
@@ -116,7 +116,7 @@ export class MongoCollection {
|
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
118
|
async betweenByIndexId(indexName, primary, secondary, options) {
|
|
119
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
119
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
120
120
|
let { items, nextKey } = await this.find({
|
|
121
121
|
[primaryKey]: primary,
|
|
122
122
|
[secondaryKey]: {
|
|
@@ -141,7 +141,7 @@ export class MongoCollection {
|
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
async listByIndexIdWithTime(indexName, primary, secondary, before, options) {
|
|
144
|
-
let { primaryKey, secondaryKey } = this.params.
|
|
144
|
+
let { primaryKey, secondaryKey } = this.params.indexes[indexName];
|
|
145
145
|
let { items, nextKey } = await this.find({
|
|
146
146
|
[primaryKey]: primary,
|
|
147
147
|
[secondaryKey]: before ? { $lt: secondary } : { $gt: secondary }
|
|
@@ -158,7 +158,7 @@ export class MongoCollection {
|
|
|
158
158
|
return count;
|
|
159
159
|
}
|
|
160
160
|
async countByIndexId(indexName, primary) {
|
|
161
|
-
let { primaryKey } = this.params.
|
|
161
|
+
let { primaryKey } = this.params.indexes[indexName];
|
|
162
162
|
let count = await this.collection.countDocuments({
|
|
163
163
|
[primaryKey]: primary
|
|
164
164
|
});
|
|
@@ -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
|
+
copy(): this;
|
|
62
|
+
from(source: Partial<D> | DataModel<T, D, PublicKey>): void;
|
|
61
63
|
save(reader?: (_data: D) => Partial<D>): Promise<void>;
|
|
62
64
|
remove(): Promise<void>;
|
|
63
65
|
}
|
|
@@ -96,6 +96,15 @@ export class DataModel {
|
|
|
96
96
|
}
|
|
97
97
|
return output;
|
|
98
98
|
}
|
|
99
|
+
copy() {
|
|
100
|
+
const newData = structuredClone(this.data);
|
|
101
|
+
const model = new DataModel(this._config, newData);
|
|
102
|
+
return model;
|
|
103
|
+
}
|
|
104
|
+
from(source) {
|
|
105
|
+
const data = source instanceof DataModel ? source.data : source;
|
|
106
|
+
Object.assign(this.data, data);
|
|
107
|
+
}
|
|
99
108
|
async save(reader = data => data) {
|
|
100
109
|
const table = this._config.table;
|
|
101
110
|
const params = table.params;
|
package/dist/stream/context.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ type Events = {
|
|
|
17
17
|
export declare class StreamRouterContext<Path extends string = any, Body extends Record<string, any> = any, Query extends Record<string, any> = any, Chunk extends Record<string, any> = any, Messages extends FailData = any> {
|
|
18
18
|
_isEnd: boolean;
|
|
19
19
|
_emitter: Event<{
|
|
20
|
-
|
|
20
|
+
close: Record<string, unknown>;
|
|
21
21
|
}>;
|
|
22
22
|
ip: string;
|
|
23
23
|
meta: Record<any, any>;
|
|
@@ -35,8 +35,8 @@ export declare class StreamRouterContext<Path extends string = any, Body extends
|
|
|
35
35
|
interaction: Interaction;
|
|
36
36
|
interactionStepMessage: string;
|
|
37
37
|
methodStream: ResponseStream;
|
|
38
|
-
on: any;
|
|
39
38
|
constructor(method: Method);
|
|
39
|
+
get on(): typeof this._emitter.on;
|
|
40
40
|
static fromAwsLambda(method: Method, event: APIGatewayEvent, responseStream: ResponseStream): Promise<StreamRouterContext<any, any, any, any, any>>;
|
|
41
41
|
_validate(): void;
|
|
42
42
|
isEnded(): boolean;
|
package/dist/stream/context.js
CHANGED
|
@@ -23,7 +23,6 @@ export class StreamRouterContext {
|
|
|
23
23
|
interaction;
|
|
24
24
|
interactionStepMessage = '';
|
|
25
25
|
methodStream;
|
|
26
|
-
on = this._emitter.on.bind(this._emitter);
|
|
27
26
|
constructor(method) {
|
|
28
27
|
this.method = method;
|
|
29
28
|
this.interaction = new Interaction({
|
|
@@ -36,11 +35,14 @@ export class StreamRouterContext {
|
|
|
36
35
|
// 綁定協助解構
|
|
37
36
|
const methods = Object.getOwnPropertyNames(StreamRouterContext.prototype);
|
|
38
37
|
for (let key of methods) {
|
|
39
|
-
if (key !== 'constructor' && typeof this[key] === 'function') {
|
|
38
|
+
if (key !== 'on' && key !== 'constructor' && typeof this[key] === 'function') {
|
|
40
39
|
this[key] = this[key].bind(this);
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
42
|
}
|
|
43
|
+
get on() {
|
|
44
|
+
return this._emitter.on.bind(this._emitter);
|
|
45
|
+
}
|
|
44
46
|
static async fromAwsLambda(method, event, responseStream) {
|
|
45
47
|
const context = new StreamRouterContext(method);
|
|
46
48
|
const xForwardedFor = event.headers['X-Forwarded-For']; // cloudfront
|
|
@@ -55,6 +57,9 @@ export class StreamRouterContext {
|
|
|
55
57
|
context.language = event.headers?.['Accept-Language'] || '';
|
|
56
58
|
context.methodStream = responseStream;
|
|
57
59
|
context.body = json.nonStrictJSONParse(event.body || '{}');
|
|
60
|
+
responseStream.on('close', () => {
|
|
61
|
+
context._emitter.emit('close', {});
|
|
62
|
+
});
|
|
58
63
|
return context;
|
|
59
64
|
}
|
|
60
65
|
_validate() {
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -4,9 +4,8 @@ import { exportOpenApi } from './export-open-api.js';
|
|
|
4
4
|
import { Router, RouterParams, Methods } from './router.js';
|
|
5
5
|
import { AnyError } from '../utils/errors.js';
|
|
6
6
|
import { Handler } from 'aws-lambda';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
end(): void;
|
|
7
|
+
import { Writable } from 'stream';
|
|
8
|
+
export interface ResponseStream extends Writable {
|
|
10
9
|
setContentType(type: string): void;
|
|
11
10
|
}
|
|
12
11
|
export type FailData = Record<string, {
|
|
@@ -35,9 +34,9 @@ export declare class StreamAPIManager extends Event<Channels> {
|
|
|
35
34
|
routers: Router[];
|
|
36
35
|
constructor(params: Params);
|
|
37
36
|
_injectInanis(inanis: Inanis): void;
|
|
38
|
-
createRoute<Path extends string,
|
|
37
|
+
createRoute<Path extends string, Headers extends string>(params: RouterParams<Path, Headers>): Router<Path, Headers>;
|
|
39
38
|
eachMethods(cb: (_route: Router, _method: keyof Methods) => void): void;
|
|
40
|
-
getRouter(path: string): Router<any,
|
|
39
|
+
getRouter(path: string): Router<any, string>;
|
|
41
40
|
getMethod(path: string, method: keyof Methods): import("./method.js").Method<any, any, any, any, any>;
|
|
42
41
|
get outputs(): {
|
|
43
42
|
toTypes: () => Promise<string>;
|
package/dist/stream/index.js
CHANGED
|
@@ -5,6 +5,15 @@ 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
|
+
}
|
|
8
17
|
const exception = rootException.checkout('APIManager');
|
|
9
18
|
const getLambdaGroup = (manager, method, path) => {
|
|
10
19
|
let sourcePath = `${method}@${path}`;
|
|
@@ -123,6 +132,15 @@ export class StreamAPIManager extends Event {
|
|
|
123
132
|
const handlerName = group.handlerName + appendHandleName;
|
|
124
133
|
if (outputs[handlerName] == null) {
|
|
125
134
|
outputs[handlerName] = awslambda.streamifyResponse(async (event, responseStream) => {
|
|
135
|
+
const httpResponseMetadata = {
|
|
136
|
+
statusCode: 200,
|
|
137
|
+
headers: {
|
|
138
|
+
'Content-Type': 'text/event-stream',
|
|
139
|
+
'Access-Control-Allow-Origin': '*',
|
|
140
|
+
'Access-Control-Allow-Credentials': 'true'
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
|
|
126
144
|
let callPath = event.requestContext.resourcePath;
|
|
127
145
|
let isOffline = !!this.params.serverless?.isOffline;
|
|
128
146
|
if (isOffline) {
|
package/dist/stream/method.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export declare class Method<Path extends string = any, Fails extends FailData =
|
|
|
47
47
|
private handler;
|
|
48
48
|
constructor(router: Router, action: string, params: MethodParams<Path, Body, Query, Chunk, Fails>);
|
|
49
49
|
private get inanis();
|
|
50
|
-
get fullRouters(): Router<any,
|
|
50
|
+
get fullRouters(): Router<any, string>[];
|
|
51
51
|
get allowHeaders(): string[];
|
|
52
52
|
run(context: StreamRouterContext): Promise<void>;
|
|
53
53
|
get outputs(): {
|
package/dist/stream/method.js
CHANGED
|
@@ -158,7 +158,8 @@ export class Method {
|
|
|
158
158
|
for (let key in attrs) {
|
|
159
159
|
const doc = docs.query?.[key] || {};
|
|
160
160
|
const schema = attrs[key];
|
|
161
|
-
const
|
|
161
|
+
const isNumber = schema.safeParse(0).success || schema.type === 'number';
|
|
162
|
+
const isOptional = schema.safeParse(null).success || schema.safeParse(undefined).success;
|
|
162
163
|
output.parameters.push({
|
|
163
164
|
in: 'query',
|
|
164
165
|
name: key,
|
|
@@ -166,7 +167,7 @@ export class Method {
|
|
|
166
167
|
example: doc.example,
|
|
167
168
|
required: !isOptional,
|
|
168
169
|
schema: {
|
|
169
|
-
type: 'string'
|
|
170
|
+
type: isNumber ? 'number' : 'string'
|
|
170
171
|
}
|
|
171
172
|
});
|
|
172
173
|
}
|
package/dist/stream/router.d.ts
CHANGED
|
@@ -11,27 +11,25 @@ export type Methods = {
|
|
|
11
11
|
get?: Method;
|
|
12
12
|
post?: Method;
|
|
13
13
|
};
|
|
14
|
-
export type RouterParams<Path extends string,
|
|
14
|
+
export type RouterParams<Path extends string, Headers extends string> = {
|
|
15
15
|
path: Path;
|
|
16
16
|
tags?: string[];
|
|
17
|
-
failMessages: Fails;
|
|
18
17
|
allowHeaders?: Headers[];
|
|
19
18
|
authorizerExpression?: AuthorizerExpression;
|
|
20
19
|
};
|
|
21
|
-
export declare class Router<Path extends string = any,
|
|
20
|
+
export declare class Router<Path extends string = any, Headers extends string = string> {
|
|
22
21
|
tags: string[];
|
|
23
22
|
path: Path;
|
|
24
23
|
manager: StreamAPIManager;
|
|
25
|
-
failMessages: Fails | null;
|
|
26
24
|
methods: Methods;
|
|
27
25
|
allowHeaders: string[];
|
|
28
26
|
authorizerExpression?: AuthorizerExpression;
|
|
29
|
-
constructor(manager: StreamAPIManager, params: RouterParams<Path,
|
|
27
|
+
constructor(manager: StreamAPIManager, params: RouterParams<Path, Headers>);
|
|
30
28
|
get name(): string;
|
|
31
29
|
get fullTags(): string[];
|
|
32
30
|
get schema(): typeof definedValidateSchema;
|
|
33
31
|
get nowAuthorizerExpression(): AuthorizerExpression | null;
|
|
34
|
-
export(): Record<string, Router<any,
|
|
32
|
+
export(): Record<string, Router<any, string>>;
|
|
35
33
|
method<Fails extends FailData, Body extends ValidateCallback<any>, Query extends ValidateCallback<any>, Chunk extends ValidateCallback<any>>(key: keyof Router['methods'], params: MethodParams<Path, Body, Query, Chunk, Fails>): Method;
|
|
36
34
|
}
|
|
37
35
|
export {};
|
package/dist/stream/router.js
CHANGED
|
@@ -6,14 +6,12 @@ export class Router {
|
|
|
6
6
|
tags;
|
|
7
7
|
path;
|
|
8
8
|
manager;
|
|
9
|
-
failMessages = null;
|
|
10
9
|
methods = {};
|
|
11
10
|
allowHeaders;
|
|
12
11
|
authorizerExpression;
|
|
13
12
|
constructor(manager, params) {
|
|
14
13
|
this.path = params.path;
|
|
15
14
|
this.tags = params.tags || [];
|
|
16
|
-
this.failMessages = params.failMessages;
|
|
17
15
|
this.manager = manager;
|
|
18
16
|
this.allowHeaders = params.allowHeaders || [];
|
|
19
17
|
this.authorizerExpression = params.authorizerExpression;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ValidateCallback } from './validate.js';
|
|
3
|
-
export declare const zodToJsonSchema: (cb: ValidateCallback<any>) => z.core.
|
|
3
|
+
export declare const zodToJsonSchema: (cb: ValidateCallback<any>) => z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
|
|
4
|
+
[x: string]: any;
|
|
5
|
+
}, z.core.$strip>>;
|
|
4
6
|
export type JsonSchema = ReturnType<typeof zodToJsonSchema>;
|
package/dist/utils/validate.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inanis",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.7-beta.
|
|
4
|
+
"version": "0.0.7-beta.15",
|
|
5
5
|
"description": "Micro Service Best Tools.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -65,6 +65,7 @@
|
|
|
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",
|
|
68
69
|
"mime": "^4.1.0",
|
|
69
70
|
"mongodb": "^7.0.0",
|
|
70
71
|
"node-rsa": "^1.1.1",
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
"redis": "^5.10.0",
|
|
75
76
|
"websocket": "^1.0.35",
|
|
76
77
|
"yaml": "^2.8.2",
|
|
77
|
-
"zod": "^4.1
|
|
78
|
+
"zod": "^4.2.1"
|
|
78
79
|
},
|
|
79
80
|
"packageManager": "yarn@4.1.1"
|
|
80
81
|
}
|