New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@oasislabs/parcel

Package Overview
Dependencies
Maintainers
15
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@oasislabs/parcel - npm Package Compare versions

Comparing version 1.0.0-beta.8 to 1.0.0-beta.9

3

lib/app.d.ts

@@ -105,3 +105,4 @@ import type { Except, Opaque } from 'type-fest';

export declare const APPS_EP = "apps";
export declare const endpointForId: (id: AppId) => string;
declare const endpointForId: (id: AppId) => string;
export { endpointForId as endpointForApp };
export declare type AppCreateParams = Except<AppUpdateParams, 'owner'> & {

@@ -108,0 +109,0 @@ /** The credentials used to authorize clients acting as this app. */

@@ -109,3 +109,4 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {

export const APPS_EP = 'apps';
export const endpointForId = (id) => `${APPS_EP}/${id}`;
const endpointForId = (id) => `${APPS_EP}/${id}`;
export { endpointForId as endpointForApp };
//# sourceMappingURL=app.js.map

@@ -15,3 +15,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {

var _client;
import { endpointForId as endpointForApp } from './app.js';
import { endpointForApp } from './app.js';
export class Client {

@@ -18,0 +18,0 @@ constructor(client, pod) {

@@ -81,2 +81,13 @@ import type { Opaque } from 'type-fest';

outputDocuments?: OutputDocumentSpec[];
/**
* The (fractional) number of cpus requested to run the job. This is clamped by a per-worker
* maximum.
*/
cpus?: number;
/**
* The amount of memory requested to run the job. This is clamped by a per-worker
* maximum. Memory limit (format: <number>[<unit>]). Number is a positive integer.
* Unit can be one of M or G. Minimum is 4M.
*/
memory?: string;
};

@@ -83,0 +94,0 @@ export declare type JobStatus = {

@@ -15,2 +15,5 @@ import type { Primitive } from 'type-fest';

};
type DocumentOwner = {
'document.owner': RelationalOp<$IdentityId>;
};
type DocumentTitle = {

@@ -20,4 +23,5 @@ 'document.title': RelationalOp<string>;

type DocumentTags = {
'document.tags': ArrayOp<string>;
'document.tags': SetOp<string>;
};
type Document = DocumentId | DocumentCreator | DocumentOwner | DocumentTitle | DocumentTags;
type JobImage = {

@@ -32,2 +36,3 @@ 'job.spec.image': RelationalOp<string>;

};
type Job = JobImage | JobInputs | JobOutputs;
type AccessTime = {

@@ -43,3 +48,3 @@ accessTime: RelationalOp<string>;

}
export declare type Selector = Selectors.IdentityId | Selectors.DocumentId | Selectors.DocumentCreator | Selectors.DocumentTitle | Selectors.DocumentTags | Selectors.JobImage | Selectors.JobInputs | Selectors.JobOutputs | Selectors.AccessTime;
export declare type Selector = Selectors.IdentityId | Selectors.Document | Selectors.Job | Selectors.AccessTime;
export declare namespace LogicalOps {

@@ -59,3 +64,3 @@ type And = {

}
declare type LogicalOp = LogicalOps.And | LogicalOps.Or | LogicalOps.Nor | LogicalOps.Not;
export declare type LogicalOp = LogicalOps.And | LogicalOps.Or | LogicalOps.Nor | LogicalOps.Not;
export declare type Condition = Selector | LogicalOp;

@@ -101,4 +106,25 @@ export declare namespace RelationalOp {

}
declare type ArrayOp<T> = ArrayOps.Any<T> | ArrayOps.All<T> | ArrayOps.Len<T>;
export declare type ArrayOp<T> = ArrayOps.Any<T> | ArrayOps.All<T> | ArrayOps.Len<T>;
export declare namespace SetOps {
type Contains<T = Primitive> = {
$contains: T;
};
type Intersects<T = Primitive> = {
$intersects: T[];
};
type Superset<T = Primitive> = {
$superset: T[];
};
type Subset<T = Primitive> = {
$subset: T[];
};
type Values<T = Primitive> = {
$values: ArrayOp<T>;
};
type Len<T = Primitive> = {
$size: RelationalOp<T>;
};
}
export declare type SetOp<T> = SetOps.Contains<T> | SetOps.Intersects<T> | SetOps.Superset<T> | SetOps.Subset<T> | SetOps.Values<T> | SetOps.Len<T>;
export {};
//# sourceMappingURL=condition.d.ts.map

@@ -5,5 +5,6 @@ /// <reference types="node" />

import type { Readable } from 'readable-stream';
import type { Opaque, RequireExactlyOne, SetOptional } from 'type-fest';
import type { Opaque, SetOptional } from 'type-fest';
import type { AppId } from './app.js';
import type { JobId } from './compute.js';
import type { JobId, JobSpec } from './compute.js';
import type { Condition } from './condition.js';
import type { HttpClient, Download } from './http.js';

@@ -52,3 +53,3 @@ import type { IdentityId } from './identity.js';

function get(client: HttpClient, id: DocumentId): Promise<Document>;
function list(client: HttpClient, filter?: ListDocumentsFilter & PageParams): Promise<Page<Document>>;
function search(client: HttpClient, params?: DocumentSearchParams & PageParams): Promise<Page<Document>>;
function upload(client: HttpClient, data: Storable, params: DocumentUploadParams | undefined | null): Upload;

@@ -65,11 +66,78 @@ function download(client: HttpClient, id: DocumentId): Download;

export declare type Storable = Uint8Array | Readable | ReadStream | Blob | string;
export declare type ListDocumentsFilter = Partial<{
creator: IdentityId;
owner: IdentityId;
sharedWith: IdentityId;
tags: string[] | RequireExactlyOne<{
any: string[];
all: string[];
}>;
}>;
/**
* A very flexible document search interface.
*
* ## Examples:
*
* ### Search for documents you own
*
* ```
* {
* selectedByCondition: { 'document.owner': { $eq: (await parcel.getCurrentIdentity()).id } },
* }
* ```
*
* ### Search for documents shared with you
*
* ```
* let me = (await parcel.getCurrentIdentity()).id;
* {
* selectedByCondition: { 'document.owner': { $ne: me } },
* accessibleInContext: { accessor: me },
* }
* ```
*
* ### Search for documents with tags
*
* ```
* {
* selectedByCondition: {
* 'document.tags': { $intersects: ['csv', 'json'] }
* },
* }
* ```
*
*/
export declare type DocumentSearchParams = {
/**
* Searches for documents that would be selected if a grant with the
* specfified condition were created. Use this field for simulating a grant.
*
* If `accessibleInContext` is also specfified, this field selects documents
* both accessible in the context and selected by the condition (i.e. existing
* conditions apply).
*/
selectedByCondition?: Condition;
/**
* Searches for documents that can be accessed in the provided context.
* This field allows you to discover documents that you can access either
* yourself, or from a job.
*/
accessibleInContext?: AccessContext;
};
/**
* The context in which a document will be accessed.
* Grants condition on the values of this context.
*/
declare type AccessContext = {
/**
* The identity that will be accessing the document.
* Leaving this field unset will search for documents
* accessible to anybody (likely only in the context of a job).
*/
accessor?: IdentityId;
/**
* The job that will be accessing the data.
* Leaving this field unset will search for documents
* accessible directly by identities. If `identity` is
* also unset, the search will return public documents.
*/
job?: JobSpec;
/**
* The time at which the data will be accessed.
* Generally, you don't need to set this unless you're differentiating
* among multple documents that all require a certain access time.
*/
accessTime?: Date;
};
export declare type AccessEvent = {

@@ -76,0 +144,0 @@ createdAt: Date;

@@ -17,2 +17,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {

import FormData from 'form-data';
import { setExpectedStatus } from './http.js';
import { makePage } from './model.js';

@@ -58,18 +59,11 @@ export class Document {

DocumentImpl.get = get;
async function list(client, filter) {
var _a;
let tagsFilter;
if (filter === null || filter === void 0 ? void 0 : filter.tags) {
const tagsSpec = filter.tags;
const prefix = Array.isArray(tagsSpec) || tagsSpec.all ? 'all' : 'any';
const tags = Array.isArray(tagsSpec) ? tagsSpec : (_a = tagsSpec.all) !== null && _a !== void 0 ? _a : tagsSpec.any;
tagsFilter = `${prefix}:${tags.join(',')}`;
}
const podPage = await client.get(DOCUMENTS_EP, {
...filter,
tags: tagsFilter,
async function search(client, params) {
const podPage = await client.post(`${DOCUMENTS_EP}/search`, params, {
hooks: {
beforeRequest: [setExpectedStatus(200)],
},
});
return makePage(Document, podPage, client);
}
DocumentImpl.list = list;
DocumentImpl.search = search;
function upload(client, data, params) {

@@ -145,3 +139,3 @@ return new Upload(client, data, params !== null && params !== void 0 ? params : undefined);

else if ('pipe' in data) {
throw new TypeError('uploaded data must be a `string`, `Blob`, or `Uint8Array`');
throw new TypeError('uploaded data must of type `Storable`');
}

@@ -148,0 +142,0 @@ form.append(name, data);

@@ -7,3 +7,3 @@ /// <reference types="node" />

import type { Writable } from 'stream';
import type { JsonObject } from 'type-fest';
import type { JsonSerializable } from './model.js';
import type { TokenProvider } from './token.js';

@@ -21,9 +21,37 @@ export declare type Config = Partial<{

/** Convenience method for POSTing and expecting a 201 response */
create<T>(endpoint: string, data: JsonObject | FormData, requestOptions?: KyOptions): Promise<T>;
post<T>(endpoint: string, data: JsonObject | FormData | undefined, requestOptions?: KyOptions): Promise<T>;
update<T>(endpoint: string, params: JsonObject): Promise<T>;
put<T>(endpoint: string, params: JsonObject): Promise<T>;
create<T>(endpoint: string, data: Record<string, JsonSerializable> | FormData, requestOptions?: KyOptions): Promise<T>;
post<T>(endpoint: string, data: Record<string, JsonSerializable> | FormData | undefined, requestOptions?: KyOptions): Promise<T>;
update<T>(endpoint: string, params: Record<string, JsonSerializable>): Promise<T>;
put<T>(endpoint: string, params: Record<string, JsonSerializable>): Promise<T>;
delete(endpoint: string): Promise<void>;
download(endpoint: string): Download;
}
declare module 'ky' {
type Response = Readonly<globalThis.Response>;
}
/**
* Workaround to fix `afterResponse` breaking >20MB file downloads.
*
* Ky clones the response when using afterResponse. Cloning causes requests to
* stop requesting data after 2x highWaterMark (we use 10 MB) unless all clones
* consume data at the same time. This workaround uses beforeRequest hook to
* skip ky's fetch call + afterResponse handling, and reimplements both.
*
* WARNING: Use caution if modifying response.json or response.body in hooks. In
* vanilla ky every hook receives its own clone of the response; with this
* workaround, the same response object is passed to all hooks, so changes
* propagate (somewhat mitigated by readonly fields on Response). In addition,
* response.body can only be read once.
*
* Related issues:
* - https://github.com/node-fetch/node-fetch#custom-highwatermark
* - https://github.com/sindresorhus/ky-universal/issues/8
* - https://github.com/sindresorhus/ky/issues/135
* - https://github.com/node-fetch/node-fetch/issues/386
*
* TODO: remove if fixed by https://github.com/sindresorhus/ky/pull/356
*/
export declare function dontCloneForAfterResponses(): BeforeRequestHook;
/** Attaches a hook to end of hooks.beforeRequest (incl. after one-off hooks specified in the call to fetch(), e.g. setExpectedStatus) */
export declare function appendAsLastBeforeRequest(hookToSchedule: BeforeRequestHook): BeforeRequestHook;
export declare function setExpectedStatus(status: number): BeforeRequestHook;

@@ -30,0 +58,0 @@ /**

@@ -30,2 +30,3 @@ var _a, _b, _c;

beforeRequest: [
appendAsLastBeforeRequest(dontCloneForAfterResponses()),
async (req) => {

@@ -55,3 +56,3 @@ req.headers.set('authorization', `Bearer ${await this.tokenProvider.getToken()}`);

const endpoint = res.url.replace(this.apiUrl, '');
throw new ApiError(req, opts, res, `${req.method} ${endpoint} returned unexpected status ${expectedStatus}. expected: ${res.status}.`);
throw new ApiError(req, opts, res, `${req.method} ${endpoint} returned unexpected status ${res.status}. expected: ${expectedStatus}.`);
}

@@ -72,8 +73,7 @@ },

}
return this.apiKy
.get(endpoint, {
const response = await this.apiKy.get(endpoint, {
searchParams: hasParams ? kebabCaseParams : undefined,
...requestOptions,
})
.json();
});
return response.json();
}

@@ -95,3 +95,3 @@ /** Convenience method for POSTing and expecting a 201 response */

}
return this.apiKy.post(endpoint, opts).json();
return (await this.apiKy.post(endpoint, opts)).json();
}

@@ -102,3 +102,3 @@ async update(endpoint, params) {

async put(endpoint, params) {
return this.apiKy.put(endpoint, { json: params }).json();
return (await this.apiKy.put(endpoint, { json: params })).json();
}

@@ -112,2 +112,52 @@ async delete(endpoint) {

}
/**
* Workaround to fix `afterResponse` breaking >20MB file downloads.
*
* Ky clones the response when using afterResponse. Cloning causes requests to
* stop requesting data after 2x highWaterMark (we use 10 MB) unless all clones
* consume data at the same time. This workaround uses beforeRequest hook to
* skip ky's fetch call + afterResponse handling, and reimplements both.
*
* WARNING: Use caution if modifying response.json or response.body in hooks. In
* vanilla ky every hook receives its own clone of the response; with this
* workaround, the same response object is passed to all hooks, so changes
* propagate (somewhat mitigated by readonly fields on Response). In addition,
* response.body can only be read once.
*
* Related issues:
* - https://github.com/node-fetch/node-fetch#custom-highwatermark
* - https://github.com/sindresorhus/ky-universal/issues/8
* - https://github.com/sindresorhus/ky/issues/135
* - https://github.com/node-fetch/node-fetch/issues/386
*
* TODO: remove if fixed by https://github.com/sindresorhus/ky/pull/356
*/
export function dontCloneForAfterResponses() {
return async (req, opts) => {
var _a, _b;
if (!((_b = (_a = opts.hooks) === null || _a === void 0 ? void 0 : _a.afterResponse) === null || _b === void 0 ? void 0 : _b.length))
return;
const { afterResponse } = opts.hooks;
opts.hooks.afterResponse = [];
let response = await opts.fetch(req.clone());
// https://github.com/sindresorhus/ky/blob/5f3c3158af5c7efbb6a1cfd9e5f16fc71dd26e36/source/core/Ky.ts#L112-L123
for (const hook of afterResponse) {
const modifiedResponse = await hook(req, opts, response);
if (modifiedResponse instanceof globalThis.Response) {
response = modifiedResponse;
}
}
return response;
};
}
/** Attaches a hook to end of hooks.beforeRequest (incl. after one-off hooks specified in the call to fetch(), e.g. setExpectedStatus) */
export function appendAsLastBeforeRequest(hookToSchedule) {
return (req, opts) => {
if (!opts.hooks)
opts.hooks = {};
if (!opts.hooks.beforeRequest)
opts.hooks.beforeRequest = [];
opts.hooks.beforeRequest.push(hookToSchedule);
};
}
/** A beforeRequest hook that attaches context to the Request, for displaying in errors. */

@@ -114,0 +164,0 @@ function attachContext(context) {

@@ -10,4 +10,5 @@ /**

import type { Job, JobId, JobSpec, JobStatus, JobStatusReport } from './compute.js';
import type { Condition } from './condition.js';
import { InputDocumentSpec, JobPhase, ListJobsFilter, OutputDocument, OutputDocumentSpec } from './compute.js';
import type { AccessEvent, Document, DocumentId, DocumentUpdateParams, DocumentUploadParams, ListAccessLogFilter, ListDocumentsFilter, Storable, Upload } from './document.js';
import type { AccessEvent, Document, DocumentId, DocumentUpdateParams, DocumentUploadParams, ListAccessLogFilter, DocumentSearchParams, Storable, Upload } from './document.js';
import type { Grant, GrantCreateParams, GrantId } from './grant.js';

@@ -22,3 +23,3 @@ import { Capabilities, ListGrantsFilter } from './grant.js';

import { PARCEL_RUNTIME_AUD } from './token.js';
export { AccessEvent, ApiError, App, AppCreateParams, AppId, AppUpdateParams, Capabilities, Client, ClientCreateParams, ClientCredentials, ClientId, Document, DocumentId, DocumentUpdateParams, DocumentUploadParams, Download, Grant, GrantCreateParams, GrantId, GrantedPermission, Identity, IdentityCreateParams, IdentityId, IdentityUpdateParams, InputDocumentSpec, Job, JobId, JobPhase, JobSpec, JobStatus, JobStatusReport, OutputDocument, OutputDocumentSpec, PARCEL_RUNTIME_AUD, Page, PageParams, Permission, PermissionCreateParams, PermissionId, PrivateJWK, PublicJWK, RefreshingTokenProviderParams, RenewingTokenProviderParams, Scope, SelfIssuedTokenProviderParams, Storable, TokenSource, };
export { AccessEvent, ApiError, App, AppCreateParams, AppId, AppUpdateParams, Capabilities, Client, ClientCreateParams, ClientCredentials, ClientId, Condition, Document, DocumentId, DocumentUpdateParams, DocumentUploadParams, Download, Grant, GrantCreateParams, GrantId, GrantedPermission, Identity, IdentityCreateParams, IdentityId, IdentityUpdateParams, InputDocumentSpec, Job, JobId, JobPhase, JobSpec, JobStatus, JobStatusReport, OutputDocument, OutputDocumentSpec, PARCEL_RUNTIME_AUD, Page, PageParams, Permission, PermissionCreateParams, PermissionId, PrivateJWK, PublicJWK, RefreshingTokenProviderParams, RenewingTokenProviderParams, Scope, SelfIssuedTokenProviderParams, Storable, TokenSource, };
/**

@@ -32,3 +33,3 @@ * Example:

* });
* console.log(await parcel.listDocuments());
* console.log(await parcel.searchDocuments());
* ```

@@ -47,3 +48,3 @@ *

getDocument(id: DocumentId): Promise<Document>;
listDocuments(filter?: ListDocumentsFilter & PageParams): Promise<Page<Document>>;
searchDocuments(params?: DocumentSearchParams & PageParams): Promise<Page<Document>>;
downloadDocument(id: DocumentId): Download;

@@ -50,0 +51,0 @@ getDocumentHistory(id: DocumentId, filter?: ListAccessLogFilter & PageParams): Promise<Page<AccessEvent>>;

@@ -19,3 +19,3 @@ import { AppImpl } from './app.js';

* });
* console.log(await parcel.listDocuments());
* console.log(await parcel.searchDocuments());
* ```

@@ -51,4 +51,4 @@ *

}
async listDocuments(filter) {
return DocumentImpl.list(this.client, filter);
async searchDocuments(params) {
return DocumentImpl.search(this.client, params);
}

@@ -55,0 +55,0 @@ downloadDocument(id) {

@@ -1,4 +0,7 @@

import type { ConditionalExcept, Except, JsonValue } from 'type-fest';
import type { ConditionalExcept, Except } from 'type-fest';
import type { HttpClient } from './http.js';
export declare type ResourceId = string;
export declare type JsonSerializable = Date | string | number | boolean | null | undefined | JsonSerializable[] | {
[key in string]: JsonSerializable;
};
export interface PODModel {

@@ -18,3 +21,3 @@ /** An undifferentiated model identifier. */

export declare type WritableExcluding<T extends Model, ReadOnly extends keyof T> = ConditionalExcept<Except<T, 'id' | 'createdAt' | ReadOnly>, (...args: any[]) => any>;
export declare type Page<T = JsonValue> = {
export declare type Page<T> = {
results: T[];

@@ -21,0 +24,0 @@ nextPageToken: string;

@@ -9,3 +9,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {

var _client;
import { endpointForId as endpointForApp } from './app.js';
import { endpointForApp } from './app.js';
import { makePage } from './model.js';

@@ -12,0 +12,0 @@ export class Permission {

var _a, _b;
import { appendAsLastBeforeRequest, dontCloneForAfterResponses } from './http.js';
import jsrsasign from 'jsrsasign';

@@ -18,2 +19,3 @@ import ky from 'ky';

hooks: {
beforeRequest: [appendAsLastBeforeRequest(dontCloneForAfterResponses())],
afterResponse: [

@@ -166,3 +168,3 @@ async (req, opts, res) => {

const requestTime = Date.now();
const body = await response.json();
const body = await (await response).json();
return new Token(body.access_token, requestTime + body.expires_in * 1000);

@@ -169,0 +171,0 @@ }

{
"name": "@oasislabs/parcel",
"version": "1.0.0-beta.8",
"version": "1.0.0-beta.9",
"license": "Apache-2.0",

@@ -21,6 +21,9 @@ "author": "Oasis Labs <feedback@oasislabs.com>",

"fmt": "xo --fix && prettier --write {tsconfig,package}.json",
"lint": "xo && prettier --check {tsconfig,package}.json",
"lint": "xo && prettier --check {tsconfig,package}.json && tools/update-examples-parcel-version.sh --check",
"test": "jest",
"test:unit": "jest test/jest/unit/",
"test:examples": "jest test/examples/",
"test:integration-jest": "jest test/jest/integration/",
"test:cy": "start-test 'parcel serve test/cypress/fixtures/index.html -p 4444' 4444 'cypress run'",
"coverage": "jest --coverage test/unit && yarn test:cy",
"coverage": "yarn test:unit --coverage && yarn test:cy",
"doc": "typedoc --options docs/typedoc.json",

@@ -70,6 +73,7 @@ "prepublishOnly": "yarn build"

"@types/node": "^14.0.20",
"@types/node-jose": "^1.1.6",
"ajv": "^7.0.0",
"ajv-formats": "^1.5.1",
"bs58": "^4.0.1",
"cypress": "^6.0.0",
"cypress": "7.3.0",
"esbuild": "^0.11.16",

@@ -82,2 +86,3 @@ "eslint-config-xo-typescript": "^0.38.0",

"nock": "^13.0.4",
"node-jose": "^2.0.0",
"openapi-types": "^7.0.1",

@@ -84,0 +89,0 @@ "parcel-bundler": "^1.12.4",

@@ -13,4 +13,4 @@ # @oasislabs/parcel

[examples]: https://github.com/oasislabs/parcel-examples/tree/latest
[tutorial]: https://docs.oasislabs.com/latest/
[generated TypeDoc]: https://docs.oasislabs.com/latest/typedoc/
[OpenAPI spec]: https://docs.oasislabs.com/latest/parcel-api.html
[tutorial]: https://docs.oasislabs.com/parcel/latest
[generated TypeDoc]: https://docs.oasislabs.com/parcel/latest/typedoc/
[OpenAPI spec]: https://docs.oasislabs.com/parcel/latest/parcel-api.html

@@ -193,3 +193,4 @@ import type { Except, Opaque } from 'type-fest';

export const APPS_EP = 'apps';
export const endpointForId = (id: AppId) => `${APPS_EP}/${id}`;
const endpointForId = (id: AppId) => `${APPS_EP}/${id}`;
export { endpointForId as endpointForApp };

@@ -196,0 +197,0 @@ export type AppCreateParams = Except<AppUpdateParams, 'owner'> & {

import type { Except, Opaque } from 'type-fest';
import type { AppId } from './app.js';
import { endpointForId as endpointForApp } from './app.js';
import { endpointForApp } from './app.js';
import type { HttpClient } from './http.js';

@@ -6,0 +6,0 @@ import type { IdentityId } from './identity.js';

@@ -93,2 +93,15 @@ import type { Opaque } from 'type-fest';

outputDocuments?: OutputDocumentSpec[];
/**
* The (fractional) number of cpus requested to run the job. This is clamped by a per-worker
* maximum.
*/
cpus?: number;
/**
* The amount of memory requested to run the job. This is clamped by a per-worker
* maximum. Memory limit (format: <number>[<unit>]). Number is a positive integer.
* Unit can be one of M or G. Minimum is 4M.
*/
memory?: string;
};

@@ -95,0 +108,0 @@

@@ -16,2 +16,3 @@ import type { Primitive } from 'type-fest';

};
// Resource-based selectors.

@@ -24,2 +25,5 @@ export type DocumentId = {

};
export type DocumentOwner = {
'document.owner': RelationalOp<$IdentityId>;
};
export type DocumentTitle = {

@@ -29,4 +33,11 @@ 'document.title': RelationalOp<string>;

export type DocumentTags = {
'document.tags': ArrayOp<string>;
'document.tags': SetOp<string>;
};
export type Document =
| DocumentId
| DocumentCreator
| DocumentOwner
| DocumentTitle
| DocumentTags;
// Action-based selectors.

@@ -42,2 +53,4 @@ export type JobImage = {

};
export type Job = JobImage | JobInputs | JobOutputs;
export type AccessTime = {

@@ -57,9 +70,4 @@ accessTime: RelationalOp<string>; // TODO: This should be a Date, but Date is not currently serializable as a JsonObject.

| Selectors.IdentityId
| Selectors.DocumentId
| Selectors.DocumentCreator
| Selectors.DocumentTitle
| Selectors.DocumentTags
| Selectors.JobImage
| Selectors.JobInputs
| Selectors.JobOutputs
| Selectors.Document
| Selectors.Job
| Selectors.AccessTime;

@@ -83,3 +91,3 @@

// A LogicalOp is an internal node in the boolean expression tree for a condition.
type LogicalOp = LogicalOps.And | LogicalOps.Or | LogicalOps.Nor | LogicalOps.Not;
export type LogicalOp = LogicalOps.And | LogicalOps.Or | LogicalOps.Nor | LogicalOps.Not;

@@ -133,3 +141,2 @@ export type Condition = Selector | LogicalOp;

// Array operators enabled by the conditions DSL.
export namespace ArrayOps {

@@ -148,2 +155,35 @@ export type Any<T = Primitive> = {

}
type ArrayOp<T> = ArrayOps.Any<T> | ArrayOps.All<T> | ArrayOps.Len<T>;
export type ArrayOp<T> = ArrayOps.Any<T> | ArrayOps.All<T> | ArrayOps.Len<T>;
export namespace SetOps {
export type Contains<T = Primitive> = {
$contains: T;
};
export type Intersects<T = Primitive> = {
$intersects: T[];
};
export type Superset<T = Primitive> = {
$superset: T[];
};
export type Subset<T = Primitive> = {
$subset: T[];
};
export type Values<T = Primitive> = {
$values: ArrayOp<T>;
};
export type Len<T = Primitive> = {
$size: RelationalOp<T>;
};
}
export type SetOp<T> =
| SetOps.Contains<T>
| SetOps.Intersects<T>
| SetOps.Superset<T>
| SetOps.Subset<T>
| SetOps.Values<T>
| SetOps.Len<T>;

@@ -6,7 +6,9 @@ import type { ReadStream } from 'fs';

import type { Readable } from 'readable-stream';
import type { Opaque, RequireExactlyOne, SetOptional } from 'type-fest';
import type { Opaque, SetOptional } from 'type-fest';
import type { AppId } from './app.js';
import type { JobId } from './compute.js';
import type { JobId, JobSpec } from './compute.js';
import type { Condition } from './condition.js';
import type { HttpClient, Download } from './http.js';
import { setExpectedStatus } from './http.js';
import type { IdentityId } from './identity.js';

@@ -89,17 +91,10 @@ import type { Model, Page, PageParams, PODModel, ResourceId, WritableExcluding } from './model.js';

export async function list(
export async function search(
client: HttpClient,
filter?: ListDocumentsFilter & PageParams,
params?: DocumentSearchParams & PageParams,
): Promise<Page<Document>> {
let tagsFilter;
if (filter?.tags) {
const tagsSpec = filter.tags;
const prefix = Array.isArray(tagsSpec) || tagsSpec.all ? 'all' : 'any';
const tags = Array.isArray(tagsSpec) ? tagsSpec : tagsSpec.all ?? tagsSpec.any;
tagsFilter = `${prefix}:${tags.join(',')}`;
}
const podPage = await client.get<Page<PODDocument>>(DOCUMENTS_EP, {
...filter,
tags: tagsFilter,
const podPage = await client.post<Page<PODDocument>>(`${DOCUMENTS_EP}/search`, params, {
hooks: {
beforeRequest: [setExpectedStatus(200)],
},
});

@@ -174,14 +169,88 @@ return makePage(Document, podPage, client);

export type ListDocumentsFilter = Partial<{
creator: IdentityId;
owner: IdentityId;
sharedWith: IdentityId;
tags:
| string[]
| RequireExactlyOne<{
any: string[];
all: string[];
}>;
}>;
/**
* A very flexible document search interface.
*
* ## Examples:
*
* ### Search for documents you own
*
* ```
* {
* selectedByCondition: { 'document.owner': { $eq: (await parcel.getCurrentIdentity()).id } },
* }
* ```
*
* ### Search for documents shared with you
*
* ```
* let me = (await parcel.getCurrentIdentity()).id;
* {
* selectedByCondition: { 'document.owner': { $ne: me } },
* accessibleInContext: { accessor: me },
* }
* ```
*
* ### Search for documents with tags
*
* ```
* {
* selectedByCondition: {
* 'document.tags': { $intersects: ['csv', 'json'] }
* },
* }
* ```
*
*/
export type DocumentSearchParams = {
/**
* Searches for documents that would be selected if a grant with the
* specfified condition were created. Use this field for simulating a grant.
*
* If `accessibleInContext` is also specfified, this field selects documents
* both accessible in the context and selected by the condition (i.e. existing
* conditions apply).
*/
selectedByCondition?: Condition;
/**
* Searches for documents that can be accessed in the provided context.
* This field allows you to discover documents that you can access either
* yourself, or from a job.
*/
accessibleInContext?: AccessContext;
};
/**
* The context in which a document will be accessed.
* Grants condition on the values of this context.
*/
type AccessContext = {
/**
* The identity that will be accessing the document.
* Leaving this field unset will search for documents
* accessible to anybody (likely only in the context of a job).
*/
accessor?: IdentityId;
/**
* The job that will be accessing the data.
* Leaving this field unset will search for documents
* accessible directly by identities. If `identity` is
* also unset, the search will return public documents.
*/
job?: JobSpec;
/**
* The time at which the data will be accessed.
* Generally, you don't need to set this unless you're differentiating
* among multple documents that all require a certain access time.
*/
accessTime?: Date;
// /**
// * The kind of worker that you must use to run the job.
// */
// worker: WorkerSpec; // TODO
};
export type AccessEvent = {

@@ -229,3 +298,3 @@ createdAt: Date;

} else if ('pipe' in data) {
throw new TypeError('uploaded data must be a `string`, `Blob`, or `Uint8Array`');
throw new TypeError('uploaded data must of type `Storable`');
}

@@ -232,0 +301,0 @@

@@ -9,4 +9,4 @@ import type { WriteStream } from 'fs';

import type { Readable, Writable } from 'stream';
import type { JsonObject } from 'type-fest';
import type { JsonSerializable } from './model.js';
import type { TokenProvider } from './token.js';

@@ -50,2 +50,3 @@ import { ReadableStreamPF } from './polyfill.js';

beforeRequest: [
appendAsLastBeforeRequest(dontCloneForAfterResponses()),
async (req) => {

@@ -88,3 +89,3 @@ req.headers.set('authorization', `Bearer ${await this.tokenProvider.getToken()}`);

res,
`${req.method} ${endpoint} returned unexpected status ${expectedStatus}. expected: ${res.status}.`,
`${req.method} ${endpoint} returned unexpected status ${res.status}. expected: ${expectedStatus}.`,
);

@@ -112,8 +113,7 @@ }

return this.apiKy
.get(endpoint, {
searchParams: hasParams ? kebabCaseParams : undefined,
...requestOptions,
})
.json();
const response = await this.apiKy.get(endpoint, {
searchParams: hasParams ? kebabCaseParams : undefined,
...requestOptions,
});
return response.json();
}

@@ -124,3 +124,3 @@

endpoint: string,
data: JsonObject | FormData,
data: Record<string, JsonSerializable> | FormData,
requestOptions?: KyOptions,

@@ -133,3 +133,3 @@ ): Promise<T> {

endpoint: string,
data: JsonObject | FormData | undefined,
data: Record<string, JsonSerializable> | FormData | undefined,
requestOptions?: KyOptions,

@@ -149,11 +149,11 @@ ): Promise<T> {

return this.apiKy.post(endpoint, opts).json();
return (await this.apiKy.post(endpoint, opts)).json();
}
public async update<T>(endpoint: string, params: JsonObject): Promise<T> {
public async update<T>(endpoint: string, params: Record<string, JsonSerializable>): Promise<T> {
return this.put(endpoint, params);
}
public async put<T>(endpoint: string, params: JsonObject): Promise<T> {
return this.apiKy.put(endpoint, { json: params }).json();
public async put<T>(endpoint: string, params: Record<string, JsonSerializable>): Promise<T> {
return (await this.apiKy.put(endpoint, { json: params })).json();
}

@@ -170,2 +170,59 @@

declare module 'ky' {
// Mark methods readonly too to prevent hooks from modifying `response`
export type Response = Readonly<globalThis.Response>;
}
/**
* Workaround to fix `afterResponse` breaking >20MB file downloads.
*
* Ky clones the response when using afterResponse. Cloning causes requests to
* stop requesting data after 2x highWaterMark (we use 10 MB) unless all clones
* consume data at the same time. This workaround uses beforeRequest hook to
* skip ky's fetch call + afterResponse handling, and reimplements both.
*
* WARNING: Use caution if modifying response.json or response.body in hooks. In
* vanilla ky every hook receives its own clone of the response; with this
* workaround, the same response object is passed to all hooks, so changes
* propagate (somewhat mitigated by readonly fields on Response). In addition,
* response.body can only be read once.
*
* Related issues:
* - https://github.com/node-fetch/node-fetch#custom-highwatermark
* - https://github.com/sindresorhus/ky-universal/issues/8
* - https://github.com/sindresorhus/ky/issues/135
* - https://github.com/node-fetch/node-fetch/issues/386
*
* TODO: remove if fixed by https://github.com/sindresorhus/ky/pull/356
*/
export function dontCloneForAfterResponses(): BeforeRequestHook {
return async (req, opts: NormalizedOptions & KyOptions) => {
if (!opts.hooks?.afterResponse?.length) return;
const { afterResponse } = opts.hooks;
opts.hooks.afterResponse = [];
let response = await opts.fetch!(req.clone());
// https://github.com/sindresorhus/ky/blob/5f3c3158af5c7efbb6a1cfd9e5f16fc71dd26e36/source/core/Ky.ts#L112-L123
for (const hook of afterResponse) {
const modifiedResponse = await hook(req, opts, response);
if (modifiedResponse instanceof globalThis.Response) {
response = modifiedResponse;
}
}
return response;
};
}
/** Attaches a hook to end of hooks.beforeRequest (incl. after one-off hooks specified in the call to fetch(), e.g. setExpectedStatus) */
export function appendAsLastBeforeRequest(hookToSchedule: BeforeRequestHook): BeforeRequestHook {
return (req, opts: NormalizedOptions & KyOptions) => {
if (!opts.hooks) opts.hooks = {};
if (!opts.hooks.beforeRequest) opts.hooks.beforeRequest = [];
opts.hooks.beforeRequest.push(hookToSchedule);
};
}
/** A beforeRequest hook that attaches context to the Request, for displaying in errors. */

@@ -207,3 +264,3 @@ function attachContext(context: string): BeforeRequestHook {

// https://github.com/node-fetch/node-fetch/issues/930
const bodyReadable = (body as any) as Readable;
const bodyReadable = body as any as Readable;
yield* bodyReadable;

@@ -210,0 +267,0 @@ } else {

@@ -17,2 +17,3 @@ /**

import type { Job, JobId, JobSpec, JobStatus, JobStatusReport } from './compute.js';
import type { Condition } from './condition.js';
import {

@@ -34,3 +35,3 @@ ComputeImpl,

ListAccessLogFilter,
ListDocumentsFilter,
DocumentSearchParams,
Storable,

@@ -79,2 +80,3 @@ Upload,

ClientId,
Condition,
Document,

@@ -126,3 +128,3 @@ DocumentId,

* });
* console.log(await parcel.listDocuments());
* console.log(await parcel.searchDocuments());
* ```

@@ -168,4 +170,6 @@ *

public async listDocuments(filter?: ListDocumentsFilter & PageParams): Promise<Page<Document>> {
return DocumentImpl.list(this.client, filter);
public async searchDocuments(
params?: DocumentSearchParams & PageParams,
): Promise<Page<Document>> {
return DocumentImpl.search(this.client, params);
}

@@ -172,0 +176,0 @@

@@ -1,2 +0,2 @@

import type { ConditionalExcept, Except, JsonValue } from 'type-fest';
import type { ConditionalExcept, Except } from 'type-fest';

@@ -7,2 +7,12 @@ import type { HttpClient } from './http.js';

export type JsonSerializable =
| Date
| string
| number
| boolean
| null
| undefined
| JsonSerializable[]
| { [key in string]: JsonSerializable };
export interface PODModel {

@@ -30,3 +40,3 @@ /** An undifferentiated model identifier. */

export type Page<T = JsonValue> = {
export type Page<T> = {
results: T[];

@@ -33,0 +43,0 @@ nextPageToken: string;

import type { Opaque } from 'type-fest';
import type { AppId } from './app.js';
import { endpointForId as endpointForApp } from './app.js';
import { endpointForApp } from './app.js';
import type { Condition } from './condition.js';

@@ -6,0 +6,0 @@ import type { HttpClient } from './http.js';

@@ -0,1 +1,2 @@

import { appendAsLastBeforeRequest, dontCloneForAfterResponses } from './http.js';
import jsrsasign from 'jsrsasign';

@@ -31,2 +32,3 @@ import type { NormalizedOptions, ResponsePromise } from 'ky';

hooks: {
beforeRequest: [appendAsLastBeforeRequest(dontCloneForAfterResponses())],
afterResponse: [

@@ -295,3 +297,3 @@ async (req, opts, res) => {

expires_in: number;
} = await response.json();
} = await (await response).json();
return new Token(body.access_token, requestTime + body.expires_in * 1000);

@@ -349,6 +351,6 @@ }

kjurJWK.crv = 'secp256r1'; // KJUR's preferred name for name for P-256
const privateKey = (jsrsasign.KEYUTIL.getPEM(
const privateKey = jsrsasign.KEYUTIL.getPEM(
jsrsasign.KEYUTIL.getKey(kjurJWK),
'PKCS8PRV',
) as unknown) as string; // The type definitions are wrong: they say `void` but it's actually `string`.
) as unknown as string; // The type definitions are wrong: they say `void` but it's actually `string`.
return privateKey;

@@ -355,0 +357,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc