@toa.io/origin 1.14.0 → 1.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -73,9 +73,13 @@ var Agent = class {
73
73
  return new import_error_value.Err(response.status, await response.json());
74
74
  const generator = await (0, import_browser.meros)(response);
75
75
  const ack = await generator.next();
76
+ if (options.debug)
77
+ console.debug("Multipart ACK", { path, body: ack.value.body });
76
78
  if (JSON.parse(ack.value.body) !== "ACK") throw new Error("No ACK");
77
79
  return (async function* () {
78
80
  for await (const chunk of generator) {
81
+ if (options.debug)
82
+ console.debug("Multipart chunk", { path, body: chunk.body });
79
83
  const value = JSON.parse(chunk.body);
80
84
  if (value === "FIN") return;
81
85
  yield value;
@@ -89,8 +93,11 @@ var Agent = class {
89
93
  const entry = chunk.value;
90
94
  const emitter = (0, import_mitt.default)();
91
95
  void (async () => {
96
+ await new Promise((resolve) => setTimeout(resolve, 0));
92
97
  for await (const part of generator) {
93
98
  const payload = part.status === "completed" ? part.error ? new import_error_value.Err(part.error.code ?? "UNKNOWN", part.error.message) : part.output : new import_error_value.Err("EXCEPTION");
99
+ if (init?.debug)
100
+ console.debug("Emitting octets step", { path, step: part.step, payload });
94
101
  emitter.emit(part.step, payload);
95
102
  }
96
103
  emitter.off("*");
@@ -115,15 +122,16 @@ var Agent = class {
115
122
  init.headers["authorization"] = this.challenge;
116
123
  delete init.credentials;
117
124
  }
118
- if (init.body !== void 0)
125
+ if (init.body !== void 0) {
126
+ init.method ??= "POST";
119
127
  if (init.body instanceof File || init.body instanceof ReadableStream) {
120
- init.method ??= "POST";
121
128
  init.duplex = "half";
122
129
  init.headers["content-type"] ??= init.body.type ?? "application/octet-stream";
123
130
  } else {
124
131
  init.body = JSON.stringify(init.body);
125
132
  init.headers["content-type"] ??= "application/json";
126
133
  }
134
+ }
127
135
  return init;
128
136
  }
129
137
  async request(path, init) {
@@ -162,8 +170,6 @@ var Resource = class {
162
170
  init = typeof relOrInit === "string" ? init : relOrInit;
163
171
  const abs = this.abs(rel);
164
172
  const options = Object.assign({}, this.init, init);
165
- if (options.body !== void 0 && options.method === void 0)
166
- options.method = "POST";
167
173
  if (method === "json")
168
174
  return await this.agent.json(abs, options);
169
175
  else if (method === "octets")
@@ -1 +1 @@
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, type Origin } from './Origin'\nexport { query } from './query'\nexport type { GenericError } from './Error'\nexport type { OctetsEntry, WorkflowStep } from './Octets'\nexport type { Resource } from './Resource'\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 sleep: options.sleep,\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 | string) {\n if (typeof options === 'string')\n options = { origin: options }\n\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n sleep?: [number, number]\n}\n\ntype Fetch = typeof fetch\n\nexport { connect, type Origin }\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 sleep?: string\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 if (options.sleep !== undefined)\n this.sleep = JSON.stringify(options.sleep)\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 this.events.emit('response', { status: response.status, headers: response.headers })\n\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.error\n ? new Err(part.error.code ?? 'UNKNOWN', part.error.message)\n : part.output\n : new Err('EXCEPTION')\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 (this.sleep !== undefined)\n init.headers['sleep'] = this.sleep\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 sleep?: [number, number]\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>(init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(rel: string, init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F> {\n return await this.request<R, F>('json', relOrInit, init)\n }\n\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F> {\n return await this.request<R, F>('octets', relOrInit, init)\n }\n\n public async multipart<R = unknown, F extends E = E>(init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(rel: string, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F> {\n return await this.request<R, F>('multipart', relOrInit, init)\n }\n\n private async request<R, F extends E>(method: 'json', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F>\n private async request<R extends Record<string, unknown>, F extends E = E>(method: 'octets', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n private async request<R, F extends E = E>(method: 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n private async request<R extends T, F extends E = E>(method: 'json' | 'octets' | 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions) {\n const rel = typeof relOrInit === 'string' ? relOrInit : ''\n\n init = typeof relOrInit === 'string' ? init : relOrInit\n\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n if (options.body !== undefined && options.method === undefined)\n options.method = 'POST'\n\n if (method === 'json')\n return await this.agent.json<R, F>(abs, options)\n else if (method === 'octets')\n return await this.agent.octets<Record<string, unknown>, F>(abs, options)\n else if (method === 'multipart')\n return await this.agent.multipart<R>(abs, options)\n else throw new Error(`Invalid method: ${method}`)\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 // Allows to use resource.json(id) instead of resource.json(id + '/')\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"]}
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, type Origin } from './Origin'\nexport { query } from './query'\nexport type { GenericError } from './Error'\nexport type { OctetsEntry, WorkflowStep } from './Octets'\nexport type { Resource } from './Resource'\nexport type { RequestOptions } from './Agent'\nexport type { Faulty } from './Octets'\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 sleep: options.sleep,\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 | string) {\n if (typeof options === 'string')\n options = { origin: options }\n\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n sleep?: [number, number]\n}\n\ntype Fetch = typeof fetch\n\nexport { connect, type Origin }\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 sleep?: string\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 if (options.sleep !== undefined)\n this.sleep = JSON.stringify(options.sleep)\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 this.events.emit('response', { status: response.status, headers: response.headers })\n\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 (options.debug)\n console.debug('Multipart ACK', { path, body: ack.value.body })\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 if (options.debug)\n console.debug('Multipart chunk', { path, body: chunk.body })\n\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 // workflow results may come within the same frame\n await new Promise((resolve) => setTimeout(resolve, 0))\n\n for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {\n const payload =\n part.status === 'completed'\n ? part.error\n ? new Err(part.error.code ?? 'UNKNOWN', part.error.message)\n : part.output\n : new Err('EXCEPTION')\n\n if (init?.debug)\n console.debug('Emitting octets step', { path, step: part.step, payload })\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 (this.sleep !== undefined)\n init.headers['sleep'] = this.sleep\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 init.method ??= 'POST'\n\n if (init.body instanceof File || init.body instanceof ReadableStream) {\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\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 sleep?: [number, number]\n}\n\ninterface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {\n duplex?: 'half'\n body?: any\n headers?: Record<string, string>\n debug?: boolean\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>(init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(rel: string, init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F> {\n return await this.request<R, F>('json', relOrInit, init)\n }\n\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F> {\n return await this.request<R, F>('octets', relOrInit, init)\n }\n\n public async multipart<R = unknown, F extends E = E>(init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(rel: string, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F> {\n return await this.request<R, F>('multipart', relOrInit, init)\n }\n\n private async request<R, F extends E>(method: 'json', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F>\n private async request<R extends Record<string, unknown>, F extends E = E>(method: 'octets', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n private async request<R, F extends E = E>(method: 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n private async request<R extends T, F extends E = E>(method: 'json' | 'octets' | 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions) {\n const rel = typeof relOrInit === 'string' ? relOrInit : ''\n\n init = typeof relOrInit === 'string' ? init : relOrInit\n\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n if (method === 'json')\n return await this.agent.json<R, F>(abs, options)\n else if (method === 'octets')\n return await this.agent.octets<Record<string, unknown>, F>(abs, options)\n else if (method === 'multipart')\n return await this.agent.multipart<R>(abs, options)\n else throw new Error(`Invalid method: ${method}`)\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 // Allows to use resource.json(id) instead of resource.json(id + '/')\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
@@ -50,6 +50,7 @@ interface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {
50
50
  duplex?: 'half';
51
51
  body?: any;
52
52
  headers?: Record<string, string>;
53
+ debug?: boolean;
53
54
  }
54
55
  type Fetch$1 = typeof fetch;
55
56
 
@@ -95,4 +96,4 @@ interface Options {
95
96
  map?: Record<string, string>;
96
97
  }
97
98
 
98
- export { type GenericError, type OctetsEntry, Origin, type RequestOptions, Resource, type WorkflowStep, connect, query };
99
+ export { type Faulty, type GenericError, type OctetsEntry, Origin, type RequestOptions, Resource, type WorkflowStep, connect, query };
package/dist/index.d.ts CHANGED
@@ -50,6 +50,7 @@ interface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {
50
50
  duplex?: 'half';
51
51
  body?: any;
52
52
  headers?: Record<string, string>;
53
+ debug?: boolean;
53
54
  }
54
55
  type Fetch$1 = typeof fetch;
55
56
 
@@ -95,4 +96,4 @@ interface Options {
95
96
  map?: Record<string, string>;
96
97
  }
97
98
 
98
- export { type GenericError, type OctetsEntry, Origin, type RequestOptions, Resource, type WorkflowStep, connect, query };
99
+ export { type Faulty, type GenericError, type OctetsEntry, Origin, type RequestOptions, Resource, type WorkflowStep, connect, query };
package/dist/index.js CHANGED
@@ -42,9 +42,13 @@ var Agent = class {
42
42
  return new Err(response.status, await response.json());
43
43
  const generator = await meros(response);
44
44
  const ack = await generator.next();
45
+ if (options.debug)
46
+ console.debug("Multipart ACK", { path, body: ack.value.body });
45
47
  if (JSON.parse(ack.value.body) !== "ACK") throw new Error("No ACK");
46
48
  return (async function* () {
47
49
  for await (const chunk of generator) {
50
+ if (options.debug)
51
+ console.debug("Multipart chunk", { path, body: chunk.body });
48
52
  const value = JSON.parse(chunk.body);
49
53
  if (value === "FIN") return;
50
54
  yield value;
@@ -58,8 +62,11 @@ var Agent = class {
58
62
  const entry = chunk.value;
59
63
  const emitter = mitt();
60
64
  void (async () => {
65
+ await new Promise((resolve) => setTimeout(resolve, 0));
61
66
  for await (const part of generator) {
62
67
  const payload = part.status === "completed" ? part.error ? new Err(part.error.code ?? "UNKNOWN", part.error.message) : part.output : new Err("EXCEPTION");
68
+ if (init?.debug)
69
+ console.debug("Emitting octets step", { path, step: part.step, payload });
63
70
  emitter.emit(part.step, payload);
64
71
  }
65
72
  emitter.off("*");
@@ -84,15 +91,16 @@ var Agent = class {
84
91
  init.headers["authorization"] = this.challenge;
85
92
  delete init.credentials;
86
93
  }
87
- if (init.body !== void 0)
94
+ if (init.body !== void 0) {
95
+ init.method ??= "POST";
88
96
  if (init.body instanceof File || init.body instanceof ReadableStream) {
89
- init.method ??= "POST";
90
97
  init.duplex = "half";
91
98
  init.headers["content-type"] ??= init.body.type ?? "application/octet-stream";
92
99
  } else {
93
100
  init.body = JSON.stringify(init.body);
94
101
  init.headers["content-type"] ??= "application/json";
95
102
  }
103
+ }
96
104
  return init;
97
105
  }
98
106
  async request(path, init) {
@@ -131,8 +139,6 @@ var Resource = class {
131
139
  init = typeof relOrInit === "string" ? init : relOrInit;
132
140
  const abs = this.abs(rel);
133
141
  const options = Object.assign({}, this.init, init);
134
- if (options.body !== void 0 && options.method === void 0)
135
- options.method = "POST";
136
142
  if (method === "json")
137
143
  return await this.agent.json(abs, options);
138
144
  else if (method === "octets")
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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 sleep: options.sleep,\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 | string) {\n if (typeof options === 'string')\n options = { origin: options }\n\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n sleep?: [number, number]\n}\n\ntype Fetch = typeof fetch\n\nexport { connect, type Origin }\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 sleep?: string\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 if (options.sleep !== undefined)\n this.sleep = JSON.stringify(options.sleep)\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 this.events.emit('response', { status: response.status, headers: response.headers })\n\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.error\n ? new Err(part.error.code ?? 'UNKNOWN', part.error.message)\n : part.output\n : new Err('EXCEPTION')\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 (this.sleep !== undefined)\n init.headers['sleep'] = this.sleep\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 sleep?: [number, number]\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>(init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(rel: string, init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F> {\n return await this.request<R, F>('json', relOrInit, init)\n }\n\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F> {\n return await this.request<R, F>('octets', relOrInit, init)\n }\n\n public async multipart<R = unknown, F extends E = E>(init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(rel: string, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F> {\n return await this.request<R, F>('multipart', relOrInit, init)\n }\n\n private async request<R, F extends E>(method: 'json', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F>\n private async request<R extends Record<string, unknown>, F extends E = E>(method: 'octets', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n private async request<R, F extends E = E>(method: 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n private async request<R extends T, F extends E = E>(method: 'json' | 'octets' | 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions) {\n const rel = typeof relOrInit === 'string' ? relOrInit : ''\n\n init = typeof relOrInit === 'string' ? init : relOrInit\n\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n if (options.body !== undefined && options.method === undefined)\n options.method = 'POST'\n\n if (method === 'json')\n return await this.agent.json<R, F>(abs, options)\n else if (method === 'octets')\n return await this.agent.octets<Record<string, unknown>, F>(abs, options)\n else if (method === 'multipart')\n return await this.agent.multipart<R>(abs, options)\n else throw new Error(`Invalid method: ${method}`)\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 // Allows to use resource.json(id) instead of resource.json(id + '/')\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"]}
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 sleep: options.sleep,\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 | string) {\n if (typeof options === 'string')\n options = { origin: options }\n\n return new Origin(options)\n}\n\ninterface Options {\n origin: string\n sleep?: [number, number]\n}\n\ntype Fetch = typeof fetch\n\nexport { connect, type Origin }\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 sleep?: string\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 if (options.sleep !== undefined)\n this.sleep = JSON.stringify(options.sleep)\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 this.events.emit('response', { status: response.status, headers: response.headers })\n\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 (options.debug)\n console.debug('Multipart ACK', { path, body: ack.value.body })\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 if (options.debug)\n console.debug('Multipart chunk', { path, body: chunk.body })\n\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 // workflow results may come within the same frame\n await new Promise((resolve) => setTimeout(resolve, 0))\n\n for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {\n const payload =\n part.status === 'completed'\n ? part.error\n ? new Err(part.error.code ?? 'UNKNOWN', part.error.message)\n : part.output\n : new Err('EXCEPTION')\n\n if (init?.debug)\n console.debug('Emitting octets step', { path, step: part.step, payload })\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 (this.sleep !== undefined)\n init.headers['sleep'] = this.sleep\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 init.method ??= 'POST'\n\n if (init.body instanceof File || init.body instanceof ReadableStream) {\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\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 sleep?: [number, number]\n}\n\ninterface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {\n duplex?: 'half'\n body?: any\n headers?: Record<string, string>\n debug?: boolean\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>(init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(rel: string, init?: RequestOptions): Promise<R | F>\n public async json<R = T, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F> {\n return await this.request<R, F>('json', relOrInit, init)\n }\n\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(rel: string, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n public async octets<R extends Record<string, unknown> = Record<string, unknown>, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F> {\n return await this.request<R, F>('octets', relOrInit, init)\n }\n\n public async multipart<R = unknown, F extends E = E>(init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(rel: string, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n public async multipart<R = unknown, F extends E = E>(relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F> {\n return await this.request<R, F>('multipart', relOrInit, init)\n }\n\n private async request<R, F extends E>(method: 'json', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<R | F>\n private async request<R extends Record<string, unknown>, F extends E = E>(method: 'octets', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<[OctetsEntry, Emitter<Faulty<R>>] | F>\n private async request<R, F extends E = E>(method: 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions): Promise<AsyncGenerator<R, void, undefined> | F>\n private async request<R extends T, F extends E = E>(method: 'json' | 'octets' | 'multipart', relOrInit?: string | RequestOptions, init?: RequestOptions) {\n const rel = typeof relOrInit === 'string' ? relOrInit : ''\n\n init = typeof relOrInit === 'string' ? init : relOrInit\n\n const abs = this.abs(rel)\n const options = Object.assign({}, this.init, init)\n\n if (method === 'json')\n return await this.agent.json<R, F>(abs, options)\n else if (method === 'octets')\n return await this.agent.octets<Record<string, unknown>, F>(abs, options)\n else if (method === 'multipart')\n return await this.agent.multipart<R>(abs, options)\n else throw new Error(`Invalid method: ${method}`)\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 // Allows to use resource.json(id) instead of resource.json(id + '/')\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.14.0",
3
+ "version": "1.15.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/source/Agent.ts CHANGED
@@ -51,10 +51,16 @@ class Agent {
51
51
  const generator = await meros(response) as AsyncGenerator<{ body: string }>
52
52
  const ack = await generator.next()
53
53
 
54
+ if (options.debug)
55
+ console.debug('Multipart ACK', { path, body: ack.value.body })
56
+
54
57
  if (JSON.parse(ack.value.body) !== 'ACK') throw new Error('No ACK')
55
58
 
56
59
  return (async function * () {
57
60
  for await (const chunk of generator) {
61
+ if (options.debug)
62
+ console.debug('Multipart chunk', { path, body: chunk.body })
63
+
58
64
  const value = JSON.parse(chunk.body)
59
65
 
60
66
  if (value === 'FIN') return
@@ -77,6 +83,9 @@ class Agent {
77
83
  const emitter = mitt<Faulty<T>>()
78
84
 
79
85
  void (async () => {
86
+ // workflow results may come within the same frame
87
+ await new Promise((resolve) => setTimeout(resolve, 0))
88
+
80
89
  for await (const part of (generator as AsyncGenerator<WorkflowStep>)) {
81
90
  const payload =
82
91
  part.status === 'completed'
@@ -85,6 +94,9 @@ class Agent {
85
94
  : part.output
86
95
  : new Err('EXCEPTION')
87
96
 
97
+ if (init?.debug)
98
+ console.debug('Emitting octets step', { path, step: part.step, payload })
99
+
88
100
  emitter.emit(part.step, payload as T[typeof part.step])
89
101
  }
90
102
 
@@ -118,15 +130,17 @@ class Agent {
118
130
  delete init.credentials // no cookies
119
131
  }
120
132
 
121
- if (init.body !== undefined)
133
+ if (init.body !== undefined) {
134
+ init.method ??= 'POST'
135
+
122
136
  if (init.body instanceof File || init.body instanceof ReadableStream) {
123
- init.method ??= 'POST'
124
137
  init.duplex = 'half'
125
138
  init.headers['content-type'] ??= (init.body as File).type ?? 'application/octet-stream'
126
139
  } else {
127
140
  init.body = JSON.stringify(init.body)
128
141
  init.headers['content-type'] ??= 'application/json'
129
142
  }
143
+ }
130
144
 
131
145
  return init as InitWithHeaders
132
146
  }
@@ -156,6 +170,7 @@ interface RequestOptions extends Omit<RequestInit, 'path' | 'headers'> {
156
170
  duplex?: 'half'
157
171
  body?: any
158
172
  headers?: Record<string, string>
173
+ debug?: boolean
159
174
  }
160
175
 
161
176
  interface InitWithHeaders extends RequestOptions {
@@ -43,9 +43,6 @@ class Resource<T = unknown, E extends GenericError = GenericError> {
43
43
  const abs = this.abs(rel)
44
44
  const options = Object.assign({}, this.init, init)
45
45
 
46
- if (options.body !== undefined && options.method === undefined)
47
- options.method = 'POST'
48
-
49
46
  if (method === 'json')
50
47
  return await this.agent.json<R, F>(abs, options)
51
48
  else if (method === 'octets')
package/source/index.ts CHANGED
@@ -4,3 +4,4 @@ export type { GenericError } from './Error'
4
4
  export type { OctetsEntry, WorkflowStep } from './Octets'
5
5
  export type { Resource } from './Resource'
6
6
  export type { RequestOptions } from './Agent'
7
+ export type { Faulty } from './Octets'