@oasislabs/parcel
Advanced tools
Comparing version 0.1.8 to 0.1.9
{ | ||
"name": "@oasislabs/parcel", | ||
"version": "0.1.8", | ||
"version": "0.1.9", | ||
"license": "Apache-2.0", | ||
@@ -19,3 +19,3 @@ "author": "Oasis Labs <feedback@oasislabs.com>", | ||
"test:cy": "start-test 'parcel serve test/cypress/fixtures/index.html -p 4444' 4444 'cypress run'", | ||
"coverage": "jest --coverage && yarn test:cy", | ||
"coverage": "jest --coverage test/unit && yarn test:cy", | ||
"doc": "typedoc --options docs/typedoc.json", | ||
@@ -40,3 +40,3 @@ "prepublishOnly": "yarn build" | ||
"^@oasislabs/parcel$": "<rootDir>/src/index", | ||
"^\\./(app|client|compute|condition|dataset|grant|http|identity|model|permission|polyfill|token).js$": "<rootDir>/src/$1", | ||
"^\\./(app|client|compute|condition|document|grant|http|identity|model|permission|polyfill|token).js$": "<rootDir>/src/$1", | ||
"^@oasislabs/parcel/(.*)$": "<rootDir>/src/$1" | ||
@@ -61,2 +61,3 @@ }, | ||
"@cypress/code-coverage": "^3.8.1", | ||
"@types/bs58": "^4.0.1", | ||
"@types/jest": "^26.0.9", | ||
@@ -66,5 +67,7 @@ "@types/jsonwebtoken": "^8.5.0", | ||
"@types/node": "^14.0.20", | ||
"@types/uuid": "^8.3.0", | ||
"ajv": "^6.12.5", | ||
"cypress": "^5.3.0", | ||
"ajv": "^7.0.0", | ||
"ajv-formats": "^1.5.1", | ||
"bs58": "^4.0.1", | ||
"cypress": "^6.0.0", | ||
"eslint-config-xo-typescript": "^0.38.0", | ||
"eslint-plugin-cypress": "^2.11.2", | ||
@@ -82,4 +85,3 @@ "jest": "^26.2.2", | ||
"typescript": "^4.1.3", | ||
"uuid": "^8.3.0", | ||
"xo": "^0.36.1" | ||
"xo": "^0.38.0" | ||
}, | ||
@@ -90,8 +92,8 @@ "dependencies": { | ||
"eventemitter3": "^4.0.4", | ||
"form-data": "^3.0.0", | ||
"form-data": "^4.0.0", | ||
"jsrsasign": "^10.0.0", | ||
"ky": "^0.26.0", | ||
"ky": "^0.27.0", | ||
"node-fetch": "3.0.0-beta.9", | ||
"param-case": "^3.0.3", | ||
"type-fest": "^0.20.0", | ||
"type-fest": "^0.21.0", | ||
"web-streams-polyfill": "^3.0.1" | ||
@@ -101,4 +103,4 @@ }, | ||
"engines": { | ||
"node": ">=14" | ||
"node": ">=14.8" | ||
} | ||
} |
@@ -13,1 +13,9 @@ # @oasislabs/parcel | ||
``` | ||
## Compute examples | ||
The compute examples require node version ^14.8. Run the compute examples with | ||
```sh | ||
npm i | ||
npm run start | ||
``` |
@@ -57,3 +57,3 @@ import type { Except, Opaque } from 'type-fest'; | ||
public readonly participants: IdentityId[]; | ||
/** Allow non-admin users to upload datasets. */ | ||
/** Allow non-admin users to upload documents. */ | ||
public readonly allowUserUploads: boolean; | ||
@@ -60,0 +60,0 @@ |
import type { Opaque } from 'type-fest'; | ||
import type { DatasetId } from './dataset.js'; | ||
import type { DocumentId } from './document.js'; | ||
import type { HttpClient } from './http.js'; | ||
@@ -12,14 +12,18 @@ import type { IdentityId } from './identity.js'; | ||
/** | ||
* Input dataset for a compute job. | ||
* Input document for a compute job. | ||
*/ | ||
export declare type InputDatasetSpec = { | ||
export declare type InputDocumentSpec = { | ||
/** ID of the document to mount. */ | ||
id: DocumentId; | ||
/** Path where the input document will be mounted inside the job. Interpreted relative to `/parcel/data/in`. */ | ||
mountPath: string; | ||
id: DatasetId; | ||
}; | ||
/** | ||
* Specification for a compute job for outputting a dataset. | ||
* Specification for a compute job for outputting a document. | ||
*/ | ||
export declare type OutputDatasetSpec = { | ||
export declare type OutputDocumentSpec = { | ||
/** Path to the file that should be uploaded as an output document. Interpreted relative to `/parcel/data/out`. */ | ||
mountPath: string; | ||
/** Owner to assign to the output document. */ | ||
owner?: IdentityId; | ||
@@ -29,7 +33,7 @@ }; | ||
/** | ||
* An output dataset produced in the context of running a job. | ||
* An output document produced in the context of running a job. | ||
*/ | ||
export declare type OutputDataset = { | ||
export declare type OutputDocument = { | ||
mountPath: string; | ||
id: DatasetId; | ||
id: DocumentId; | ||
}; | ||
@@ -71,10 +75,14 @@ | ||
env?: Record<string, string>; | ||
inputDatasets?: Array<{ | ||
mountPath: string; | ||
id: DatasetId; | ||
}>; | ||
outputDatasets?: Array<{ | ||
mountPath: string; | ||
owner: IdentityId; | ||
}>; | ||
/** | ||
* Documents to download and mount into the job's container before `cmd` runs. | ||
* If any of these documents do not exist or you do not have permission to access them, the job will fail. | ||
*/ | ||
inputDocuments?: InputDocumentSpec[]; | ||
/** | ||
* Files to be uploaded from the job's container as documents after `cmd` runs. | ||
* Files that do not exist will be silently skipped; the job will not fail. | ||
*/ | ||
outputDocuments?: OutputDocumentSpec[]; | ||
}; | ||
@@ -92,8 +100,8 @@ | ||
/** | ||
* Datasets that were generated by the job and uploaded by the Parcel | ||
* Documents that were generated by the job and uploaded by the Parcel | ||
* Worker. For a pending or running job, this list will be empty. For a | ||
* successfully completed job, each `outputDataset` entry from the job spec will | ||
* successfully completed job, each `outputDocument` entry from the job spec will | ||
* have a corresponding entry in this list. | ||
*/ | ||
outputDatasets: OutputDataset[]; | ||
outputDocuments: OutputDocument[]; | ||
@@ -100,0 +108,0 @@ /** |
import type { Opaque } from 'type-fest'; | ||
import type { Conditions } from './conditions.js'; | ||
import type { Condition } from './condition.js'; | ||
import type { HttpClient } from './http.js'; | ||
@@ -17,3 +17,5 @@ import type { IdentityId } from './identity.js'; | ||
permission?: ResourceId; | ||
conditions?: Conditions; | ||
condition?: Condition; | ||
capabilities?: string; | ||
delegating?: ResourceId; | ||
} | ||
@@ -28,4 +30,14 @@ >; | ||
/** Conditoins that must be matched to recieve access to one or more Datasets. */ | ||
conditions?: Conditions; | ||
/** The condition that must be matched to receive access to one or more Datasets. */ | ||
condition?: Condition; | ||
/** The capabilities attached to this grant. The default is `read`. */ | ||
capabilities?: Capabilities | string; | ||
/** | ||
* The grant to extend by delegation. If you are the delegating grant's `grantee` is you, | ||
* and it has the `extend` capability, then this grant will have the same `granter` as | ||
* the delegating grant. | ||
*/ | ||
delegating?: GrantId; | ||
}; | ||
@@ -45,6 +57,10 @@ | ||
public readonly grantee: IdentityId | 'everyone'; | ||
/** Conditions that describe Datasets to be shared. */ | ||
public readonly conditions?: Conditions; | ||
/** The Permission that created this Grant, if any. */ | ||
/** The condition that describes Documents to be shared. */ | ||
public readonly condition?: Condition; | ||
/** The permission that created this Grant, if any. */ | ||
public readonly permission?: PermissionId; | ||
/** The actions permissible to the grantee on targets selected by the conditions. */ | ||
public readonly capabilities?: Capabilities; | ||
/** The grant that this grant extends by delegation. */ | ||
public readonly delegating?: GrantId; | ||
@@ -56,4 +72,6 @@ public constructor(private readonly client: HttpClient, pod: PODGrant) { | ||
this.grantee = (pod.grantee as IdentityId) ?? 'everyone'; | ||
this.conditions = pod.conditions; | ||
this.condition = pod.condition; | ||
this.permission = pod.permission as PermissionId; | ||
this.capabilities = pod.capabilities ? parseCaps(pod.capabilities) : undefined; | ||
this.delegating = pod.delegating as GrantId; | ||
} | ||
@@ -97,1 +115,55 @@ | ||
}>; | ||
/** | ||
* `Capabilities` is a collection of bit flags. | ||
* To test if a cability is set, you can do something like | ||
* ``` | ||
* const requiredCaps = (Capabilities.Read | Capabilities.Extend); | ||
* caps & requiredCaps === requiredCaps; | ||
* ``` | ||
*/ | ||
/* eslint-disable @typescript-eslint/prefer-literal-enum-member */ | ||
export enum Capabilities { | ||
None = 0, | ||
/** The ability to read/view the target. */ | ||
Read = 1 << 0, // eslint-disable-line unicorn/prefer-math-trunc | ||
// /** The ability to write the target. */ | ||
// Write = 1 << 1, | ||
/** The ability to delegate this grant's capabilities to someone else. */ | ||
Extend = 1 << 2, | ||
} | ||
/* eslint-enable @typescript-eslint/prefer-literal-enum-member */ | ||
export function parseCaps(strCaps?: string): Capabilities { | ||
if (strCaps === undefined) return Capabilities.None; | ||
let caps = Capabilities.None; | ||
for (const strCap of strCaps.trim().split(/\s+/)) { | ||
switch (strCap) { | ||
case 'read': | ||
caps |= Capabilities.Read; | ||
break; | ||
case 'extend': | ||
caps |= Capabilities.Extend; | ||
break; | ||
case '': | ||
break; | ||
default: | ||
throw new Error(`unknown capability "${strCap}"`); | ||
} | ||
} | ||
return caps; | ||
} | ||
export function stringifyCaps(caps?: Capabilities): string { | ||
if (caps === undefined) return ''; | ||
const capsStrs = []; | ||
for (const [name, bit] of Object.entries(Capabilities)) { | ||
if (typeof bit !== 'number') continue; | ||
if ((caps & bit) !== 0) { | ||
capsStrs.push(name.toLowerCase()); | ||
} | ||
} | ||
return capsStrs.join(' '); | ||
} |
@@ -14,3 +14,4 @@ import type { WriteStream } from 'fs'; | ||
const DEFAULT_API_URL = 'https://api.oasislabs.com/parcel/v1'; | ||
const DEFAULT_API_URL = | ||
globalThis?.process?.env?.PARCEL_API_URL ?? 'https://api.oasislabs.com/parcel/v1'; | ||
@@ -165,3 +166,3 @@ export type Config = Partial<{ | ||
/** | ||
* A `Download` is the result of calling `parcel.downloadDataset` or `dataset.download()`. | ||
* A `Download` is the result of calling `parcel.downloadDocument` or `document.download()`. | ||
* | ||
@@ -246,3 +247,3 @@ * The downloaded data can be read using the Node `stream.Readable` interface, or by | ||
hooks: { | ||
beforeRequest: [attachContext('dataset download')], | ||
beforeRequest: [attachContext('document download')], | ||
}, | ||
@@ -249,0 +250,0 @@ }); |
@@ -13,21 +13,21 @@ import type { App, AppCreateParams, AppId, AppUpdateParams, ListAppsFilter } from './app.js'; | ||
AccessEvent, | ||
Dataset, | ||
DatasetId, | ||
DatasetUpdateParams, | ||
DatasetUploadParams, | ||
Document, | ||
DocumentId, | ||
DocumentUpdateParams, | ||
DocumentUploadParams, | ||
ListAccessLogFilter, | ||
ListDatasetsFilter, | ||
ListDocumentsFilter, | ||
Storable, | ||
Upload, | ||
} from './dataset.js'; | ||
import { DatasetImpl } from './dataset.js'; | ||
} from './document.js'; | ||
import { DocumentImpl } from './document.js'; | ||
import type { Job, JobId, JobSpec, JobStatus } from './compute.js'; | ||
import { | ||
ComputeImpl, | ||
InputDatasetSpec, | ||
InputDocumentSpec, | ||
JobPhase, | ||
OutputDataset, | ||
OutputDatasetSpec, | ||
OutputDocument, | ||
OutputDocumentSpec, | ||
} from './compute.js'; | ||
import type { Grant, GrantCreateParams, GrantId } from './grant.js'; | ||
import type { Capabilities, Grant, GrantCreateParams, GrantId } from './grant.js'; | ||
import { GrantImpl, ListGrantsFilter } from './grant.js'; | ||
@@ -47,3 +47,3 @@ import type { Config as ClientConfig, Download } from './http.js'; | ||
import type { ClientCredentials, PrivateJWK, PublicJWK, TokenSource } from './token.js'; | ||
import { TokenProvider } from './token.js'; | ||
import { TokenProvider, PARCEL_RUNTIME_AUD } from './token.js'; | ||
@@ -56,2 +56,3 @@ export { | ||
AppUpdateParams, | ||
Capabilities, | ||
Client, | ||
@@ -64,6 +65,6 @@ ClientCreateParams, | ||
PermissionId, | ||
Dataset, | ||
DatasetId, | ||
DatasetUpdateParams, | ||
DatasetUploadParams, | ||
Document, | ||
DocumentId, | ||
DocumentUpdateParams, | ||
DocumentUploadParams, | ||
ApiError, | ||
@@ -77,3 +78,3 @@ Grant, | ||
IdentityUpdateParams, | ||
InputDatasetSpec, | ||
InputDocumentSpec, | ||
Job, | ||
@@ -84,4 +85,5 @@ JobId, | ||
JobStatus, | ||
OutputDataset, | ||
OutputDatasetSpec, | ||
OutputDocument, | ||
OutputDocumentSpec, | ||
PARCEL_RUNTIME_AUD, | ||
Page, | ||
@@ -123,31 +125,31 @@ PageParams, | ||
public uploadDataset(data: Storable, params?: DatasetUploadParams): Upload { | ||
return DatasetImpl.upload(this.client, data, params); | ||
public uploadDocument(data: Storable, params?: DocumentUploadParams): Upload { | ||
return DocumentImpl.upload(this.client, data, params); | ||
} | ||
public async getDataset(id: DatasetId): Promise<Dataset> { | ||
return DatasetImpl.get(this.client, id); | ||
public async getDocument(id: DocumentId): Promise<Document> { | ||
return DocumentImpl.get(this.client, id); | ||
} | ||
public async listDatasets(filter?: ListDatasetsFilter & PageParams): Promise<Page<Dataset>> { | ||
return DatasetImpl.list(this.client, filter); | ||
public async listDocuments(filter?: ListDocumentsFilter & PageParams): Promise<Page<Document>> { | ||
return DocumentImpl.list(this.client, filter); | ||
} | ||
public downloadDataset(id: DatasetId): Download { | ||
return DatasetImpl.download(this.client, id); | ||
public downloadDocument(id: DocumentId): Download { | ||
return DocumentImpl.download(this.client, id); | ||
} | ||
public async getDatasetHistory( | ||
id: DatasetId, | ||
public async getDocumentHistory( | ||
id: DocumentId, | ||
filter?: ListAccessLogFilter & PageParams, | ||
): Promise<Page<AccessEvent>> { | ||
return DatasetImpl.history(this.client, id, filter); | ||
return DocumentImpl.history(this.client, id, filter); | ||
} | ||
public async updateDataset(id: DatasetId, update: DatasetUpdateParams): Promise<Dataset> { | ||
return DatasetImpl.update(this.client, id, update); | ||
public async updateDocument(id: DocumentId, update: DocumentUpdateParams): Promise<Document> { | ||
return DocumentImpl.update(this.client, id, update); | ||
} | ||
public async deleteDataset(id: DatasetId): Promise<void> { | ||
return DatasetImpl.delete_(this.client, id); | ||
public async deleteDocument(id: DocumentId): Promise<void> { | ||
return DocumentImpl.delete_(this.client, id); | ||
} | ||
@@ -179,3 +181,3 @@ | ||
public async listPermissions(appId: AppId, filter: PageParams): Promise<Page<Permission>> { | ||
public async listPermissions(appId: AppId, filter?: PageParams): Promise<Page<Permission>> { | ||
return PermissionImpl.list(this.client, appId, filter); | ||
@@ -182,0 +184,0 @@ } |
@@ -5,3 +5,3 @@ import type { Opaque } from 'type-fest'; | ||
import { endpointForId as endpointForApp } from './app.js'; | ||
import type { Conditions } from './conditions.js'; | ||
import type { Condition } from './condition.js'; | ||
import type { HttpClient } from './http.js'; | ||
@@ -114,7 +114,7 @@ import type { IdentityId } from './identity.js'; | ||
/** The symbolic grantee */ | ||
/** The symbolic grantee. */ | ||
grantee?: GranteeRef; | ||
/** The Grant's conditions. @see `Grant.conditions`. */ | ||
conditions?: Conditions; | ||
/** The Grant's condition. @see `Grant.condition`. */ | ||
condition?: Condition; | ||
}; | ||
@@ -121,0 +121,0 @@ |
@@ -7,8 +7,4 @@ // The following code is inlined from `ky-universal` because it uses ES modules and | ||
import fetch, { Headers, Request as RequestPF, Response as ResponsePF } from 'node-fetch'; | ||
import { | ||
ReadableStream as ReadableStreamPF, | ||
WritableStream as WritableStreamPF, | ||
// @ts-expect-error: The package isn't ESM-compatible. | ||
// eslint-disable-next-line import/extensions | ||
} from 'web-streams-polyfill/dist/ponyfill.es2018.js'; | ||
// @ts-expect-error: The package isn't ESM-compatible. | ||
import * as webStreams from 'web-streams-polyfill/dist/ponyfill.es2018.js'; | ||
@@ -23,7 +19,7 @@ globalThis.fetch = | ||
globalThis.FormData = globalThis.FormData ?? FormData; | ||
globalThis.ReadableStream = globalThis.ReadableStream ?? ReadableStreamPF; | ||
globalThis.WritableStream = globalThis.WritableStream ?? WritableStreamPF; | ||
globalThis.ReadableStream = globalThis.ReadableStream ?? webStreams.ReadableStream; | ||
globalThis.WritableStream = globalThis.WritableStream ?? webStreams.WritableStream; | ||
const ReadableStreamPF_ = ReadableStreamPF as typeof globalThis.ReadableStream; | ||
const ReadableStreamPF = webStreams.ReadableStream as typeof globalThis.ReadableStream; | ||
export { ReadableStreamPF_ as ReadableStreamPF }; | ||
export { ReadableStreamPF }; |
@@ -1,5 +0,5 @@ | ||
import { KEYUTIL, KJUR } from 'jsrsasign'; | ||
import jsrsasign from 'jsrsasign'; | ||
import type { ResponsePromise } from 'ky'; | ||
import ky from 'ky'; | ||
import type { Except, JsonObject } from 'type-fest'; | ||
import type { JsonObject, Merge } from 'type-fest'; | ||
@@ -9,3 +9,4 @@ import type { IdentityId } from './identity.js'; | ||
const DEFAULT_TOKEN_ENDPOINT = 'https://auth.oasislabs.com/oauth/token'; | ||
const DEFAULT_TOKEN_ENDPOINT = | ||
globalThis?.process?.env?.PARCEL_TOKEN_ENDPOINT ?? 'https://auth.oasislabs.com/oauth/token'; | ||
export const PARCEL_RUNTIME_AUD = 'https://api.oasislabs.com/parcel'; // TODO(#326) | ||
@@ -87,4 +88,4 @@ | ||
private readonly scopes: string[]; | ||
private readonly privateKey: PrivateJWK; | ||
private readonly privateKeyPEM: string; // PEM is required by jsrsasign. | ||
private readonly keyId: string; | ||
@@ -106,5 +107,5 @@ private readonly clientAssertionLifetime = 1 * 60 * 60; // 1 hour | ||
const { privateKey: privateKeyPEM, keyId } = jwkToPem(privateKey); | ||
this.privateKey = privateKey; | ||
const privateKeyPEM = jwkToPem(privateKey); | ||
this.privateKeyPEM = privateKeyPEM; | ||
this.keyId = keyId; | ||
@@ -114,3 +115,3 @@ this.clientId = clientId; | ||
this.audience = audience ?? PARCEL_RUNTIME_AUD; | ||
this.scopes = scopes ?? ['parcel.temp_api', 'parcel.temp_storage']; | ||
this.scopes = scopes ?? ['parcel.*']; | ||
} | ||
@@ -121,3 +122,3 @@ | ||
privateKey: this.privateKeyPEM, | ||
keyId: this.keyId, | ||
keyId: this.privateKey.kid, | ||
payload: { | ||
@@ -127,3 +128,3 @@ sub: this.clientId, | ||
aud: this.tokenEndpoint, | ||
jti: KJUR.crypto.Util.getRandomHexOfNbytes(8), | ||
jti: jsrsasign.KJUR.crypto.Util.getRandomHexOfNbytes(8), | ||
}, | ||
@@ -208,4 +209,4 @@ lifetime: this.clientAssertionLifetime, | ||
private readonly principal: string; | ||
private readonly privateKey: PrivateJWK; | ||
private readonly privateKeyPEM: string; // PEM is required by jsrsasign. | ||
private readonly keyId: string; | ||
private readonly scopes: string[]; | ||
@@ -222,5 +223,5 @@ private readonly tokenLifetime: number; | ||
const { privateKey: privateKeyPEM, keyId } = jwkToPem(privateKey); | ||
this.privateKey = privateKey; | ||
const privateKeyPEM = jwkToPem(privateKey); | ||
this.privateKeyPEM = privateKeyPEM; | ||
this.keyId = keyId; | ||
@@ -236,3 +237,3 @@ this.principal = principal; | ||
privateKey: this.privateKeyPEM, | ||
keyId: this.keyId, | ||
keyId: this.privateKey.kid, | ||
payload: { | ||
@@ -242,3 +243,3 @@ sub: this.principal, | ||
aud: PARCEL_RUNTIME_AUD, | ||
scope: this.scopes, | ||
scope: this.scopes.join(' '), | ||
}, | ||
@@ -288,3 +289,3 @@ lifetime: this.tokenLifetime, | ||
}; | ||
export type PublicES256JWK = Except<PrivateES256JWK, 'd'>; | ||
export type PublicES256JWK = Merge<PrivateES256JWK, { d?: undefined | null }>; | ||
@@ -307,3 +308,3 @@ export type PublicJWK = PublicES256JWK; | ||
/** Returns the PKCS8-encoded private key and the JWK"s key id. */ | ||
function jwkToPem(jwk: PrivateJWK): { privateKey: string; keyId: string } { | ||
function jwkToPem(jwk: PrivateJWK): string { | ||
if (jwk.kty !== 'EC' || jwk.alg !== 'ES256') { | ||
@@ -314,9 +315,8 @@ throw new Error(`Unsupported private key. Expected \`alg: 'ES256'\` but was \`${jwk.alg}\` }`); | ||
const kjurJWK = JSON.parse(JSON.stringify(jwk)); | ||
const keyId = jwk.kid ?? KJUR.jws.JWS.getJWKthumbprint(kjurJWK); | ||
kjurJWK.crv = 'secp256r1'; // KJUR's preferred name for name for P-256 | ||
const privateKey = (KEYUTIL.getPEM(KEYUTIL.getKey(kjurJWK), 'PKCS8PRV') as unknown) as string; // The type definitions are wrong: they say `void` but it's actually `string`. | ||
return { | ||
privateKey, | ||
keyId, | ||
}; | ||
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`. | ||
return privateKey; | ||
} | ||
@@ -332,3 +332,3 @@ | ||
privateKey: string; | ||
keyId: string; | ||
keyId?: string; | ||
payload: JsonObject; | ||
@@ -348,3 +348,3 @@ /** The token's lifetime in seconds. */ | ||
return KJUR.jws.JWS.sign(null, header, payload, privateKey); | ||
return jsrsasign.KJUR.jws.JWS.sign(null, header, payload, privateKey); | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
21
74078
26
15
1955
+ Addedform-data@4.0.1(transitive)
+ Addedky@0.27.0(transitive)
+ Addedtype-fest@0.21.3(transitive)
- Removedform-data@3.0.2(transitive)
- Removedky@0.26.0(transitive)
- Removedtype-fest@0.20.2(transitive)
Updatedform-data@^4.0.0
Updatedky@^0.27.0
Updatedtype-fest@^0.21.0