@toa.io/origin 1.4.0 → 1.6.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/dist/index.cjs +56 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -9
- package/dist/index.d.ts +17 -9
- package/dist/index.js +60 -5
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/source/Origin.ts +3 -1
- package/source/Resource.ts +7 -2
- package/source/criteria/Format.ts +4 -0
- package/source/criteria/index.ts +6 -0
- package/source/criteria/range.ts +20 -0
- package/source/index.ts +1 -0
- package/source/query.test.ts +70 -0
- package/source/query.ts +39 -0
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// source/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
connect: () => connect
|
|
33
|
+
connect: () => connect,
|
|
34
|
+
query: () => query
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(index_exports);
|
|
36
37
|
|
|
@@ -135,17 +136,21 @@ var Agent = class {
|
|
|
135
136
|
var Resource = class {
|
|
136
137
|
agent;
|
|
137
138
|
path;
|
|
139
|
+
init;
|
|
138
140
|
constructor(options) {
|
|
139
141
|
this.agent = options.agent;
|
|
140
142
|
this.path = options.path;
|
|
143
|
+
this.init = options.init;
|
|
141
144
|
}
|
|
142
145
|
async json(rel = "", init) {
|
|
143
146
|
const abs = this.abs(rel);
|
|
144
|
-
|
|
147
|
+
const options = Object.assign({}, this.init, init);
|
|
148
|
+
return await this.agent.json(abs, options);
|
|
145
149
|
}
|
|
146
150
|
async octets(rel = "", init) {
|
|
147
151
|
const abs = this.abs(rel);
|
|
148
|
-
|
|
152
|
+
const options = Object.assign({}, this.init, init);
|
|
153
|
+
return await this.agent.octets(abs, options);
|
|
149
154
|
}
|
|
150
155
|
abs(rel) {
|
|
151
156
|
const base = new URL(this.path, "uri://void");
|
|
@@ -167,10 +172,11 @@ var Origin = class {
|
|
|
167
172
|
events: this.events
|
|
168
173
|
});
|
|
169
174
|
}
|
|
170
|
-
resource(path) {
|
|
175
|
+
resource(path, init) {
|
|
171
176
|
return new Resource({
|
|
172
177
|
agent: this.agent,
|
|
173
|
-
path
|
|
178
|
+
path,
|
|
179
|
+
init
|
|
174
180
|
});
|
|
175
181
|
}
|
|
176
182
|
authenticate(challenge) {
|
|
@@ -183,8 +189,52 @@ var Origin = class {
|
|
|
183
189
|
function connect(options) {
|
|
184
190
|
return new Origin(options);
|
|
185
191
|
}
|
|
192
|
+
|
|
193
|
+
// source/criteria/range.ts
|
|
194
|
+
var range_exports = {};
|
|
195
|
+
__export(range_exports, {
|
|
196
|
+
format: () => format,
|
|
197
|
+
test: () => test
|
|
198
|
+
});
|
|
199
|
+
function test(value) {
|
|
200
|
+
return /^[[(]\d+\.\.\d+[\])]{1}$/.test(value);
|
|
201
|
+
}
|
|
202
|
+
function format(name, value) {
|
|
203
|
+
const [min, max] = value.slice(1, -1).split("..");
|
|
204
|
+
return [
|
|
205
|
+
`${name}${value.startsWith("(") ? ">" : ">="}${min}`,
|
|
206
|
+
`${name}${value.endsWith(")") ? "<" : "<="}${max}`
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// source/criteria/index.ts
|
|
211
|
+
var formats = [range_exports];
|
|
212
|
+
|
|
213
|
+
// source/query.ts
|
|
214
|
+
function query(params, options) {
|
|
215
|
+
if (params === void 0) return "";
|
|
216
|
+
const parts = [];
|
|
217
|
+
const criteria = [];
|
|
218
|
+
for (const [key, value] of params.entries()) {
|
|
219
|
+
const name = options?.map?.[key] ?? key;
|
|
220
|
+
if (SEPARATE.includes(name) || options?.separate?.includes(name) === true)
|
|
221
|
+
parts.push(`${name}=${value}`);
|
|
222
|
+
else {
|
|
223
|
+
const format2 = formats.find((format3) => format3.test(value));
|
|
224
|
+
if (format2 === void 0)
|
|
225
|
+
criteria.push(`${name}==${value}`);
|
|
226
|
+
else
|
|
227
|
+
criteria.push(...format2.format(name, value));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (criteria.length > 0)
|
|
231
|
+
parts.unshift(`criteria=${criteria.join(";")}`);
|
|
232
|
+
return parts.length === 0 ? "" : "?" + parts.join("&");
|
|
233
|
+
}
|
|
234
|
+
var SEPARATE = ["omit", "limit", "search"];
|
|
186
235
|
// Annotate the CommonJS export names for ESM import in node:
|
|
187
236
|
0 && (module.exports = {
|
|
188
|
-
connect
|
|
237
|
+
connect,
|
|
238
|
+
query
|
|
189
239
|
});
|
|
190
240
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../source/index.ts","../source/Origin.ts","../source/Agent.ts","../source/Resource.ts"],"sourcesContent":["export { connect } from './Origin'\nexport type { GenericError } from './Error'\nexport type { OctetsEntry, WorkflowStep } from './Octets'\nexport type { RequestOptions } from './Agent'\n","import mitt from 'mitt'\nimport { Agent } from './Agent'\nimport { Resource } from './Resource'\nimport type { Events } from './Events'\nimport type { Emitter } from 'mitt'\n\n/** Resoruce factory */\nclass Origin {\n public readonly events: Emitter<Events>\n private readonly agent: Agent\n\n constructor(options: Options) {\n this.events = mitt<Events>()\n\n this.agent = new Agent({\n origin: options.origin,\n events: this.events,\n })\n }\n\n public resource<T = unknown>(path: string) {\n return new Resource<T>({\n agent: this.agent,\n path,\n })\n }\n\n public authenticate(challenge: string | null) {\n this.agent.authenticate(challenge)\n }\n\n public use(fetch: Fetch) {\n this.agent.use(fetch)\n }\n}\n\nfunction connect(options: Options) {\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n}\n\ntype Fetch = typeof fetch\n\nexport { connect }\n","import { Err } from 'error-value'\nimport { meros } from 'meros/browser'\nimport mitt from 'mitt'\nimport type { GenericError } from './Error'\nimport type { Events } from './Events'\nimport type { Faulty, OctetsEntry, WorkflowStep } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Agent {\n private readonly origin: string\n private readonly events: Emitter<Events>\n private fetch: Fetch = fetch\n\n private challenge: string | null = null\n\n constructor(options: Options) {\n this.origin = options.origin\n this.events = options.events\n }\n\n public async json<T, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<T | E> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n const body = response.headers.get('content-type') === 'application/json'\n ? await response.json()\n : await response.text()\n\n if (response.ok)\n return body as T\n else {\n this.events.emit('error', { code: response.status, body })\n\n return new Err(response.status, body) as E\n }\n }\n\n public async multipart<T = unknown>(path: string, init?: RequestOptions): Promise<AsyncGenerator<T, void, undefined> | GenericError> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n if (!response.ok)\n return new Err(response.status, await response.json())\n\n const generator = await meros(response) as AsyncGenerator<{ body: string }>\n const ack = await generator.next()\n\n if (JSON.parse(ack.value.body) !== 'ACK') throw new Error('No ACK')\n\n return (async function * () {\n for await (const chunk of generator) {\n const value = JSON.parse(chunk.body)\n\n if (value === 'FIN') return\n\n yield value\n }\n })()\n }\n\n public async octets<\n T extends Record<string, unknown> = Record<string, unknown>,\n E extends GenericError = GenericError\n >(path: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | E> {\n const generator = await this.multipart<OctetsEntry | WorkflowStep>(path, init)\n\n if (generator instanceof Error) return generator as E\n\n const chunk = await generator.next()\n const entry = chunk.value as OctetsEntry\n const emitter = mitt<Faulty<T>>()\n\n void (async () => {\n for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {\n const payload =\n part.status === 'completed'\n ? part.output\n : new Err(part.error?.code ?? 'UNKNOWN', part.error?.message)\n\n emitter.emit(part.step, payload as T[typeof part.step])\n }\n\n emitter.off('*')\n })()\n\n return [entry, emitter]\n }\n\n public authenticate(challenge: string | null) {\n this.challenge = challenge\n }\n\n public use(fetch: Fetch) {\n this.fetch = fetch\n }\n\n private setup(init?: RequestOptions): InitWithHeaders {\n init ??= {}\n init.headers ??= {}\n init.headers['accept'] ??= 'application/json'\n\n if (init.credentials === 'include' && init.headers['authorization'] === undefined) {\n if (this.challenge === null)\n throw new Error('Credentials must be set before sending authenticated request')\n\n init.headers['authorization'] = this.challenge\n delete init.credentials // no cookies\n }\n\n if (init.body !== undefined)\n if (init.body instanceof File || init.body instanceof ReadableStream) {\n init.method ??= 'POST'\n init.duplex = 'half'\n init.headers['content-type'] ??= (init.body as File).type ?? 'application/octet-stream'\n } else {\n init.body = JSON.stringify(init.body)\n init.headers['content-type'] ??= 'application/json'\n }\n\n return init as InitWithHeaders\n }\n\n private async request(path: string, init: RequestOptions): Promise<Response> {\n const url = new URL(path, this.origin)\n const response = await this.fetch(url.href, init)\n\n const challenge = response.headers.get('authorization')\n\n if (challenge !== null) {\n this.challenge = challenge\n this.events.emit('challenge', challenge)\n }\n\n return response\n }\n}\n\ninterface Options {\n origin: string\n events: Emitter<Events>\n}\n\ninterface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {\n duplex?: 'half'\n body?: any\n headers?: Record<string, string>\n}\n\ninterface InitWithHeaders extends RequestOptions {\n headers: Record<string, string>\n}\n\ntype Fetch = typeof fetch\n\nexport { Agent }\nexport type { RequestOptions }\n","import type { Agent, RequestOptions } from './Agent'\nimport type { GenericError } from './Error'\nimport type { Faulty, OctetsEntry } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Resource<T = unknown, E extends GenericError = GenericError> {\n private readonly agent: Agent\n private readonly path: string\n\n public constructor(options: Options) {\n this.agent = options.agent\n this.path = options.path\n }\n\n public async json<R = T, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<R | F> {\n const abs = this.abs(rel)\n\n return await this.agent.json<R, F>(abs, init)\n }\n\n public async octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F> {\n const abs = this.abs(rel)\n\n return await this.agent.octets<T, F>(abs, init)\n }\n\n private abs(rel: string): string {\n const base = new URL(this.path, 'uri://void')\n const url = new URL(rel, base)\n\n if (!url.pathname.endsWith('/'))\n url.pathname += '/'\n\n return url.pathname + url.search\n }\n}\n\ninterface Options {\n agent: Agent\n path: string\n}\n\nexport { Resource }\n"],"mappings":"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","names":["import_mitt","mitt","fetch","mitt","fetch"]}
|
|
1
|
+
{"version":3,"sources":["../source/index.ts","../source/Origin.ts","../source/Agent.ts","../source/Resource.ts","../source/criteria/range.ts","../source/criteria/index.ts","../source/query.ts"],"sourcesContent":["export { connect } from './Origin'\nexport { query } from './query'\nexport type { GenericError } from './Error'\nexport type { OctetsEntry, WorkflowStep } from './Octets'\nexport type { RequestOptions } from './Agent'\n","import mitt from 'mitt'\nimport { Agent } from './Agent'\nimport { Resource } from './Resource'\nimport type { RequestOptions } from './Agent'\nimport type { Events } from './Events'\nimport type { Emitter } from 'mitt'\n\n/** Resoruce factory */\nclass Origin {\n public readonly events: Emitter<Events>\n private readonly agent: Agent\n\n constructor(options: Options) {\n this.events = mitt<Events>()\n\n this.agent = new Agent({\n origin: options.origin,\n events: this.events,\n })\n }\n\n public resource<T = unknown>(path: string, init?: Partial<RequestOptions>) {\n return new Resource<T>({\n agent: this.agent,\n path,\n init,\n })\n }\n\n public authenticate(challenge: string | null) {\n this.agent.authenticate(challenge)\n }\n\n public use(fetch: Fetch) {\n this.agent.use(fetch)\n }\n}\n\nfunction connect(options: Options) {\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n}\n\ntype Fetch = typeof fetch\n\nexport { connect }\n","import { Err } from 'error-value'\nimport { meros } from 'meros/browser'\nimport mitt from 'mitt'\nimport type { GenericError } from './Error'\nimport type { Events } from './Events'\nimport type { Faulty, OctetsEntry, WorkflowStep } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Agent {\n private readonly origin: string\n private readonly events: Emitter<Events>\n private fetch: Fetch = fetch\n\n private challenge: string | null = null\n\n constructor(options: Options) {\n this.origin = options.origin\n this.events = options.events\n }\n\n public async json<T, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<T | E> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n const body = response.headers.get('content-type') === 'application/json'\n ? await response.json()\n : await response.text()\n\n if (response.ok)\n return body as T\n else {\n this.events.emit('error', { code: response.status, body })\n\n return new Err(response.status, body) as E\n }\n }\n\n public async multipart<T = unknown>(path: string, init?: RequestOptions): Promise<AsyncGenerator<T, void, undefined> | GenericError> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n if (!response.ok)\n return new Err(response.status, await response.json())\n\n const generator = await meros(response) as AsyncGenerator<{ body: string }>\n const ack = await generator.next()\n\n if (JSON.parse(ack.value.body) !== 'ACK') throw new Error('No ACK')\n\n return (async function * () {\n for await (const chunk of generator) {\n const value = JSON.parse(chunk.body)\n\n if (value === 'FIN') return\n\n yield value\n }\n })()\n }\n\n public async octets<\n T extends Record<string, unknown> = Record<string, unknown>,\n E extends GenericError = GenericError\n >(path: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | E> {\n const generator = await this.multipart<OctetsEntry | WorkflowStep>(path, init)\n\n if (generator instanceof Error) return generator as E\n\n const chunk = await generator.next()\n const entry = chunk.value as OctetsEntry\n const emitter = mitt<Faulty<T>>()\n\n void (async () => {\n for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {\n const payload =\n part.status === 'completed'\n ? part.output\n : new Err(part.error?.code ?? 'UNKNOWN', part.error?.message)\n\n emitter.emit(part.step, payload as T[typeof part.step])\n }\n\n emitter.off('*')\n })()\n\n return [entry, emitter]\n }\n\n public authenticate(challenge: string | null) {\n this.challenge = challenge\n }\n\n public use(fetch: Fetch) {\n this.fetch = fetch\n }\n\n private setup(init?: RequestOptions): InitWithHeaders {\n init ??= {}\n init.headers ??= {}\n init.headers['accept'] ??= 'application/json'\n\n if (init.credentials === 'include' && init.headers['authorization'] === undefined) {\n if (this.challenge === null)\n throw new Error('Credentials must be set before sending authenticated request')\n\n init.headers['authorization'] = this.challenge\n delete init.credentials // no cookies\n }\n\n if (init.body !== undefined)\n if (init.body instanceof File || init.body instanceof ReadableStream) {\n init.method ??= 'POST'\n init.duplex = 'half'\n init.headers['content-type'] ??= (init.body as File).type ?? 'application/octet-stream'\n } else {\n init.body = JSON.stringify(init.body)\n init.headers['content-type'] ??= 'application/json'\n }\n\n return init as InitWithHeaders\n }\n\n private async request(path: string, init: RequestOptions): Promise<Response> {\n const url = new URL(path, this.origin)\n const response = await this.fetch(url.href, init)\n\n const challenge = response.headers.get('authorization')\n\n if (challenge !== null) {\n this.challenge = challenge\n this.events.emit('challenge', challenge)\n }\n\n return response\n }\n}\n\ninterface Options {\n origin: string\n events: Emitter<Events>\n}\n\ninterface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {\n duplex?: 'half'\n body?: any\n headers?: Record<string, string>\n}\n\ninterface InitWithHeaders extends RequestOptions {\n headers: Record<string, string>\n}\n\ntype Fetch = typeof fetch\n\nexport { Agent }\nexport type { RequestOptions }\n","import type { Agent, RequestOptions } from './Agent'\nimport type { GenericError } from './Error'\nimport type { Faulty, OctetsEntry } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Resource<T = unknown, E extends GenericError = GenericError> {\n private readonly agent: Agent\n private readonly path: string\n private readonly init?: Partial<RequestOptions>\n\n public constructor(options: Options) {\n this.agent = options.agent\n this.path = options.path\n this.init = options.init\n }\n\n public async json<R = T, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<R | F> {\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n return await this.agent.json<R, F>(abs, options)\n }\n\n public async octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F> {\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n return await this.agent.octets<T, F>(abs, options)\n }\n\n private abs(rel: string): string {\n const base = new URL(this.path, 'uri://void')\n const url = new URL(rel, base)\n\n if (!url.pathname.endsWith('/'))\n url.pathname += '/'\n\n return url.pathname + url.search\n }\n}\n\ninterface Options {\n agent: Agent\n path: string\n init?: Partial<RequestOptions>\n}\n\nexport { Resource }\n","/**\n *\n * @example\n * [10..20]\n * [10..20)\n * (10..20]\n * (10..20)\n */\nexport function test(value: string): boolean {\n return /^[[(]\\d+\\.\\.\\d+[\\])]{1}$/.test(value)\n}\n\nexport function format(name: string, value: string): string[] {\n const [min, max] = value.slice(1, -1).split('..')\n\n return [\n `${name}${value.startsWith('(') ? '>' : '>='}${min}`,\n `${name}${value.endsWith(')') ? '<' : '<='}${max}`,\n ]\n}\n","import * as range from './range'\nimport type { Format } from './Format'\n\nconst formats: Format[] = [range]\n\nexport { formats }\n","import { formats } from './criteria'\n\nfunction query(params?: URLSearchParams, options?: Options): string {\n if (params === undefined) return ''\n\n const parts: string[] = []\n const criteria: string[] = []\n\n for (const [key, value] of params.entries()) {\n const name = options?.map?.[key] ?? key\n\n if (SEPARATE.includes(name) || options?.separate?.includes(name) === true)\n parts.push(`${name}=${value}`)\n else {\n const format = formats.find((format) => format.test(value))\n\n if (format === undefined)\n criteria.push(`${name}==${value}`)\n else\n criteria.push(...format.format(name, value))\n }\n }\n\n if (criteria.length > 0)\n parts.unshift(`criteria=${criteria.join(';')}`)\n\n return parts.length === 0\n ? ''\n : '?' + parts.join('&')\n}\n\nconst SEPARATE: string[] = ['omit', 'limit', 'search'] as const\n\ninterface Options {\n separate?: string[]\n map?: Record<string, string>\n}\n\nexport { query }\n"],"mappings":"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","names":["import_mitt","mitt","fetch","mitt","fetch","format"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -27,7 +27,7 @@ declare class Agent {
|
|
|
27
27
|
private readonly events;
|
|
28
28
|
private fetch;
|
|
29
29
|
private challenge;
|
|
30
|
-
constructor(options: Options$
|
|
30
|
+
constructor(options: Options$3);
|
|
31
31
|
json<T, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<T | E>;
|
|
32
32
|
multipart<T = unknown>(path: string, init?: RequestOptions): Promise<AsyncGenerator<T, void, undefined> | GenericError>;
|
|
33
33
|
octets<T extends Record<string, unknown> = Record<string, unknown>, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | E>;
|
|
@@ -36,7 +36,7 @@ declare class Agent {
|
|
|
36
36
|
private setup;
|
|
37
37
|
private request;
|
|
38
38
|
}
|
|
39
|
-
interface Options$
|
|
39
|
+
interface Options$3 {
|
|
40
40
|
origin: string;
|
|
41
41
|
events: Emitter<Events>;
|
|
42
42
|
}
|
|
@@ -50,29 +50,37 @@ type Fetch$1 = typeof fetch;
|
|
|
50
50
|
declare class Resource<T = unknown, E extends GenericError = GenericError> {
|
|
51
51
|
private readonly agent;
|
|
52
52
|
private readonly path;
|
|
53
|
-
|
|
53
|
+
private readonly init?;
|
|
54
|
+
constructor(options: Options$2);
|
|
54
55
|
json<R = T, F extends E = E>(rel?: string, init?: RequestOptions): Promise<R | F>;
|
|
55
56
|
octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel?: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F>;
|
|
56
57
|
private abs;
|
|
57
58
|
}
|
|
58
|
-
interface Options$
|
|
59
|
+
interface Options$2 {
|
|
59
60
|
agent: Agent;
|
|
60
61
|
path: string;
|
|
62
|
+
init?: Partial<RequestOptions>;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/** Resoruce factory */
|
|
64
66
|
declare class Origin {
|
|
65
67
|
readonly events: Emitter<Events>;
|
|
66
68
|
private readonly agent;
|
|
67
|
-
constructor(options: Options);
|
|
68
|
-
resource<T = unknown>(path: string): Resource<T, GenericError>;
|
|
69
|
+
constructor(options: Options$1);
|
|
70
|
+
resource<T = unknown>(path: string, init?: Partial<RequestOptions>): Resource<T, GenericError>;
|
|
69
71
|
authenticate(challenge: string | null): void;
|
|
70
72
|
use(fetch: Fetch): void;
|
|
71
73
|
}
|
|
72
|
-
declare function connect(options: Options): Origin;
|
|
73
|
-
interface Options {
|
|
74
|
+
declare function connect(options: Options$1): Origin;
|
|
75
|
+
interface Options$1 {
|
|
74
76
|
origin: string;
|
|
75
77
|
}
|
|
76
78
|
type Fetch = typeof fetch;
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
declare function query(params?: URLSearchParams, options?: Options): string;
|
|
81
|
+
interface Options {
|
|
82
|
+
separate?: string[];
|
|
83
|
+
map?: Record<string, string>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { type GenericError, type OctetsEntry, type RequestOptions, type WorkflowStep, connect, query };
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ declare class Agent {
|
|
|
27
27
|
private readonly events;
|
|
28
28
|
private fetch;
|
|
29
29
|
private challenge;
|
|
30
|
-
constructor(options: Options$
|
|
30
|
+
constructor(options: Options$3);
|
|
31
31
|
json<T, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<T | E>;
|
|
32
32
|
multipart<T = unknown>(path: string, init?: RequestOptions): Promise<AsyncGenerator<T, void, undefined> | GenericError>;
|
|
33
33
|
octets<T extends Record<string, unknown> = Record<string, unknown>, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | E>;
|
|
@@ -36,7 +36,7 @@ declare class Agent {
|
|
|
36
36
|
private setup;
|
|
37
37
|
private request;
|
|
38
38
|
}
|
|
39
|
-
interface Options$
|
|
39
|
+
interface Options$3 {
|
|
40
40
|
origin: string;
|
|
41
41
|
events: Emitter<Events>;
|
|
42
42
|
}
|
|
@@ -50,29 +50,37 @@ type Fetch$1 = typeof fetch;
|
|
|
50
50
|
declare class Resource<T = unknown, E extends GenericError = GenericError> {
|
|
51
51
|
private readonly agent;
|
|
52
52
|
private readonly path;
|
|
53
|
-
|
|
53
|
+
private readonly init?;
|
|
54
|
+
constructor(options: Options$2);
|
|
54
55
|
json<R = T, F extends E = E>(rel?: string, init?: RequestOptions): Promise<R | F>;
|
|
55
56
|
octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel?: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F>;
|
|
56
57
|
private abs;
|
|
57
58
|
}
|
|
58
|
-
interface Options$
|
|
59
|
+
interface Options$2 {
|
|
59
60
|
agent: Agent;
|
|
60
61
|
path: string;
|
|
62
|
+
init?: Partial<RequestOptions>;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
/** Resoruce factory */
|
|
64
66
|
declare class Origin {
|
|
65
67
|
readonly events: Emitter<Events>;
|
|
66
68
|
private readonly agent;
|
|
67
|
-
constructor(options: Options);
|
|
68
|
-
resource<T = unknown>(path: string): Resource<T, GenericError>;
|
|
69
|
+
constructor(options: Options$1);
|
|
70
|
+
resource<T = unknown>(path: string, init?: Partial<RequestOptions>): Resource<T, GenericError>;
|
|
69
71
|
authenticate(challenge: string | null): void;
|
|
70
72
|
use(fetch: Fetch): void;
|
|
71
73
|
}
|
|
72
|
-
declare function connect(options: Options): Origin;
|
|
73
|
-
interface Options {
|
|
74
|
+
declare function connect(options: Options$1): Origin;
|
|
75
|
+
interface Options$1 {
|
|
74
76
|
origin: string;
|
|
75
77
|
}
|
|
76
78
|
type Fetch = typeof fetch;
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
declare function query(params?: URLSearchParams, options?: Options): string;
|
|
81
|
+
interface Options {
|
|
82
|
+
separate?: string[];
|
|
83
|
+
map?: Record<string, string>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { type GenericError, type OctetsEntry, type RequestOptions, type WorkflowStep, connect, query };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
1
7
|
// source/Origin.ts
|
|
2
8
|
import mitt2 from "mitt";
|
|
3
9
|
|
|
@@ -99,17 +105,21 @@ var Agent = class {
|
|
|
99
105
|
var Resource = class {
|
|
100
106
|
agent;
|
|
101
107
|
path;
|
|
108
|
+
init;
|
|
102
109
|
constructor(options) {
|
|
103
110
|
this.agent = options.agent;
|
|
104
111
|
this.path = options.path;
|
|
112
|
+
this.init = options.init;
|
|
105
113
|
}
|
|
106
114
|
async json(rel = "", init) {
|
|
107
115
|
const abs = this.abs(rel);
|
|
108
|
-
|
|
116
|
+
const options = Object.assign({}, this.init, init);
|
|
117
|
+
return await this.agent.json(abs, options);
|
|
109
118
|
}
|
|
110
119
|
async octets(rel = "", init) {
|
|
111
120
|
const abs = this.abs(rel);
|
|
112
|
-
|
|
121
|
+
const options = Object.assign({}, this.init, init);
|
|
122
|
+
return await this.agent.octets(abs, options);
|
|
113
123
|
}
|
|
114
124
|
abs(rel) {
|
|
115
125
|
const base = new URL(this.path, "uri://void");
|
|
@@ -131,10 +141,11 @@ var Origin = class {
|
|
|
131
141
|
events: this.events
|
|
132
142
|
});
|
|
133
143
|
}
|
|
134
|
-
resource(path) {
|
|
144
|
+
resource(path, init) {
|
|
135
145
|
return new Resource({
|
|
136
146
|
agent: this.agent,
|
|
137
|
-
path
|
|
147
|
+
path,
|
|
148
|
+
init
|
|
138
149
|
});
|
|
139
150
|
}
|
|
140
151
|
authenticate(challenge) {
|
|
@@ -147,7 +158,51 @@ var Origin = class {
|
|
|
147
158
|
function connect(options) {
|
|
148
159
|
return new Origin(options);
|
|
149
160
|
}
|
|
161
|
+
|
|
162
|
+
// source/criteria/range.ts
|
|
163
|
+
var range_exports = {};
|
|
164
|
+
__export(range_exports, {
|
|
165
|
+
format: () => format,
|
|
166
|
+
test: () => test
|
|
167
|
+
});
|
|
168
|
+
function test(value) {
|
|
169
|
+
return /^[[(]\d+\.\.\d+[\])]{1}$/.test(value);
|
|
170
|
+
}
|
|
171
|
+
function format(name, value) {
|
|
172
|
+
const [min, max] = value.slice(1, -1).split("..");
|
|
173
|
+
return [
|
|
174
|
+
`${name}${value.startsWith("(") ? ">" : ">="}${min}`,
|
|
175
|
+
`${name}${value.endsWith(")") ? "<" : "<="}${max}`
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// source/criteria/index.ts
|
|
180
|
+
var formats = [range_exports];
|
|
181
|
+
|
|
182
|
+
// source/query.ts
|
|
183
|
+
function query(params, options) {
|
|
184
|
+
if (params === void 0) return "";
|
|
185
|
+
const parts = [];
|
|
186
|
+
const criteria = [];
|
|
187
|
+
for (const [key, value] of params.entries()) {
|
|
188
|
+
const name = options?.map?.[key] ?? key;
|
|
189
|
+
if (SEPARATE.includes(name) || options?.separate?.includes(name) === true)
|
|
190
|
+
parts.push(`${name}=${value}`);
|
|
191
|
+
else {
|
|
192
|
+
const format2 = formats.find((format3) => format3.test(value));
|
|
193
|
+
if (format2 === void 0)
|
|
194
|
+
criteria.push(`${name}==${value}`);
|
|
195
|
+
else
|
|
196
|
+
criteria.push(...format2.format(name, value));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (criteria.length > 0)
|
|
200
|
+
parts.unshift(`criteria=${criteria.join(";")}`);
|
|
201
|
+
return parts.length === 0 ? "" : "?" + parts.join("&");
|
|
202
|
+
}
|
|
203
|
+
var SEPARATE = ["omit", "limit", "search"];
|
|
150
204
|
export {
|
|
151
|
-
connect
|
|
205
|
+
connect,
|
|
206
|
+
query
|
|
152
207
|
};
|
|
153
208
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../source/Origin.ts","../source/Agent.ts","../source/Resource.ts"],"sourcesContent":["import mitt from 'mitt'\nimport { Agent } from './Agent'\nimport { Resource } from './Resource'\nimport type { Events } from './Events'\nimport type { Emitter } from 'mitt'\n\n/** Resoruce factory */\nclass Origin {\n public readonly events: Emitter<Events>\n private readonly agent: Agent\n\n constructor(options: Options) {\n this.events = mitt<Events>()\n\n this.agent = new Agent({\n origin: options.origin,\n events: this.events,\n })\n }\n\n public resource<T = unknown>(path: string) {\n return new Resource<T>({\n agent: this.agent,\n path,\n })\n }\n\n public authenticate(challenge: string | null) {\n this.agent.authenticate(challenge)\n }\n\n public use(fetch: Fetch) {\n this.agent.use(fetch)\n }\n}\n\nfunction connect(options: Options) {\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n}\n\ntype Fetch = typeof fetch\n\nexport { connect }\n","import { Err } from 'error-value'\nimport { meros } from 'meros/browser'\nimport mitt from 'mitt'\nimport type { GenericError } from './Error'\nimport type { Events } from './Events'\nimport type { Faulty, OctetsEntry, WorkflowStep } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Agent {\n private readonly origin: string\n private readonly events: Emitter<Events>\n private fetch: Fetch = fetch\n\n private challenge: string | null = null\n\n constructor(options: Options) {\n this.origin = options.origin\n this.events = options.events\n }\n\n public async json<T, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<T | E> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n const body = response.headers.get('content-type') === 'application/json'\n ? await response.json()\n : await response.text()\n\n if (response.ok)\n return body as T\n else {\n this.events.emit('error', { code: response.status, body })\n\n return new Err(response.status, body) as E\n }\n }\n\n public async multipart<T = unknown>(path: string, init?: RequestOptions): Promise<AsyncGenerator<T, void, undefined> | GenericError> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n if (!response.ok)\n return new Err(response.status, await response.json())\n\n const generator = await meros(response) as AsyncGenerator<{ body: string }>\n const ack = await generator.next()\n\n if (JSON.parse(ack.value.body) !== 'ACK') throw new Error('No ACK')\n\n return (async function * () {\n for await (const chunk of generator) {\n const value = JSON.parse(chunk.body)\n\n if (value === 'FIN') return\n\n yield value\n }\n })()\n }\n\n public async octets<\n T extends Record<string, unknown> = Record<string, unknown>,\n E extends GenericError = GenericError\n >(path: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | E> {\n const generator = await this.multipart<OctetsEntry | WorkflowStep>(path, init)\n\n if (generator instanceof Error) return generator as E\n\n const chunk = await generator.next()\n const entry = chunk.value as OctetsEntry\n const emitter = mitt<Faulty<T>>()\n\n void (async () => {\n for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {\n const payload =\n part.status === 'completed'\n ? part.output\n : new Err(part.error?.code ?? 'UNKNOWN', part.error?.message)\n\n emitter.emit(part.step, payload as T[typeof part.step])\n }\n\n emitter.off('*')\n })()\n\n return [entry, emitter]\n }\n\n public authenticate(challenge: string | null) {\n this.challenge = challenge\n }\n\n public use(fetch: Fetch) {\n this.fetch = fetch\n }\n\n private setup(init?: RequestOptions): InitWithHeaders {\n init ??= {}\n init.headers ??= {}\n init.headers['accept'] ??= 'application/json'\n\n if (init.credentials === 'include' && init.headers['authorization'] === undefined) {\n if (this.challenge === null)\n throw new Error('Credentials must be set before sending authenticated request')\n\n init.headers['authorization'] = this.challenge\n delete init.credentials // no cookies\n }\n\n if (init.body !== undefined)\n if (init.body instanceof File || init.body instanceof ReadableStream) {\n init.method ??= 'POST'\n init.duplex = 'half'\n init.headers['content-type'] ??= (init.body as File).type ?? 'application/octet-stream'\n } else {\n init.body = JSON.stringify(init.body)\n init.headers['content-type'] ??= 'application/json'\n }\n\n return init as InitWithHeaders\n }\n\n private async request(path: string, init: RequestOptions): Promise<Response> {\n const url = new URL(path, this.origin)\n const response = await this.fetch(url.href, init)\n\n const challenge = response.headers.get('authorization')\n\n if (challenge !== null) {\n this.challenge = challenge\n this.events.emit('challenge', challenge)\n }\n\n return response\n }\n}\n\ninterface Options {\n origin: string\n events: Emitter<Events>\n}\n\ninterface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {\n duplex?: 'half'\n body?: any\n headers?: Record<string, string>\n}\n\ninterface InitWithHeaders extends RequestOptions {\n headers: Record<string, string>\n}\n\ntype Fetch = typeof fetch\n\nexport { Agent }\nexport type { RequestOptions }\n","import type { Agent, RequestOptions } from './Agent'\nimport type { GenericError } from './Error'\nimport type { Faulty, OctetsEntry } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Resource<T = unknown, E extends GenericError = GenericError> {\n private readonly agent: Agent\n private readonly path: string\n\n public constructor(options: Options) {\n this.agent = options.agent\n this.path = options.path\n }\n\n public async json<R = T, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<R | F> {\n const abs = this.abs(rel)\n\n return await this.agent.json<R, F>(abs, init)\n }\n\n public async octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F> {\n const abs = this.abs(rel)\n\n return await this.agent.octets<T, F>(abs, init)\n }\n\n private abs(rel: string): string {\n const base = new URL(this.path, 'uri://void')\n const url = new URL(rel, base)\n\n if (!url.pathname.endsWith('/'))\n url.pathname += '/'\n\n return url.pathname + url.search\n }\n}\n\ninterface Options {\n agent: Agent\n path: string\n}\n\nexport { Resource }\n"],"mappings":"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","names":["mitt","fetch","mitt","fetch"]}
|
|
1
|
+
{"version":3,"sources":["../source/Origin.ts","../source/Agent.ts","../source/Resource.ts","../source/criteria/range.ts","../source/criteria/index.ts","../source/query.ts"],"sourcesContent":["import mitt from 'mitt'\nimport { Agent } from './Agent'\nimport { Resource } from './Resource'\nimport type { RequestOptions } from './Agent'\nimport type { Events } from './Events'\nimport type { Emitter } from 'mitt'\n\n/** Resoruce factory */\nclass Origin {\n public readonly events: Emitter<Events>\n private readonly agent: Agent\n\n constructor(options: Options) {\n this.events = mitt<Events>()\n\n this.agent = new Agent({\n origin: options.origin,\n events: this.events,\n })\n }\n\n public resource<T = unknown>(path: string, init?: Partial<RequestOptions>) {\n return new Resource<T>({\n agent: this.agent,\n path,\n init,\n })\n }\n\n public authenticate(challenge: string | null) {\n this.agent.authenticate(challenge)\n }\n\n public use(fetch: Fetch) {\n this.agent.use(fetch)\n }\n}\n\nfunction connect(options: Options) {\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n}\n\ntype Fetch = typeof fetch\n\nexport { connect }\n","import { Err } from 'error-value'\nimport { meros } from 'meros/browser'\nimport mitt from 'mitt'\nimport type { GenericError } from './Error'\nimport type { Events } from './Events'\nimport type { Faulty, OctetsEntry, WorkflowStep } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Agent {\n private readonly origin: string\n private readonly events: Emitter<Events>\n private fetch: Fetch = fetch\n\n private challenge: string | null = null\n\n constructor(options: Options) {\n this.origin = options.origin\n this.events = options.events\n }\n\n public async json<T, E extends GenericError = GenericError>(path: string, init?: RequestOptions): Promise<T | E> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n const body = response.headers.get('content-type') === 'application/json'\n ? await response.json()\n : await response.text()\n\n if (response.ok)\n return body as T\n else {\n this.events.emit('error', { code: response.status, body })\n\n return new Err(response.status, body) as E\n }\n }\n\n public async multipart<T = unknown>(path: string, init?: RequestOptions): Promise<AsyncGenerator<T, void, undefined> | GenericError> {\n const options = this.setup(init)\n const response = await this.request(path, options)\n\n if (!response.ok)\n return new Err(response.status, await response.json())\n\n const generator = await meros(response) as AsyncGenerator<{ body: string }>\n const ack = await generator.next()\n\n if (JSON.parse(ack.value.body) !== 'ACK') throw new Error('No ACK')\n\n return (async function * () {\n for await (const chunk of generator) {\n const value = JSON.parse(chunk.body)\n\n if (value === 'FIN') return\n\n yield value\n }\n })()\n }\n\n public async octets<\n T extends Record<string, unknown> = Record<string, unknown>,\n E extends GenericError = GenericError\n >(path: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | E> {\n const generator = await this.multipart<OctetsEntry | WorkflowStep>(path, init)\n\n if (generator instanceof Error) return generator as E\n\n const chunk = await generator.next()\n const entry = chunk.value as OctetsEntry\n const emitter = mitt<Faulty<T>>()\n\n void (async () => {\n for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {\n const payload =\n part.status === 'completed'\n ? part.output\n : new Err(part.error?.code ?? 'UNKNOWN', part.error?.message)\n\n emitter.emit(part.step, payload as T[typeof part.step])\n }\n\n emitter.off('*')\n })()\n\n return [entry, emitter]\n }\n\n public authenticate(challenge: string | null) {\n this.challenge = challenge\n }\n\n public use(fetch: Fetch) {\n this.fetch = fetch\n }\n\n private setup(init?: RequestOptions): InitWithHeaders {\n init ??= {}\n init.headers ??= {}\n init.headers['accept'] ??= 'application/json'\n\n if (init.credentials === 'include' && init.headers['authorization'] === undefined) {\n if (this.challenge === null)\n throw new Error('Credentials must be set before sending authenticated request')\n\n init.headers['authorization'] = this.challenge\n delete init.credentials // no cookies\n }\n\n if (init.body !== undefined)\n if (init.body instanceof File || init.body instanceof ReadableStream) {\n init.method ??= 'POST'\n init.duplex = 'half'\n init.headers['content-type'] ??= (init.body as File).type ?? 'application/octet-stream'\n } else {\n init.body = JSON.stringify(init.body)\n init.headers['content-type'] ??= 'application/json'\n }\n\n return init as InitWithHeaders\n }\n\n private async request(path: string, init: RequestOptions): Promise<Response> {\n const url = new URL(path, this.origin)\n const response = await this.fetch(url.href, init)\n\n const challenge = response.headers.get('authorization')\n\n if (challenge !== null) {\n this.challenge = challenge\n this.events.emit('challenge', challenge)\n }\n\n return response\n }\n}\n\ninterface Options {\n origin: string\n events: Emitter<Events>\n}\n\ninterface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {\n duplex?: 'half'\n body?: any\n headers?: Record<string, string>\n}\n\ninterface InitWithHeaders extends RequestOptions {\n headers: Record<string, string>\n}\n\ntype Fetch = typeof fetch\n\nexport { Agent }\nexport type { RequestOptions }\n","import type { Agent, RequestOptions } from './Agent'\nimport type { GenericError } from './Error'\nimport type { Faulty, OctetsEntry } from './Octets'\nimport type { Emitter } from 'mitt'\n\nclass Resource<T = unknown, E extends GenericError = GenericError> {\n private readonly agent: Agent\n private readonly path: string\n private readonly init?: Partial<RequestOptions>\n\n public constructor(options: Options) {\n this.agent = options.agent\n this.path = options.path\n this.init = options.init\n }\n\n public async json<R = T, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<R | F> {\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n return await this.agent.json<R, F>(abs, options)\n }\n\n public async octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F> {\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n return await this.agent.octets<T, F>(abs, options)\n }\n\n private abs(rel: string): string {\n const base = new URL(this.path, 'uri://void')\n const url = new URL(rel, base)\n\n if (!url.pathname.endsWith('/'))\n url.pathname += '/'\n\n return url.pathname + url.search\n }\n}\n\ninterface Options {\n agent: Agent\n path: string\n init?: Partial<RequestOptions>\n}\n\nexport { Resource }\n","/**\n *\n * @example\n * [10..20]\n * [10..20)\n * (10..20]\n * (10..20)\n */\nexport function test(value: string): boolean {\n return /^[[(]\\d+\\.\\.\\d+[\\])]{1}$/.test(value)\n}\n\nexport function format(name: string, value: string): string[] {\n const [min, max] = value.slice(1, -1).split('..')\n\n return [\n `${name}${value.startsWith('(') ? '>' : '>='}${min}`,\n `${name}${value.endsWith(')') ? '<' : '<='}${max}`,\n ]\n}\n","import * as range from './range'\nimport type { Format } from './Format'\n\nconst formats: Format[] = [range]\n\nexport { formats }\n","import { formats } from './criteria'\n\nfunction query(params?: URLSearchParams, options?: Options): string {\n if (params === undefined) return ''\n\n const parts: string[] = []\n const criteria: string[] = []\n\n for (const [key, value] of params.entries()) {\n const name = options?.map?.[key] ?? key\n\n if (SEPARATE.includes(name) || options?.separate?.includes(name) === true)\n parts.push(`${name}=${value}`)\n else {\n const format = formats.find((format) => format.test(value))\n\n if (format === undefined)\n criteria.push(`${name}==${value}`)\n else\n criteria.push(...format.format(name, value))\n }\n }\n\n if (criteria.length > 0)\n parts.unshift(`criteria=${criteria.join(';')}`)\n\n return parts.length === 0\n ? ''\n : '?' + parts.join('&')\n}\n\nconst SEPARATE: string[] = ['omit', 'limit', 'search'] as const\n\ninterface Options {\n separate?: string[]\n map?: Record<string, string>\n}\n\nexport { query }\n"],"mappings":"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","names":["mitt","fetch","mitt","fetch","format"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/origin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"husky": "^9.1.7",
|
|
43
43
|
"neostandard": "^0.12.2",
|
|
44
44
|
"semantic-release": "^24.2.9",
|
|
45
|
+
"ts-node": "^10.9.2",
|
|
45
46
|
"tsup": "^8.5.0"
|
|
46
47
|
},
|
|
47
48
|
"scripts": {
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
"prepublishOnly": "npm run build",
|
|
51
52
|
"lint": "eslint .",
|
|
52
53
|
"format": "eslint . --fix",
|
|
53
|
-
"test": "npm run lint &&
|
|
54
|
+
"test": "npm run lint && npx tsx --test",
|
|
54
55
|
"ci": "rm -rf node_modules && rm -rf package-lock.json && npm i"
|
|
55
56
|
},
|
|
56
57
|
"dependencies": {
|
package/source/Origin.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import mitt from 'mitt'
|
|
2
2
|
import { Agent } from './Agent'
|
|
3
3
|
import { Resource } from './Resource'
|
|
4
|
+
import type { RequestOptions } from './Agent'
|
|
4
5
|
import type { Events } from './Events'
|
|
5
6
|
import type { Emitter } from 'mitt'
|
|
6
7
|
|
|
@@ -18,10 +19,11 @@ class Origin {
|
|
|
18
19
|
})
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
public resource<T = unknown>(path: string) {
|
|
22
|
+
public resource<T = unknown>(path: string, init?: Partial<RequestOptions>) {
|
|
22
23
|
return new Resource<T>({
|
|
23
24
|
agent: this.agent,
|
|
24
25
|
path,
|
|
26
|
+
init,
|
|
25
27
|
})
|
|
26
28
|
}
|
|
27
29
|
|
package/source/Resource.ts
CHANGED
|
@@ -6,22 +6,26 @@ import type { Emitter } from 'mitt'
|
|
|
6
6
|
class Resource<T = unknown, E extends GenericError = GenericError> {
|
|
7
7
|
private readonly agent: Agent
|
|
8
8
|
private readonly path: string
|
|
9
|
+
private readonly init?: Partial<RequestOptions>
|
|
9
10
|
|
|
10
11
|
public constructor(options: Options) {
|
|
11
12
|
this.agent = options.agent
|
|
12
13
|
this.path = options.path
|
|
14
|
+
this.init = options.init
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
public async json<R = T, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<R | F> {
|
|
16
18
|
const abs = this.abs(rel)
|
|
19
|
+
const options = Object.assign({}, this.init, init)
|
|
17
20
|
|
|
18
|
-
return await this.agent.json<R, F>(abs,
|
|
21
|
+
return await this.agent.json<R, F>(abs, options)
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
public async octets<T extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string = '', init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<T>>] | F> {
|
|
22
25
|
const abs = this.abs(rel)
|
|
26
|
+
const options = Object.assign({}, this.init, init)
|
|
23
27
|
|
|
24
|
-
return await this.agent.octets<T, F>(abs,
|
|
28
|
+
return await this.agent.octets<T, F>(abs, options)
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
private abs(rel: string): string {
|
|
@@ -38,6 +42,7 @@ class Resource<T = unknown, E extends GenericError = GenericError> {
|
|
|
38
42
|
interface Options {
|
|
39
43
|
agent: Agent
|
|
40
44
|
path: string
|
|
45
|
+
init?: Partial<RequestOptions>
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
export { Resource }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @example
|
|
4
|
+
* [10..20]
|
|
5
|
+
* [10..20)
|
|
6
|
+
* (10..20]
|
|
7
|
+
* (10..20)
|
|
8
|
+
*/
|
|
9
|
+
export function test(value: string): boolean {
|
|
10
|
+
return /^[[(]\d+\.\.\d+[\])]{1}$/.test(value)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function format(name: string, value: string): string[] {
|
|
14
|
+
const [min, max] = value.slice(1, -1).split('..')
|
|
15
|
+
|
|
16
|
+
return [
|
|
17
|
+
`${name}${value.startsWith('(') ? '>' : '>='}${min}`,
|
|
18
|
+
`${name}${value.endsWith(')') ? '<' : '<='}${max}`,
|
|
19
|
+
]
|
|
20
|
+
}
|
package/source/index.ts
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { it } from 'node:test'
|
|
3
|
+
import { query } from './query'
|
|
4
|
+
|
|
5
|
+
it('should build criteria', () => {
|
|
6
|
+
const params = new URLSearchParams()
|
|
7
|
+
|
|
8
|
+
params.set('foo', 'bar')
|
|
9
|
+
params.set('baz', 'qux')
|
|
10
|
+
|
|
11
|
+
const result = query(params)
|
|
12
|
+
|
|
13
|
+
assert.equal(result, '?criteria=foo==bar;baz==qux')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('should build empty criteria', () => {
|
|
17
|
+
const params = new URLSearchParams()
|
|
18
|
+
|
|
19
|
+
const result = query(params)
|
|
20
|
+
|
|
21
|
+
assert.equal(result, '')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should separate known parameters', () => {
|
|
25
|
+
const params = new URLSearchParams()
|
|
26
|
+
|
|
27
|
+
params.set('foo', 'bar')
|
|
28
|
+
params.set('omit', '10')
|
|
29
|
+
params.set('limit', '20')
|
|
30
|
+
params.set('search', 'qux')
|
|
31
|
+
|
|
32
|
+
const result = query(params)
|
|
33
|
+
|
|
34
|
+
assert.equal(result, '?criteria=foo==bar&omit=10&limit=20&search=qux')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should separate specified parameters', () => {
|
|
38
|
+
const params = new URLSearchParams()
|
|
39
|
+
|
|
40
|
+
params.set('foo', 'bar')
|
|
41
|
+
params.set('baz', 'qux')
|
|
42
|
+
|
|
43
|
+
const result = query(params, { separate: ['baz'] })
|
|
44
|
+
|
|
45
|
+
assert.equal(result, '?criteria=foo==bar&baz=qux')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should map parameters', () => {
|
|
49
|
+
const params = new URLSearchParams()
|
|
50
|
+
|
|
51
|
+
params.set('foo', 'bar')
|
|
52
|
+
params.set('baz', 'baz')
|
|
53
|
+
params.set('quz', 'qux')
|
|
54
|
+
params.set('max', '10')
|
|
55
|
+
|
|
56
|
+
const result = query(params, { separate: ['qux'], map: { foo: 'bar', quz: 'qux', max: 'limit' } })
|
|
57
|
+
|
|
58
|
+
assert.equal(result, '?criteria=bar==bar;baz==baz&qux=qux&limit=10')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should parse ranges', () => {
|
|
62
|
+
const params = new URLSearchParams()
|
|
63
|
+
|
|
64
|
+
params.set('foo', '[10..20]')
|
|
65
|
+
params.set('bar', '[10..20)')
|
|
66
|
+
|
|
67
|
+
const result = query(params)
|
|
68
|
+
|
|
69
|
+
assert.equal(result, '?criteria=foo>=10;foo<=20;bar>=10;bar<20')
|
|
70
|
+
})
|
package/source/query.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { formats } from './criteria'
|
|
2
|
+
|
|
3
|
+
function query(params?: URLSearchParams, options?: Options): string {
|
|
4
|
+
if (params === undefined) return ''
|
|
5
|
+
|
|
6
|
+
const parts: string[] = []
|
|
7
|
+
const criteria: string[] = []
|
|
8
|
+
|
|
9
|
+
for (const [key, value] of params.entries()) {
|
|
10
|
+
const name = options?.map?.[key] ?? key
|
|
11
|
+
|
|
12
|
+
if (SEPARATE.includes(name) || options?.separate?.includes(name) === true)
|
|
13
|
+
parts.push(`${name}=${value}`)
|
|
14
|
+
else {
|
|
15
|
+
const format = formats.find((format) => format.test(value))
|
|
16
|
+
|
|
17
|
+
if (format === undefined)
|
|
18
|
+
criteria.push(`${name}==${value}`)
|
|
19
|
+
else
|
|
20
|
+
criteria.push(...format.format(name, value))
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (criteria.length > 0)
|
|
25
|
+
parts.unshift(`criteria=${criteria.join(';')}`)
|
|
26
|
+
|
|
27
|
+
return parts.length === 0
|
|
28
|
+
? ''
|
|
29
|
+
: '?' + parts.join('&')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const SEPARATE: string[] = ['omit', 'limit', 'search'] as const
|
|
33
|
+
|
|
34
|
+
interface Options {
|
|
35
|
+
separate?: string[]
|
|
36
|
+
map?: Record<string, string>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { query }
|