@opra/common 0.10.3 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/filter/antlr/OpraFilterLexer.js +1 -1
- package/cjs/filter/antlr/OpraFilterListener.js +1 -1
- package/cjs/filter/antlr/OpraFilterParser.js +5 -5
- package/cjs/filter/antlr/OpraFilterVisitor.js +1 -1
- package/cjs/filter/filter-tree-visitor.js +8 -2
- package/cjs/filter/opra-error-listener.js +2 -2
- package/cjs/filter/parse.js +1 -1
- package/cjs/helpers/responsive-map.js +45 -28
- package/{esm/http/enums/http-headers.enum.js → cjs/http/enums/http-headers-codes.enum.js} +95 -92
- package/{esm/http/enums/http-status.enum.js → cjs/http/enums/http-status-codes.enum.js} +62 -59
- package/cjs/http/http-headers.js +213 -0
- package/cjs/http/http-param-codec.js +6 -0
- package/cjs/http/http-params.js +321 -0
- package/cjs/http/http-request-node.js +105 -0
- package/cjs/http/http-request.js +73 -88
- package/cjs/http/http-response.js +23 -0
- package/cjs/http/index.js +13 -2
- package/cjs/http/multipart/batch-multipart.js +12 -12
- package/cjs/http/param-codec/boolean-codec.js +25 -0
- package/cjs/http/param-codec/date-codec.js +44 -0
- package/cjs/http/param-codec/filter-codec.js +18 -0
- package/cjs/http/param-codec/integer-codec.js +19 -0
- package/cjs/http/param-codec/number-codec.js +26 -0
- package/cjs/http/param-codec/string-codec.js +25 -0
- package/cjs/http/utils/encodeURIParam.js +21 -0
- package/cjs/http/utils/normalize-headers.js +2 -2
- package/cjs/i18n/i18n.js +1 -4
- package/cjs/schema/implementation/data-type/data-type.js +4 -0
- package/cjs/schema/implementation/opra-document.js +12 -11
- package/cjs/schema/implementation/resource/collection-resource-info.js +15 -0
- package/cjs/schema/implementation/resource/singleton-resource-info.js +8 -0
- package/cjs/url/opra-url-path.js +96 -72
- package/cjs/url/opra-url-search-params.js +16 -234
- package/cjs/url/opra-url.js +201 -160
- package/esm/filter/antlr/OpraFilterLexer.d.ts +1 -1
- package/esm/filter/antlr/OpraFilterLexer.js +1 -1
- package/esm/filter/antlr/OpraFilterListener.d.ts +1 -1
- package/esm/filter/antlr/OpraFilterListener.js +1 -1
- package/esm/filter/antlr/OpraFilterParser.d.ts +1 -1
- package/esm/filter/antlr/OpraFilterParser.js +5 -5
- package/esm/filter/antlr/OpraFilterVisitor.d.ts +1 -1
- package/esm/filter/antlr/OpraFilterVisitor.js +1 -1
- package/esm/filter/ast/expressions/arithmetic-expression.d.ts +1 -1
- package/esm/filter/ast/expressions/comparison-expression.d.ts +1 -1
- package/esm/filter/ast/expressions/logical-expression.d.ts +1 -1
- package/esm/filter/build.d.ts +3 -3
- package/esm/filter/errors.d.ts +4 -2
- package/esm/filter/filter-tree-visitor.d.ts +2 -1
- package/esm/filter/filter-tree-visitor.js +8 -2
- package/esm/filter/opra-error-listener.d.ts +2 -2
- package/esm/filter/opra-error-listener.js +2 -2
- package/esm/filter/parse.d.ts +1 -1
- package/esm/filter/parse.js +1 -1
- package/esm/helpers/responsive-map.d.ts +19 -5
- package/esm/helpers/responsive-map.js +45 -28
- package/esm/http/enums/{http-headers.enum.d.ts → http-headers-codes.enum.d.ts} +1 -1
- package/{cjs/http/enums/http-headers.enum.js → esm/http/enums/http-headers-codes.enum.js} +92 -95
- package/esm/http/enums/{http-status.enum.d.ts → http-status-codes.enum.d.ts} +1 -1
- package/{cjs/http/enums/http-status.enum.js → esm/http/enums/http-status-codes.enum.js} +59 -62
- package/esm/http/http-headers.d.ts +70 -0
- package/esm/http/http-headers.js +209 -0
- package/esm/http/http-param-codec.d.ts +4 -0
- package/esm/http/http-param-codec.js +2 -0
- package/esm/http/http-params.d.ts +99 -0
- package/esm/http/http-params.js +317 -0
- package/esm/http/http-request-node.d.ts +34 -0
- package/esm/http/http-request-node.js +101 -0
- package/esm/http/http-request.d.ts +73 -31
- package/esm/http/http-request.js +72 -87
- package/esm/http/http-response.d.ts +41 -0
- package/esm/http/http-response.js +19 -0
- package/esm/http/index.d.ts +13 -2
- package/esm/http/index.js +13 -2
- package/esm/http/interfaces/client-http-headers.interface.d.ts +1 -1
- package/esm/http/interfaces/server-http-headers.interface.d.ts +1 -1
- package/esm/http/multipart/batch-multipart.d.ts +1 -1
- package/esm/http/multipart/batch-multipart.js +12 -12
- package/esm/http/multipart/http-request-content.d.ts +1 -1
- package/esm/http/multipart/http-response-content.d.ts +1 -1
- package/esm/http/param-codec/boolean-codec.d.ts +5 -0
- package/esm/http/param-codec/boolean-codec.js +21 -0
- package/esm/http/param-codec/date-codec.d.ts +16 -0
- package/esm/http/param-codec/date-codec.js +40 -0
- package/esm/http/param-codec/filter-codec.d.ts +6 -0
- package/esm/http/param-codec/filter-codec.js +14 -0
- package/esm/http/param-codec/integer-codec.d.ts +9 -0
- package/esm/http/param-codec/integer-codec.js +15 -0
- package/esm/http/param-codec/number-codec.d.ts +12 -0
- package/esm/http/param-codec/number-codec.js +22 -0
- package/esm/http/param-codec/string-codec.d.ts +14 -0
- package/esm/http/param-codec/string-codec.js +21 -0
- package/esm/http/utils/encodeURIParam.d.ts +1 -0
- package/esm/http/utils/encodeURIParam.js +17 -0
- package/esm/http/utils/normalize-headers.js +2 -2
- package/esm/i18n/i18n.d.ts +6 -6
- package/esm/i18n/i18n.js +1 -4
- package/esm/schema/decorators/opr-collection-resource.decorator.d.ts +1 -1
- package/esm/schema/decorators/opr-complex-type.decorator.d.ts +1 -1
- package/esm/schema/decorators/opr-simple-type.decorator.d.ts +1 -1
- package/esm/schema/decorators/opr-singleton-resource.decorator.d.ts +1 -1
- package/esm/schema/implementation/data-type/complex-type.d.ts +1 -1
- package/esm/schema/implementation/data-type/data-type.d.ts +1 -0
- package/esm/schema/implementation/data-type/data-type.js +4 -0
- package/esm/schema/implementation/data-type/union-type.d.ts +1 -1
- package/esm/schema/implementation/document-builder.d.ts +1 -1
- package/esm/schema/implementation/opra-document.d.ts +2 -2
- package/esm/schema/implementation/opra-document.js +12 -11
- package/esm/schema/implementation/query/collection-count-query.d.ts +1 -1
- package/esm/schema/implementation/query/collection-create-query.d.ts +1 -1
- package/esm/schema/implementation/query/collection-delete-many-query.d.ts +1 -1
- package/esm/schema/implementation/query/collection-get-query.d.ts +1 -1
- package/esm/schema/implementation/query/collection-search-query.d.ts +1 -1
- package/esm/schema/implementation/query/collection-update-many-query.d.ts +1 -1
- package/esm/schema/implementation/query/collection-update-query.d.ts +1 -1
- package/esm/schema/implementation/query/field-get-query.d.ts +1 -1
- package/esm/schema/implementation/query/index.d.ts +4 -4
- package/esm/schema/implementation/query/singleton-get-query.d.ts +1 -1
- package/esm/schema/implementation/resource/collection-resource-info.d.ts +3 -0
- package/esm/schema/implementation/resource/collection-resource-info.js +15 -0
- package/esm/schema/implementation/resource/singleton-resource-info.d.ts +1 -0
- package/esm/schema/implementation/resource/singleton-resource-info.js +8 -0
- package/esm/schema/interfaces/data-type.metadata.d.ts +4 -4
- package/esm/schema/interfaces/resource.metadata.d.ts +9 -9
- package/esm/schema/types.d.ts +8 -8
- package/esm/url/opra-url-path-component.d.ts +1 -1
- package/esm/url/opra-url-path.d.ts +24 -18
- package/esm/url/opra-url-path.js +96 -72
- package/esm/url/opra-url-search-params.d.ts +3 -42
- package/esm/url/opra-url-search-params.js +16 -234
- package/esm/url/opra-url.d.ts +38 -28
- package/esm/url/opra-url.js +201 -160
- package/package.json +11 -11
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { StrictOmit } from 'ts-gems';
|
|
2
|
+
import { ResponsiveMap } from '../helpers/responsive-map.js';
|
|
3
|
+
import { HttpParamCodec } from './http-param-codec.js';
|
|
4
|
+
declare const kEntries: unique symbol;
|
|
5
|
+
declare const kSize: unique symbol;
|
|
6
|
+
declare const kParamDefs: unique symbol;
|
|
7
|
+
declare const kOptions: unique symbol;
|
|
8
|
+
export type HttpParamsInit = string | URLSearchParams | HttpParams | Map<string, any> | Record<string, any>;
|
|
9
|
+
export interface HttpParamsCodec {
|
|
10
|
+
encodeKey?: (key: string) => string;
|
|
11
|
+
decodeKey?: (key: string) => string;
|
|
12
|
+
encodeValue?: (value: any) => string;
|
|
13
|
+
decodeValue?: (value: string) => any;
|
|
14
|
+
}
|
|
15
|
+
interface HttpParamMeta {
|
|
16
|
+
codec: HttpParamCodec;
|
|
17
|
+
array?: boolean | 'strict';
|
|
18
|
+
arrayDelimiter?: string;
|
|
19
|
+
minArrayItems?: number;
|
|
20
|
+
maxArrayItems?: number;
|
|
21
|
+
}
|
|
22
|
+
export type HttpParamDefinition = StrictOmit<HttpParamMeta, 'codec'> & {
|
|
23
|
+
codec?: HttpParamCodec | string;
|
|
24
|
+
};
|
|
25
|
+
export interface HttpParamsOptions extends HttpParamsCodec {
|
|
26
|
+
onChange?: () => void;
|
|
27
|
+
params?: Record<string, HttpParamDefinition>;
|
|
28
|
+
}
|
|
29
|
+
export declare class HttpParams {
|
|
30
|
+
protected static kEntries: symbol;
|
|
31
|
+
protected static kSize: symbol;
|
|
32
|
+
protected static kParamDefs: symbol;
|
|
33
|
+
protected static kOptions: symbol;
|
|
34
|
+
protected [kEntries]: ResponsiveMap<string, any[]>;
|
|
35
|
+
protected [kSize]: number;
|
|
36
|
+
protected [kOptions]: HttpParamsOptions;
|
|
37
|
+
protected [kParamDefs]: Map<string, HttpParamMeta>;
|
|
38
|
+
constructor(init?: HttpParamsInit, options?: HttpParamsOptions);
|
|
39
|
+
get size(): number;
|
|
40
|
+
/**
|
|
41
|
+
* Appends a new value to the existing set of values for a parameter
|
|
42
|
+
* and returns this instance
|
|
43
|
+
*/
|
|
44
|
+
append(name: string, value?: any): this;
|
|
45
|
+
appendAll(input: HttpParamsInit): this;
|
|
46
|
+
changed(): void;
|
|
47
|
+
clear(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Deletes values for a given parameter
|
|
50
|
+
*/
|
|
51
|
+
delete(name: string, value?: any): this;
|
|
52
|
+
/**
|
|
53
|
+
* Returns an iterable of key, value pairs for every entry in the map.
|
|
54
|
+
*/
|
|
55
|
+
entries(): IterableIterator<[string, string]>;
|
|
56
|
+
forEach(callbackFn: (value: string, key: string, parent: HttpParams) => void, thisArg?: any): void;
|
|
57
|
+
/**
|
|
58
|
+
* Retrieves value of a given parameter at given index
|
|
59
|
+
*/
|
|
60
|
+
get(name: string, index?: number): any;
|
|
61
|
+
/**
|
|
62
|
+
* Retrieves an array of values for a given parameter.
|
|
63
|
+
*/
|
|
64
|
+
getAll(name: string): any[] | null;
|
|
65
|
+
/**
|
|
66
|
+
* Retrieves the names of the parameters.
|
|
67
|
+
*/
|
|
68
|
+
keys(): IterableIterator<string>;
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves the names of the parameters.
|
|
71
|
+
*/
|
|
72
|
+
values(): IterableIterator<any>;
|
|
73
|
+
/**
|
|
74
|
+
* Checks for existence of a parameter.
|
|
75
|
+
*/
|
|
76
|
+
has(name: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Sets or modifies a value for a given parameter.
|
|
79
|
+
* If the header already exists, its value is replaced with the given value
|
|
80
|
+
*/
|
|
81
|
+
set(name: string, value: any): this;
|
|
82
|
+
sort(compareFn?: (a: string, b: string) => number): this;
|
|
83
|
+
/**
|
|
84
|
+
* Serializes the body to an encoded string, where key-value pairs (separated by `=`) are
|
|
85
|
+
* separated by `&`s.
|
|
86
|
+
*/
|
|
87
|
+
toString(): string;
|
|
88
|
+
define(name: string, options?: HttpParamDefinition): this;
|
|
89
|
+
encodeKey(key: string): string;
|
|
90
|
+
decodeKey(key: string): string;
|
|
91
|
+
encodeValue(value: any, key: string): string;
|
|
92
|
+
decodeValue(value: string, key: string): any;
|
|
93
|
+
protected _append(name: string, value?: any): void;
|
|
94
|
+
protected _delete(name: string, value?: string | string[]): boolean;
|
|
95
|
+
protected _set(name: string, value: any, index?: number): void;
|
|
96
|
+
[Symbol.iterator](): IterableIterator<[string, string]>;
|
|
97
|
+
get [Symbol.toStringTag](): string;
|
|
98
|
+
}
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
var _a, _b, _c;
|
|
2
|
+
import { splitString, tokenize } from 'fast-tokenizer';
|
|
3
|
+
import { ResponsiveMap } from '../helpers/responsive-map.js';
|
|
4
|
+
import { BooleanCodec } from './param-codec/boolean-codec.js';
|
|
5
|
+
import { DateCodec } from './param-codec/date-codec.js';
|
|
6
|
+
import { FilterCodec } from './param-codec/filter-codec.js';
|
|
7
|
+
import { IntegerCodec } from './param-codec/integer-codec.js';
|
|
8
|
+
import { NumberCodec } from './param-codec/number-codec.js';
|
|
9
|
+
import { StringCodec } from './param-codec/string-codec.js';
|
|
10
|
+
import { encodeURIParam } from './utils/encodeURIParam.js';
|
|
11
|
+
const kEntries = Symbol('kEntries');
|
|
12
|
+
const kSize = Symbol('kSize');
|
|
13
|
+
const kParamDefs = Symbol('kParamDefs');
|
|
14
|
+
const kOptions = Symbol('kOptions');
|
|
15
|
+
const defaultKeyDecoder = (s) => decodeURIComponent(s);
|
|
16
|
+
const defaultValueDecoder = (s) => decodeURIComponent(s);
|
|
17
|
+
const defaultKeyEncoder = (s) => encodeURIParam(s);
|
|
18
|
+
const defaultValueEncoder = (s) => encodeURIParam(s);
|
|
19
|
+
const internalCodecs = {
|
|
20
|
+
'boolean': new BooleanCodec(),
|
|
21
|
+
'date': new DateCodec(),
|
|
22
|
+
'filter': new FilterCodec(),
|
|
23
|
+
'integer': new IntegerCodec(),
|
|
24
|
+
'number': new NumberCodec(),
|
|
25
|
+
'string': new StringCodec()
|
|
26
|
+
};
|
|
27
|
+
export class HttpParams {
|
|
28
|
+
constructor(init, options) {
|
|
29
|
+
this[_a] = new ResponsiveMap();
|
|
30
|
+
this[_b] = 0;
|
|
31
|
+
this[_c] = new Map();
|
|
32
|
+
this[kOptions] = { ...options, onChange: undefined };
|
|
33
|
+
const defineParams = options?.params;
|
|
34
|
+
if (defineParams)
|
|
35
|
+
Object.keys(defineParams).forEach(key => this.define(key, defineParams[key]));
|
|
36
|
+
if (init)
|
|
37
|
+
this.appendAll(init);
|
|
38
|
+
this[kOptions].onChange = options?.onChange;
|
|
39
|
+
}
|
|
40
|
+
get size() {
|
|
41
|
+
return this[kSize];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Appends a new value to the existing set of values for a parameter
|
|
45
|
+
* and returns this instance
|
|
46
|
+
*/
|
|
47
|
+
append(name, value) {
|
|
48
|
+
this._append(name, value);
|
|
49
|
+
this.changed();
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
appendAll(input) {
|
|
53
|
+
if (typeof input === 'string') {
|
|
54
|
+
if (input && input.startsWith('?'))
|
|
55
|
+
input = input.substring(1);
|
|
56
|
+
if (!input)
|
|
57
|
+
return this;
|
|
58
|
+
const tokenizer = tokenize(input, { delimiters: '&', quotes: true, brackets: true });
|
|
59
|
+
for (const token of tokenizer) {
|
|
60
|
+
if (!token)
|
|
61
|
+
continue;
|
|
62
|
+
const itemTokenizer = tokenize(token, {
|
|
63
|
+
delimiters: '=',
|
|
64
|
+
quotes: true,
|
|
65
|
+
brackets: true
|
|
66
|
+
});
|
|
67
|
+
const k = this.decodeKey(itemTokenizer.next() || '');
|
|
68
|
+
const v = this.decodeValue(itemTokenizer.join('='), k);
|
|
69
|
+
this._append(k, v);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (input.forEach && typeof input.forEach === 'function')
|
|
73
|
+
input.forEach((value, name) => this._append(name, value));
|
|
74
|
+
else
|
|
75
|
+
Object.keys(input).forEach(name => this._append(name, input[name]));
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
changed() {
|
|
79
|
+
if (this[kOptions].onChange)
|
|
80
|
+
this[kOptions].onChange();
|
|
81
|
+
}
|
|
82
|
+
clear() {
|
|
83
|
+
if (this[kEntries].size) {
|
|
84
|
+
this[kEntries].clear();
|
|
85
|
+
this[kSize] = 0;
|
|
86
|
+
this.changed();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Deletes values for a given parameter
|
|
91
|
+
*/
|
|
92
|
+
delete(name, value) {
|
|
93
|
+
if (this._delete(name, value))
|
|
94
|
+
this.changed();
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns an iterable of key, value pairs for every entry in the map.
|
|
99
|
+
*/
|
|
100
|
+
entries() {
|
|
101
|
+
const iter = this[kEntries].entries();
|
|
102
|
+
let i = 0;
|
|
103
|
+
let key;
|
|
104
|
+
let values;
|
|
105
|
+
return {
|
|
106
|
+
[Symbol.iterator]() {
|
|
107
|
+
return this;
|
|
108
|
+
},
|
|
109
|
+
next() {
|
|
110
|
+
if (values) {
|
|
111
|
+
if (i >= values.length) {
|
|
112
|
+
values = undefined;
|
|
113
|
+
i = 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!values) {
|
|
117
|
+
const n = iter.next();
|
|
118
|
+
if (n.done)
|
|
119
|
+
return { done: true, value: undefined };
|
|
120
|
+
key = n.value[0];
|
|
121
|
+
values = n.value[1];
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
done: false,
|
|
125
|
+
value: [key, values[i++]]
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
forEach(callbackFn, thisArg) {
|
|
131
|
+
const iterator = this.entries();
|
|
132
|
+
let entry = iterator.next();
|
|
133
|
+
while (!entry.done) {
|
|
134
|
+
callbackFn.call(thisArg || this, entry.value[1], entry.value[0], this);
|
|
135
|
+
entry = iterator.next();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Retrieves value of a given parameter at given index
|
|
140
|
+
*/
|
|
141
|
+
get(name, index = 0) {
|
|
142
|
+
const values = this[kEntries].get(name.toLowerCase());
|
|
143
|
+
return values && values.length > index ? values[index] : null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Retrieves an array of values for a given parameter.
|
|
147
|
+
*/
|
|
148
|
+
getAll(name) {
|
|
149
|
+
const entry = this[kEntries].get(name);
|
|
150
|
+
return entry ? entry.slice(0) : null;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Retrieves the names of the parameters.
|
|
154
|
+
*/
|
|
155
|
+
keys() {
|
|
156
|
+
return this[kEntries].keys();
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Retrieves the names of the parameters.
|
|
160
|
+
*/
|
|
161
|
+
values() {
|
|
162
|
+
const items = [];
|
|
163
|
+
this.forEach((value) => items.push(value));
|
|
164
|
+
return items.values();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Checks for existence of a parameter.
|
|
168
|
+
*/
|
|
169
|
+
has(name) {
|
|
170
|
+
return this[kEntries].has(name);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Sets or modifies a value for a given parameter.
|
|
174
|
+
* If the header already exists, its value is replaced with the given value
|
|
175
|
+
*/
|
|
176
|
+
set(name, value) {
|
|
177
|
+
this._set(name, value);
|
|
178
|
+
this.changed();
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
sort(compareFn) {
|
|
182
|
+
this[kEntries].sort(compareFn);
|
|
183
|
+
this.changed();
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Serializes the body to an encoded string, where key-value pairs (separated by `=`) are
|
|
188
|
+
* separated by `&`s.
|
|
189
|
+
*/
|
|
190
|
+
toString() {
|
|
191
|
+
const out = [];
|
|
192
|
+
this.forEach((v, k) => {
|
|
193
|
+
out.push(this.encodeKey(k) +
|
|
194
|
+
(v ? '=' + this.encodeValue(v, k) : ''));
|
|
195
|
+
});
|
|
196
|
+
return out.join('&');
|
|
197
|
+
}
|
|
198
|
+
define(name, options) {
|
|
199
|
+
if (!name)
|
|
200
|
+
throw new Error('Parameter name required');
|
|
201
|
+
if (typeof options?.codec === 'string' && !internalCodecs[options.codec])
|
|
202
|
+
throw new Error(`Unknown url parameter format name "${options.codec}"`);
|
|
203
|
+
const codec = (typeof options?.codec === 'string'
|
|
204
|
+
? internalCodecs[options.codec]
|
|
205
|
+
: options?.codec) || internalCodecs.string;
|
|
206
|
+
const meta = {
|
|
207
|
+
...options,
|
|
208
|
+
codec
|
|
209
|
+
};
|
|
210
|
+
this[kParamDefs].set(name, meta);
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
encodeKey(key) {
|
|
214
|
+
return (this[kOptions].encodeKey || defaultKeyEncoder)(key);
|
|
215
|
+
}
|
|
216
|
+
decodeKey(key) {
|
|
217
|
+
return (this[kOptions].decodeKey || defaultKeyDecoder)(key);
|
|
218
|
+
}
|
|
219
|
+
encodeValue(value, key) {
|
|
220
|
+
const prmDef = this[kParamDefs].get(key);
|
|
221
|
+
if (prmDef) {
|
|
222
|
+
const delimReplace = '%' + (prmDef.arrayDelimiter || ',').charCodeAt(0).toString(16).toUpperCase();
|
|
223
|
+
const fn = (x) => encodeURIParam(prmDef.codec.encode(x)).replaceAll(',', delimReplace);
|
|
224
|
+
return Array.isArray(value)
|
|
225
|
+
? value.map((v) => fn(v)).join(prmDef.arrayDelimiter || ',')
|
|
226
|
+
: fn(value);
|
|
227
|
+
}
|
|
228
|
+
return (this[kOptions].encodeValue || defaultValueEncoder)(value);
|
|
229
|
+
}
|
|
230
|
+
decodeValue(value, key) {
|
|
231
|
+
const prmDef = this[kParamDefs].get(key);
|
|
232
|
+
const valueDecoder = (this[kOptions].decodeValue || defaultValueDecoder);
|
|
233
|
+
let val = value;
|
|
234
|
+
if (prmDef) {
|
|
235
|
+
if (prmDef.array) {
|
|
236
|
+
val = splitString(value, {
|
|
237
|
+
delimiters: prmDef.arrayDelimiter || ',',
|
|
238
|
+
brackets: true,
|
|
239
|
+
quotes: true,
|
|
240
|
+
keepQuotes: false
|
|
241
|
+
}).map((x) => valueDecoder(x));
|
|
242
|
+
}
|
|
243
|
+
else
|
|
244
|
+
val = valueDecoder(val);
|
|
245
|
+
const fn = (x) => prmDef.codec.decode(valueDecoder(x));
|
|
246
|
+
val = Array.isArray(val) ? val.map(fn) : fn(val);
|
|
247
|
+
if (prmDef.array === 'strict')
|
|
248
|
+
val = Array.isArray(val) ? val : [val];
|
|
249
|
+
else if (prmDef.array)
|
|
250
|
+
val = Array.isArray(val) && val.length === 1 ? val[0] : val;
|
|
251
|
+
if (Array.isArray(val)) {
|
|
252
|
+
if (prmDef.minArrayItems && val.length < prmDef.minArrayItems)
|
|
253
|
+
throw new Error(`"${key}" parameter requires at least ${prmDef.minArrayItems} values`);
|
|
254
|
+
if (prmDef.maxArrayItems && val.length > prmDef.maxArrayItems)
|
|
255
|
+
throw new Error(`"${key}" parameter accepts up to ${prmDef.maxArrayItems} values`);
|
|
256
|
+
}
|
|
257
|
+
return val;
|
|
258
|
+
}
|
|
259
|
+
return valueDecoder(value);
|
|
260
|
+
}
|
|
261
|
+
_append(name, value) {
|
|
262
|
+
let values = this[kEntries].get(name);
|
|
263
|
+
if (!values) {
|
|
264
|
+
values = [];
|
|
265
|
+
this[kEntries].set(name, values);
|
|
266
|
+
}
|
|
267
|
+
values.push(value ?? null);
|
|
268
|
+
this[kSize] += 1;
|
|
269
|
+
}
|
|
270
|
+
_delete(name, value) {
|
|
271
|
+
const oldValues = this[kEntries].get(name);
|
|
272
|
+
if (!oldValues)
|
|
273
|
+
return false;
|
|
274
|
+
const oldSize = this[kSize];
|
|
275
|
+
if (value) {
|
|
276
|
+
const valueToDelete = Array.isArray(value) ? value : [value];
|
|
277
|
+
const newValues = oldValues.filter(x => !valueToDelete.includes(x));
|
|
278
|
+
this[kEntries].set(name, newValues);
|
|
279
|
+
this[kSize] += -oldValues.length + newValues.length;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
this[kEntries].delete(name);
|
|
283
|
+
this[kSize] -= oldValues.length;
|
|
284
|
+
}
|
|
285
|
+
return oldSize !== this[kSize];
|
|
286
|
+
}
|
|
287
|
+
_set(name, value, index) {
|
|
288
|
+
if (value == null) {
|
|
289
|
+
this._delete(name);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const values = this[kEntries].get(name);
|
|
293
|
+
if (!values) {
|
|
294
|
+
this[kEntries].set(name, [value]);
|
|
295
|
+
this[kSize] += 1;
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (index == null || index < 0) {
|
|
299
|
+
this[kEntries].set(name, [value]);
|
|
300
|
+
this[kSize] += -(values.length) + 1;
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const oldLen = values.length;
|
|
304
|
+
values[Math.min(index, values.length)] = value;
|
|
305
|
+
this[kSize] += -oldLen + values.length;
|
|
306
|
+
}
|
|
307
|
+
[(_a = kEntries, _b = kSize, _c = kParamDefs, Symbol.iterator)]() {
|
|
308
|
+
return this.entries();
|
|
309
|
+
}
|
|
310
|
+
get [Symbol.toStringTag]() {
|
|
311
|
+
return 'HttpParams';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
HttpParams.kEntries = kEntries;
|
|
315
|
+
HttpParams.kSize = kSize;
|
|
316
|
+
HttpParams.kParamDefs = kParamDefs;
|
|
317
|
+
HttpParams.kOptions = kOptions;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { Readable } from 'stream';
|
|
4
|
+
declare const kHeaders: unique symbol;
|
|
5
|
+
declare const kHeadersCount: unique symbol;
|
|
6
|
+
declare const kTrailers: unique symbol;
|
|
7
|
+
declare const kTrailersCount: unique symbol;
|
|
8
|
+
export declare class HttpRequestNode extends Readable {
|
|
9
|
+
httpVersionMajor: number;
|
|
10
|
+
httpVersionMinor: number;
|
|
11
|
+
httpVersion: string;
|
|
12
|
+
complete: boolean;
|
|
13
|
+
rawHeaders: string[];
|
|
14
|
+
rawTrailers: string[];
|
|
15
|
+
aborted: boolean;
|
|
16
|
+
upgrade: boolean;
|
|
17
|
+
url: string;
|
|
18
|
+
originalUrl: string;
|
|
19
|
+
method: string;
|
|
20
|
+
shouldKeepAlive: boolean;
|
|
21
|
+
data?: Buffer;
|
|
22
|
+
body?: any;
|
|
23
|
+
[kHeaders]: Record<string, string | string[]>;
|
|
24
|
+
[kHeadersCount]: number;
|
|
25
|
+
[kTrailers]: Record<string, string | string[]>;
|
|
26
|
+
[kTrailersCount]: number;
|
|
27
|
+
get headers(): Record<string, string | string[]>;
|
|
28
|
+
get headersCount(): number;
|
|
29
|
+
get trailers(): Record<string, string | string[]>;
|
|
30
|
+
get trailersCount(): number;
|
|
31
|
+
_read(): void;
|
|
32
|
+
static parse(input: Buffer): HttpRequestNode;
|
|
33
|
+
}
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { HTTPParser } from 'http-parser-js';
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
const crlfBuffer = Buffer.from('\r\n');
|
|
4
|
+
const kHeaders = Symbol('kHeaders');
|
|
5
|
+
const kHeadersCount = Symbol('kHeadersCount');
|
|
6
|
+
const kTrailers = Symbol('kTrailers');
|
|
7
|
+
const kTrailersCount = Symbol('kTrailersCount');
|
|
8
|
+
// todo: Check is this class should be in common library
|
|
9
|
+
export class HttpRequestNode extends Readable {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.aborted = false;
|
|
13
|
+
}
|
|
14
|
+
get headers() {
|
|
15
|
+
if (!this[kHeaders])
|
|
16
|
+
this[kHeaders] = arrayToHeaders(this.rawHeaders);
|
|
17
|
+
return this[kHeaders];
|
|
18
|
+
}
|
|
19
|
+
get headersCount() {
|
|
20
|
+
return this[kHeadersCount];
|
|
21
|
+
}
|
|
22
|
+
get trailers() {
|
|
23
|
+
if (!this[kTrailers])
|
|
24
|
+
this[kTrailers] = arrayToHeaders(this.rawTrailers);
|
|
25
|
+
return this[kTrailers];
|
|
26
|
+
}
|
|
27
|
+
get trailersCount() {
|
|
28
|
+
return this[kTrailersCount];
|
|
29
|
+
}
|
|
30
|
+
_read() {
|
|
31
|
+
if (this.data) {
|
|
32
|
+
this.push(this.data);
|
|
33
|
+
}
|
|
34
|
+
this.push(null);
|
|
35
|
+
}
|
|
36
|
+
static parse(input) {
|
|
37
|
+
const parser = new HTTPParser(HTTPParser.REQUEST);
|
|
38
|
+
const out = new HttpRequestNode();
|
|
39
|
+
const bodyChunks = [];
|
|
40
|
+
parser[HTTPParser.kOnHeadersComplete] = function (req) {
|
|
41
|
+
out.shouldKeepAlive = req.shouldKeepAlive;
|
|
42
|
+
out.upgrade = req.upgrade;
|
|
43
|
+
out.method = HTTPParser.methods[req.method];
|
|
44
|
+
out.url = req.url;
|
|
45
|
+
out.originalUrl = req.url;
|
|
46
|
+
out.httpVersionMajor = req.versionMajor;
|
|
47
|
+
out.httpVersionMinor = req.versionMinor;
|
|
48
|
+
out.httpVersion = req.versionMajor + '.' + req.versionMinor;
|
|
49
|
+
out.rawHeaders = req.headers;
|
|
50
|
+
out[kHeadersCount] = Math.ceil(req.headers.length / 2);
|
|
51
|
+
out[kTrailersCount] = 0;
|
|
52
|
+
};
|
|
53
|
+
parser[HTTPParser.kOnBody] = function (chunk, offset, length) {
|
|
54
|
+
bodyChunks.push(chunk.subarray(offset, offset + length));
|
|
55
|
+
};
|
|
56
|
+
// This is actually the event for trailers, go figure.
|
|
57
|
+
parser[HTTPParser.kOnHeaders] = function (t) {
|
|
58
|
+
out.rawTrailers = t;
|
|
59
|
+
out[kTrailersCount] = Math.ceil(t.length / 2);
|
|
60
|
+
};
|
|
61
|
+
parser[HTTPParser.kOnMessageComplete] = function () {
|
|
62
|
+
out.complete = true;
|
|
63
|
+
};
|
|
64
|
+
// Since we are sending the entire Buffer at once here all callbacks above happen synchronously.
|
|
65
|
+
// The parser does not do _anything_ asynchronous.
|
|
66
|
+
// However, you can of course call execute() multiple times with multiple chunks, e.g. from a stream.
|
|
67
|
+
// But then you have to refactor the entire logic to be async (e.g. resolve a Promise in kOnMessageComplete and add timeout logic).
|
|
68
|
+
parser.execute(input);
|
|
69
|
+
if (!out.complete)
|
|
70
|
+
parser.execute(crlfBuffer);
|
|
71
|
+
parser.finish();
|
|
72
|
+
if (!out.complete) {
|
|
73
|
+
throw new Error('Could not parse request');
|
|
74
|
+
}
|
|
75
|
+
out.rawTrailers = out.rawTrailers || [];
|
|
76
|
+
if (bodyChunks.length)
|
|
77
|
+
out.data = Buffer.concat(bodyChunks);
|
|
78
|
+
out.resume();
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function arrayToHeaders(arr) {
|
|
83
|
+
const headers = {};
|
|
84
|
+
for (let i = 0; i < arr.length; i++) {
|
|
85
|
+
const k = arr[i].toLowerCase();
|
|
86
|
+
const v = arr[++i];
|
|
87
|
+
const trgV = headers[k];
|
|
88
|
+
// Array header -- only Set-Cookie at the moment
|
|
89
|
+
if (trgV && k === 'set-cookie') {
|
|
90
|
+
const a = Array.isArray(trgV) ? trgV : [trgV];
|
|
91
|
+
a.push(v);
|
|
92
|
+
headers[k] = a;
|
|
93
|
+
}
|
|
94
|
+
else if (typeof trgV === 'string') {
|
|
95
|
+
headers[k] += (k === 'cookie' ? '; ' : ', ') + v;
|
|
96
|
+
}
|
|
97
|
+
else
|
|
98
|
+
headers[k] = v;
|
|
99
|
+
}
|
|
100
|
+
return headers;
|
|
101
|
+
}
|
|
@@ -1,34 +1,76 @@
|
|
|
1
|
-
/// <reference
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import { OpraURL, OpraURLPath, OpraURLSearchParams } from '../url/index.js';
|
|
3
|
+
import { HttpHeaders, HttpHeadersInit } from './http-headers.js';
|
|
4
|
+
import { HttpParamsInit } from './http-params.js';
|
|
5
|
+
export interface HttpRequestInit {
|
|
6
|
+
cache?: RequestCache;
|
|
7
|
+
credentials?: RequestCredentials;
|
|
8
|
+
destination?: RequestDestination;
|
|
9
|
+
headers?: HttpHeadersInit;
|
|
10
|
+
integrity?: string;
|
|
11
|
+
keepalive?: boolean;
|
|
12
|
+
method?: string;
|
|
13
|
+
mode?: RequestMode;
|
|
14
|
+
params?: HttpParamsInit;
|
|
15
|
+
redirect?: RequestRedirect;
|
|
16
|
+
referrer?: string;
|
|
17
|
+
referrerPolicy?: ReferrerPolicy;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
url?: string;
|
|
20
|
+
body?: any;
|
|
21
|
+
}
|
|
22
|
+
export declare class HttpRequest {
|
|
23
|
+
/** Returns the cache mode associated with request, which is a string indicating
|
|
24
|
+
* how the request will interact with the browser's cache when fetching. */
|
|
25
|
+
cache: RequestCache;
|
|
26
|
+
/** Returns the credentials mode associated with request, which is a string indicating
|
|
27
|
+
* whether credentials will be sent with the request always, never,
|
|
28
|
+
* or only when sent to a same-origin URL. */
|
|
29
|
+
credentials: RequestCredentials;
|
|
30
|
+
/** Returns the kind of resource requested by request, e.g., "document" or "script". */
|
|
31
|
+
destination: RequestDestination;
|
|
32
|
+
/** Returns a Headers object consisting of the headers associated with request.
|
|
33
|
+
* Note that headers added in the network layer by the user agent will not be accounted for in this object,
|
|
34
|
+
* e.g., the "Host" header. */
|
|
35
|
+
headers: HttpHeaders;
|
|
36
|
+
/** Returns request's subresource integrity metadata, which is a cryptographic
|
|
37
|
+
* hash of the resource being fetched.
|
|
38
|
+
* Its value consists of multiple hashes separated by whitespace. [SRI] */
|
|
39
|
+
integrity: string;
|
|
40
|
+
/** Returns a boolean indicating whether or not request can outlive the global in which it was created. */
|
|
41
|
+
keepalive: boolean;
|
|
42
|
+
/** Returns request's HTTP method, which is "GET" by default. */
|
|
19
43
|
method: string;
|
|
20
|
-
|
|
21
|
-
|
|
44
|
+
/** Returns the mode associated with request, which is a string indicating whether the request will use CORS,
|
|
45
|
+
* or will be restricted to same-origin URLs. */
|
|
46
|
+
mode: RequestMode;
|
|
47
|
+
/** Returns the redirect mode associated with request, which is a string indicating
|
|
48
|
+
* how redirects for the request will be handled during fetching. A request will follow redirects by default. */
|
|
49
|
+
redirect: RequestRedirect;
|
|
50
|
+
/** Returns the referrer of request. Its value can be a same-origin URL if explicitly set in init,
|
|
51
|
+
* the empty string to indicate no referrer, and "about:client" when defaulting to the global's default.
|
|
52
|
+
* This is used during fetching to determine the value of the `Referer` header of the request being made. */
|
|
53
|
+
referrer: string;
|
|
54
|
+
/** Returns the referrer policy associated with request. This is used during fetching
|
|
55
|
+
* to compute the value of the request's referrer. */
|
|
56
|
+
referrerPolicy: ReferrerPolicy;
|
|
57
|
+
/** Returns the signal associated with request, which is an AbortSignal object indicating
|
|
58
|
+
* whether or not request has been aborted, and its abort event handler. */
|
|
59
|
+
signal?: AbortSignal;
|
|
60
|
+
/** Returns the parsed url as OpraURL instance */
|
|
61
|
+
readonly urlInstance: OpraURL;
|
|
62
|
+
/** Body of the http request */
|
|
22
63
|
body?: any;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
get
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
64
|
+
duplex?: 'half';
|
|
65
|
+
constructor(init?: HttpRequestInit);
|
|
66
|
+
/** Returns the URL of request as a string. */
|
|
67
|
+
get url(): string;
|
|
68
|
+
set url(value: string);
|
|
69
|
+
/** Returns the searchParams of the URL as OpraURLSearchParams */
|
|
70
|
+
get params(): OpraURLSearchParams;
|
|
71
|
+
/** Returns the path part of URL as OpraURLPath */
|
|
72
|
+
get path(): OpraURLPath;
|
|
73
|
+
clone(...update: (HttpRequest | HttpRequestInit)[]): HttpRequest;
|
|
74
|
+
merge(update: HttpRequest | HttpRequestInit): void;
|
|
75
|
+
inset(src: HttpRequest | HttpRequestInit): void;
|
|
33
76
|
}
|
|
34
|
-
export {};
|