@vercel/sandbox 2.0.0-beta.13 → 2.0.0-beta.18
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/api-client/api-client.cjs +3 -15
- package/dist/api-client/api-client.cjs.map +1 -1
- package/dist/api-client/api-client.d.cts +5510 -76
- package/dist/api-client/api-client.d.ts +5510 -76
- package/dist/api-client/api-client.js +4 -16
- package/dist/api-client/api-client.js.map +1 -1
- package/dist/api-client/base-client.cjs +2 -1
- package/dist/api-client/base-client.cjs.map +1 -1
- package/dist/api-client/base-client.js +2 -1
- package/dist/api-client/base-client.js.map +1 -1
- package/dist/api-client/index.d.ts +1 -1
- package/dist/api-client/index.js +1 -1
- package/dist/api-client/validators.cjs +60 -16
- package/dist/api-client/validators.cjs.map +1 -1
- package/dist/api-client/validators.d.cts +25546 -130
- package/dist/api-client/validators.d.ts +25546 -130
- package/dist/api-client/validators.js +55 -16
- package/dist/api-client/validators.js.map +1 -1
- package/dist/auth/api.cjs +1 -1
- package/dist/auth/api.cjs.map +1 -1
- package/dist/auth/api.js +1 -1
- package/dist/auth/api.js.map +1 -1
- package/dist/auth/file.d.cts +3 -3
- package/dist/auth/file.d.ts +3 -3
- package/dist/auth/index.cjs +0 -1
- package/dist/auth/index.d.cts +2 -2
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +2 -2
- package/dist/auth/project.cjs +124 -26
- package/dist/auth/project.cjs.map +1 -1
- package/dist/auth/project.d.cts +9 -13
- package/dist/auth/project.d.ts +9 -13
- package/dist/auth/project.js +125 -26
- package/dist/auth/project.js.map +1 -1
- package/dist/filesystem.cjs +499 -0
- package/dist/filesystem.cjs.map +1 -0
- package/dist/filesystem.d.cts +258 -0
- package/dist/filesystem.d.ts +258 -0
- package/dist/filesystem.js +497 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -1
- package/dist/network-policy.d.cts +58 -2
- package/dist/network-policy.d.ts +58 -2
- package/dist/sandbox.cjs +138 -22
- package/dist/sandbox.cjs.map +1 -1
- package/dist/sandbox.d.cts +2069 -22
- package/dist/sandbox.d.ts +2069 -22
- package/dist/sandbox.js +138 -22
- package/dist/sandbox.js.map +1 -1
- package/dist/session.cjs +10 -7
- package/dist/session.cjs.map +1 -1
- package/dist/session.d.cts +7 -5
- package/dist/session.d.ts +7 -5
- package/dist/session.js +10 -7
- package/dist/session.js.map +1 -1
- package/dist/snapshot.cjs +63 -10
- package/dist/snapshot.cjs.map +1 -1
- package/dist/snapshot.d.cts +41 -9
- package/dist/snapshot.d.ts +41 -9
- package/dist/snapshot.js +62 -10
- package/dist/snapshot.js.map +1 -1
- package/dist/utils/network-policy.cjs +23 -39
- package/dist/utils/network-policy.cjs.map +1 -1
- package/dist/utils/network-policy.js +23 -39
- package/dist/utils/network-policy.js.map +1 -1
- package/dist/utils/paginator.cjs +41 -0
- package/dist/utils/paginator.cjs.map +1 -0
- package/dist/utils/paginator.d.cts +16 -0
- package/dist/utils/paginator.d.ts +16 -0
- package/dist/utils/paginator.js +40 -0
- package/dist/utils/paginator.js.map +1 -0
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/snapshot.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { APIClient } from "./api-client/api-client.js";
|
|
2
2
|
import "./api-client/index.js";
|
|
3
3
|
import { getCredentials } from "./utils/get-credentials.js";
|
|
4
|
+
import { attachPaginator } from "./utils/paginator.js";
|
|
5
|
+
import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from "@workflow/serde";
|
|
4
6
|
|
|
5
7
|
//#region src/snapshot.ts
|
|
6
8
|
/**
|
|
@@ -10,6 +12,22 @@ import { getCredentials } from "./utils/get-credentials.js";
|
|
|
10
12
|
* @hideconstructor
|
|
11
13
|
*/
|
|
12
14
|
var Snapshot = class Snapshot {
|
|
15
|
+
/**
|
|
16
|
+
* Lazily resolve credentials and construct an API client.
|
|
17
|
+
* This is used in step contexts where the Snapshot was deserialized
|
|
18
|
+
* without a client (e.g. when crossing workflow/step boundaries).
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
async ensureClient() {
|
|
22
|
+
"use step";
|
|
23
|
+
if (this._client) return this._client;
|
|
24
|
+
const credentials = await getCredentials();
|
|
25
|
+
this._client = new APIClient({
|
|
26
|
+
teamId: credentials.teamId,
|
|
27
|
+
token: credentials.token
|
|
28
|
+
});
|
|
29
|
+
return this._client;
|
|
30
|
+
}
|
|
13
31
|
/**
|
|
14
32
|
* Unique ID of this snapshot.
|
|
15
33
|
*/
|
|
@@ -48,31 +66,65 @@ var Snapshot = class Snapshot {
|
|
|
48
66
|
return new Date(this.snapshot.expiresAt);
|
|
49
67
|
}
|
|
50
68
|
/**
|
|
51
|
-
*
|
|
69
|
+
* Serialize a Snapshot instance to plain data for @workflow/serde.
|
|
70
|
+
*
|
|
71
|
+
* @param instance - The Snapshot instance to serialize
|
|
72
|
+
* @returns A plain object containing snapshot metadata
|
|
73
|
+
*/
|
|
74
|
+
static [WORKFLOW_SERIALIZE](instance) {
|
|
75
|
+
return { snapshot: instance.snapshot };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Deserialize a Snapshot from serialized data.
|
|
79
|
+
*
|
|
80
|
+
* The deserialized instance uses the serialized metadata synchronously and
|
|
81
|
+
* lazily creates an API client only when methods perform API requests.
|
|
52
82
|
*
|
|
53
|
-
* @param
|
|
54
|
-
* @
|
|
83
|
+
* @param data - The serialized snapshot data
|
|
84
|
+
* @returns The reconstructed Snapshot instance
|
|
55
85
|
*/
|
|
86
|
+
static [WORKFLOW_DESERIALIZE](data) {
|
|
87
|
+
return new Snapshot({ snapshot: data.snapshot });
|
|
88
|
+
}
|
|
56
89
|
constructor({ client, snapshot }) {
|
|
57
|
-
this.
|
|
90
|
+
this._client = null;
|
|
91
|
+
this._client = client ?? null;
|
|
58
92
|
this.snapshot = snapshot;
|
|
59
93
|
}
|
|
60
94
|
/**
|
|
61
95
|
* Allow to get a list of snapshots for a team narrowed to the given params.
|
|
62
96
|
* It returns both the snapshots and the pagination metadata to allow getting
|
|
63
97
|
* the next page of results.
|
|
98
|
+
*
|
|
99
|
+
* The returned object is async-iterable to auto-paginate through all pages:
|
|
100
|
+
*
|
|
101
|
+
* ```ts
|
|
102
|
+
* const result = await Snapshot.list({ name: "my-sandbox" });
|
|
103
|
+
* for await (const snapshot of result) { ... }
|
|
104
|
+
* // or: await result.toArray();
|
|
105
|
+
* // or: for await (const page of result.pages()) { ... }
|
|
106
|
+
* ```
|
|
64
107
|
*/
|
|
65
108
|
static async list(params) {
|
|
66
109
|
"use step";
|
|
67
110
|
const credentials = await getCredentials(params);
|
|
68
|
-
|
|
111
|
+
const client = new APIClient({
|
|
69
112
|
teamId: credentials.teamId,
|
|
70
113
|
token: credentials.token,
|
|
71
114
|
fetch: params?.fetch
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
115
|
+
});
|
|
116
|
+
const fetchPage = async (cursor) => {
|
|
117
|
+
return (await client.listSnapshots({
|
|
118
|
+
...credentials,
|
|
119
|
+
...params,
|
|
120
|
+
...cursor !== void 0 && { cursor }
|
|
121
|
+
})).json;
|
|
122
|
+
};
|
|
123
|
+
return attachPaginator(await fetchPage(params?.cursor), {
|
|
124
|
+
itemsKey: "snapshots",
|
|
125
|
+
fetchNext: fetchPage,
|
|
126
|
+
signal: params?.signal
|
|
127
|
+
});
|
|
76
128
|
}
|
|
77
129
|
/**
|
|
78
130
|
* Retrieve an existing snapshot.
|
|
@@ -104,7 +156,7 @@ var Snapshot = class Snapshot {
|
|
|
104
156
|
*/
|
|
105
157
|
async delete(opts) {
|
|
106
158
|
"use step";
|
|
107
|
-
this.snapshot = (await this.
|
|
159
|
+
this.snapshot = (await (await this.ensureClient()).deleteSnapshot({
|
|
108
160
|
snapshotId: this.snapshot.id,
|
|
109
161
|
signal: opts?.signal
|
|
110
162
|
})).json.snapshot;
|
package/dist/snapshot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","names":[],"sources":["../src/snapshot.ts"],"sourcesContent":["import type { WithFetchOptions } from \"./api-client/api-client.js\";\nimport type { SnapshotMetadata } from \"./api-client/index.js\";\nimport { APIClient } from \"./api-client/index.js\";\nimport { type Credentials, getCredentials } from \"./utils/get-credentials.js\";\n\n/** @inline */\ninterface GetSnapshotParams {\n /**\n * Unique identifier of the snapshot.\n */\n snapshotId: string;\n /**\n * An AbortSignal to cancel the operation.\n */\n signal?: AbortSignal;\n}\n\n/**\n * A Snapshot is a saved state of a Sandbox that can be used to create new Sandboxes\n *\n * Use {@link Sandbox.snapshot} or {@link Snapshot.get} to construct.\n * @hideconstructor\n */\nexport class Snapshot {\n private
|
|
1
|
+
{"version":3,"file":"snapshot.js","names":[],"sources":["../src/snapshot.ts"],"sourcesContent":["import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from \"@workflow/serde\";\nimport type { WithFetchOptions } from \"./api-client/api-client.js\";\nimport type { SnapshotMetadata } from \"./api-client/index.js\";\nimport { APIClient } from \"./api-client/index.js\";\nimport { type Credentials, getCredentials } from \"./utils/get-credentials.js\";\nimport { attachPaginator } from \"./utils/paginator.js\";\n\nexport interface SerializedSnapshot {\n snapshot: SnapshotMetadata;\n}\n\n/** @inline */\ninterface GetSnapshotParams {\n /**\n * Unique identifier of the snapshot.\n */\n snapshotId: string;\n /**\n * An AbortSignal to cancel the operation.\n */\n signal?: AbortSignal;\n}\n\n/**\n * A Snapshot is a saved state of a Sandbox that can be used to create new Sandboxes\n *\n * Use {@link Sandbox.snapshot} or {@link Snapshot.get} to construct.\n * @hideconstructor\n */\nexport class Snapshot {\n private _client: APIClient | null = null;\n\n /**\n * Lazily resolve credentials and construct an API client.\n * This is used in step contexts where the Snapshot was deserialized\n * without a client (e.g. when crossing workflow/step boundaries).\n * @internal\n */\n private async ensureClient(): Promise<APIClient> {\n \"use step\";\n if (this._client) return this._client;\n const credentials = await getCredentials();\n this._client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n });\n return this._client;\n }\n\n /**\n * Unique ID of this snapshot.\n */\n public get snapshotId(): string {\n return this.snapshot.id;\n }\n\n /**\n * The ID of the session from which this snapshot was created.\n */\n public get sourceSessionId(): string {\n return this.snapshot.sourceSessionId;\n }\n\n /**\n * The status of the snapshot.\n */\n public get status(): SnapshotMetadata[\"status\"] {\n return this.snapshot.status;\n }\n\n /**\n * The size of the snapshot in bytes, or null if not available.\n */\n public get sizeBytes(): number {\n return this.snapshot.sizeBytes;\n }\n\n /**\n * The creation date of this snapshot.\n */\n public get createdAt(): Date {\n return new Date(this.snapshot.createdAt);\n }\n\n /**\n * The expiration date of this snapshot, or undefined if it does not expire.\n */\n public get expiresAt(): Date | undefined {\n if (this.snapshot.expiresAt === undefined) {\n return undefined;\n }\n\n return new Date(this.snapshot.expiresAt);\n }\n\n /**\n * Internal metadata about this snapshot.\n */\n private snapshot: SnapshotMetadata;\n\n /**\n * Serialize a Snapshot instance to plain data for @workflow/serde.\n *\n * @param instance - The Snapshot instance to serialize\n * @returns A plain object containing snapshot metadata\n */\n static [WORKFLOW_SERIALIZE](instance: Snapshot): SerializedSnapshot {\n return {\n snapshot: instance.snapshot,\n };\n }\n\n /**\n * Deserialize a Snapshot from serialized data.\n *\n * The deserialized instance uses the serialized metadata synchronously and\n * lazily creates an API client only when methods perform API requests.\n *\n * @param data - The serialized snapshot data\n * @returns The reconstructed Snapshot instance\n */\n static [WORKFLOW_DESERIALIZE](data: SerializedSnapshot): Snapshot {\n return new Snapshot({\n snapshot: data.snapshot,\n });\n }\n\n constructor({\n client,\n snapshot,\n }: {\n client?: APIClient;\n snapshot: SnapshotMetadata;\n }) {\n this._client = client ?? null;\n this.snapshot = snapshot;\n }\n\n /**\n * Allow to get a list of snapshots for a team narrowed to the given params.\n * It returns both the snapshots and the pagination metadata to allow getting\n * the next page of results.\n *\n * The returned object is async-iterable to auto-paginate through all pages:\n *\n * ```ts\n * const result = await Snapshot.list({ name: \"my-sandbox\" });\n * for await (const snapshot of result) { ... }\n * // or: await result.toArray();\n * // or: for await (const page of result.pages()) { ... }\n * ```\n */\n static async list(\n params?: Partial<Parameters<APIClient[\"listSnapshots\"]>[0]> &\n Partial<Credentials> &\n WithFetchOptions,\n ) {\n \"use step\";\n const credentials = await getCredentials(params);\n const client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n fetch: params?.fetch,\n });\n const fetchPage = async (cursor?: string) => {\n const response = await client.listSnapshots({\n ...credentials,\n ...params,\n ...(cursor !== undefined && { cursor }),\n });\n return response.json;\n };\n const firstPage = await fetchPage(params?.cursor);\n return attachPaginator(firstPage, {\n itemsKey: \"snapshots\",\n fetchNext: fetchPage,\n signal: params?.signal,\n });\n }\n\n /**\n * Retrieve an existing snapshot.\n *\n * @param params - Get parameters and optional credentials.\n * @returns A promise resolving to the {@link Sandbox}.\n */\n static async get(\n params: GetSnapshotParams | (GetSnapshotParams & Credentials),\n ): Promise<Snapshot> {\n \"use step\";\n const credentials = await getCredentials(params);\n const client = new APIClient({\n teamId: credentials.teamId,\n token: credentials.token,\n });\n\n const sandbox = await client.getSnapshot({\n snapshotId: params.snapshotId,\n signal: params.signal,\n });\n\n return new Snapshot({\n client,\n snapshot: sandbox.json.snapshot,\n });\n }\n\n /**\n * Delete this snapshot.\n *\n * @param opts - Optional parameters.\n * @param opts.signal - An AbortSignal to cancel the operation.\n * @returns A promise that resolves once the snapshot has been deleted.\n */\n async delete(opts?: { signal?: AbortSignal }): Promise<void> {\n \"use step\";\n const client = await this.ensureClient();\n const response = await client.deleteSnapshot({\n snapshotId: this.snapshot.id,\n signal: opts?.signal,\n });\n\n this.snapshot = response.json.snapshot;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AA6BA,IAAa,WAAb,MAAa,SAAS;;;;;;;CASpB,MAAc,eAAmC;AAC/C;AACA,MAAI,KAAK,QAAS,QAAO,KAAK;EAC9B,MAAM,cAAc,MAAM,gBAAgB;AAC1C,OAAK,UAAU,IAAI,UAAU;GAC3B,QAAQ,YAAY;GACpB,OAAO,YAAY;GACpB,CAAC;AACF,SAAO,KAAK;;;;;CAMd,IAAW,aAAqB;AAC9B,SAAO,KAAK,SAAS;;;;;CAMvB,IAAW,kBAA0B;AACnC,SAAO,KAAK,SAAS;;;;;CAMvB,IAAW,SAAqC;AAC9C,SAAO,KAAK,SAAS;;;;;CAMvB,IAAW,YAAoB;AAC7B,SAAO,KAAK,SAAS;;;;;CAMvB,IAAW,YAAkB;AAC3B,SAAO,IAAI,KAAK,KAAK,SAAS,UAAU;;;;;CAM1C,IAAW,YAA8B;AACvC,MAAI,KAAK,SAAS,cAAc,OAC9B;AAGF,SAAO,IAAI,KAAK,KAAK,SAAS,UAAU;;;;;;;;CAc1C,QAAQ,oBAAoB,UAAwC;AAClE,SAAO,EACL,UAAU,SAAS,UACpB;;;;;;;;;;;CAYH,QAAQ,sBAAsB,MAAoC;AAChE,SAAO,IAAI,SAAS,EAClB,UAAU,KAAK,UAChB,CAAC;;CAGJ,YAAY,EACV,QACA,YAIC;OAvGK,UAA4B;AAwGlC,OAAK,UAAU,UAAU;AACzB,OAAK,WAAW;;;;;;;;;;;;;;;;CAiBlB,aAAa,KACX,QAGA;AACA;EACA,MAAM,cAAc,MAAM,eAAe,OAAO;EAChD,MAAM,SAAS,IAAI,UAAU;GAC3B,QAAQ,YAAY;GACpB,OAAO,YAAY;GACnB,OAAO,QAAQ;GAChB,CAAC;EACF,MAAM,YAAY,OAAO,WAAoB;AAM3C,WALiB,MAAM,OAAO,cAAc;IAC1C,GAAG;IACH,GAAG;IACH,GAAI,WAAW,UAAa,EAAE,QAAQ;IACvC,CAAC,EACc;;AAGlB,SAAO,gBADW,MAAM,UAAU,QAAQ,OAAO,EACf;GAChC,UAAU;GACV,WAAW;GACX,QAAQ,QAAQ;GACjB,CAAC;;;;;;;;CASJ,aAAa,IACX,QACmB;AACnB;EACA,MAAM,cAAc,MAAM,eAAe,OAAO;EAChD,MAAM,SAAS,IAAI,UAAU;GAC3B,QAAQ,YAAY;GACpB,OAAO,YAAY;GACpB,CAAC;AAOF,SAAO,IAAI,SAAS;GAClB;GACA,WAPc,MAAM,OAAO,YAAY;IACvC,YAAY,OAAO;IACnB,QAAQ,OAAO;IAChB,CAAC,EAIkB,KAAK;GACxB,CAAC;;;;;;;;;CAUJ,MAAM,OAAO,MAAgD;AAC3D;AAOA,OAAK,YALY,OADF,MAAM,KAAK,cAAc,EACV,eAAe;GAC3C,YAAY,KAAK,SAAS;GAC1B,QAAQ,MAAM;GACf,CAAC,EAEuB,KAAK"}
|
|
@@ -1,53 +1,37 @@
|
|
|
1
1
|
|
|
2
2
|
//#region src/utils/network-policy.ts
|
|
3
3
|
function toAPINetworkPolicy(policy) {
|
|
4
|
-
if (policy === "allow-all") return { mode:
|
|
5
|
-
|
|
6
|
-
if (policy.allow && !Array.isArray(policy.allow)) {
|
|
7
|
-
const allowedDomains = Object.keys(policy.allow);
|
|
8
|
-
const injectionRules = [];
|
|
9
|
-
for (const [domain, rules] of Object.entries(policy.allow)) {
|
|
10
|
-
const merged = {};
|
|
11
|
-
for (const rule of rules) for (const t of rule.transform ?? []) Object.assign(merged, t.headers);
|
|
12
|
-
if (Object.keys(merged).length > 0) injectionRules.push({
|
|
13
|
-
domain,
|
|
14
|
-
headers: merged
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return {
|
|
18
|
-
mode: "custom",
|
|
19
|
-
...allowedDomains.length > 0 && { allowedDomains },
|
|
20
|
-
...injectionRules.length > 0 && { injectionRules },
|
|
21
|
-
...policy.subnets?.allow && { allowedCIDRs: policy.subnets.allow },
|
|
22
|
-
...policy.subnets?.deny && { deniedCIDRs: policy.subnets.deny }
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
mode: "custom",
|
|
27
|
-
...policy.allow && { allowedDomains: policy.allow },
|
|
28
|
-
...policy.subnets?.allow && { allowedCIDRs: policy.subnets.allow },
|
|
29
|
-
...policy.subnets?.deny && { deniedCIDRs: policy.subnets.deny }
|
|
30
|
-
};
|
|
4
|
+
if (policy === "allow-all" || policy === "deny-all") return { mode: policy };
|
|
5
|
+
return policy;
|
|
31
6
|
}
|
|
32
7
|
function fromAPINetworkPolicy(api) {
|
|
33
|
-
if (api.mode === "allow-all"
|
|
34
|
-
if (api.mode === "deny-all") return "deny-all";
|
|
8
|
+
if (api.mode === "allow-all" || api.mode === "deny-all") return api.mode;
|
|
35
9
|
const subnets = api.allowedCIDRs || api.deniedCIDRs ? { subnets: {
|
|
36
10
|
...api.allowedCIDRs && { allow: api.allowedCIDRs },
|
|
37
11
|
...api.deniedCIDRs && { deny: api.deniedCIDRs }
|
|
38
12
|
} } : void 0;
|
|
39
|
-
if (api.injectionRules && api.injectionRules.length > 0) {
|
|
40
|
-
const rulesByDomain = new Map(
|
|
41
|
-
const
|
|
42
|
-
for (const domain of api.allowedDomains ?? []) {
|
|
43
|
-
const headerNames = rulesByDomain.get(domain);
|
|
44
|
-
if (headerNames && headerNames.length > 0) allow[domain] = [{ transform: [{ headers: Object.fromEntries(headerNames.map((n) => [n, "<redacted>"])) }] }];
|
|
45
|
-
else allow[domain] = [];
|
|
46
|
-
}
|
|
47
|
-
for (const rule of api.injectionRules) if (!(rule.domain in allow)) {
|
|
13
|
+
if (api.injectionRules && api.injectionRules.length > 0 || api.forwardRules && api.forwardRules.length > 0) {
|
|
14
|
+
const rulesByDomain = /* @__PURE__ */ new Map();
|
|
15
|
+
for (const rule of api.injectionRules ?? []) {
|
|
48
16
|
const headers = Object.fromEntries((rule.headerNames ?? []).map((n) => [n, "<redacted>"]));
|
|
49
|
-
|
|
17
|
+
const rules = rulesByDomain.get(rule.domain) ?? [];
|
|
18
|
+
rules.push({
|
|
19
|
+
...rule.match ? { match: rule.match } : {},
|
|
20
|
+
transform: [{ headers }]
|
|
21
|
+
});
|
|
22
|
+
rulesByDomain.set(rule.domain, rules);
|
|
50
23
|
}
|
|
24
|
+
for (const rule of api.forwardRules ?? []) {
|
|
25
|
+
const rules = rulesByDomain.get(rule.domain) ?? [];
|
|
26
|
+
rules.push({
|
|
27
|
+
...rule.match ? { match: rule.match } : {},
|
|
28
|
+
forwardURL: rule.forwardURL
|
|
29
|
+
});
|
|
30
|
+
rulesByDomain.set(rule.domain, rules);
|
|
31
|
+
}
|
|
32
|
+
const allow = {};
|
|
33
|
+
for (const domain of api.allowedDomains ?? []) allow[domain] = rulesByDomain.get(domain) ?? [];
|
|
34
|
+
for (const rule of [...api.injectionRules ?? [], ...api.forwardRules ?? []]) if (!(rule.domain in allow)) allow[rule.domain] = rulesByDomain.get(rule.domain) ?? [];
|
|
51
35
|
return {
|
|
52
36
|
allow,
|
|
53
37
|
...subnets
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-policy.cjs","names":["
|
|
1
|
+
{"version":3,"file":"network-policy.cjs","names":["allow: Record<string, NetworkPolicyRule[]>"],"sources":["../../src/utils/network-policy.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { NetworkPolicy, NetworkPolicyRule } from \"../network-policy.js\";\nimport {\n NetworkPolicyRequestValidator,\n NetworkPolicyResponseValidator,\n} from \"../api-client/validators.js\";\n\ntype APIRequestNetworkPolicy = z.infer<typeof NetworkPolicyRequestValidator>;\ntype APIResponseNetworkPolicy = z.infer<typeof NetworkPolicyResponseValidator>;\n\nexport function toAPINetworkPolicy(\n policy: NetworkPolicy,\n): APIRequestNetworkPolicy {\n if (policy === \"allow-all\" || policy === \"deny-all\") {\n return { mode: policy };\n }\n\n return policy;\n}\n\nexport function fromAPINetworkPolicy(\n api: APIResponseNetworkPolicy,\n): NetworkPolicy {\n if (api.mode === \"allow-all\" || api.mode === \"deny-all\") {\n return api.mode;\n }\n\n const subnets =\n api.allowedCIDRs || api.deniedCIDRs\n ? {\n subnets: {\n ...(api.allowedCIDRs && { allow: api.allowedCIDRs }),\n ...(api.deniedCIDRs && { deny: api.deniedCIDRs }),\n },\n }\n : undefined;\n\n // If L7 rules are present, reconstruct the record form.\n // The API returns headerNames (secret values are stripped), so we\n // populate each header value with \"<redacted>\".\n if (\n (api.injectionRules && api.injectionRules.length > 0) ||\n (api.forwardRules && api.forwardRules.length > 0)\n ) {\n const rulesByDomain = new Map<string, NetworkPolicyRule[]>();\n for (const rule of api.injectionRules ?? []) {\n const headers = Object.fromEntries(\n (rule.headerNames ?? []).map((n) => [n, \"<redacted>\"]),\n );\n const rules = rulesByDomain.get(rule.domain) ?? [];\n rules.push({\n ...(rule.match ? { match: rule.match } : {}),\n transform: [{ headers }],\n });\n rulesByDomain.set(rule.domain, rules);\n }\n for (const rule of api.forwardRules ?? []) {\n const rules = rulesByDomain.get(rule.domain) ?? [];\n rules.push({\n ...(rule.match ? { match: rule.match } : {}),\n forwardURL: rule.forwardURL,\n });\n rulesByDomain.set(rule.domain, rules);\n }\n\n const allow: Record<string, NetworkPolicyRule[]> = {};\n for (const domain of api.allowedDomains ?? []) {\n allow[domain] = rulesByDomain.get(domain) ?? [];\n }\n // Include L7 rules for domains not in allowedDomains\n for (const rule of [...(api.injectionRules ?? []), ...(api.forwardRules ?? [])]) {\n if (!(rule.domain in allow)) {\n allow[rule.domain] = rulesByDomain.get(rule.domain) ?? [];\n }\n }\n\n return { allow, ...subnets };\n }\n\n return {\n ...(api.allowedDomains && { allow: api.allowedDomains }),\n ...subnets,\n };\n}\n"],"mappings":";;AAUA,SAAgB,mBACd,QACyB;AACzB,KAAI,WAAW,eAAe,WAAW,WACvC,QAAO,EAAE,MAAM,QAAQ;AAGzB,QAAO;;AAGT,SAAgB,qBACd,KACe;AACf,KAAI,IAAI,SAAS,eAAe,IAAI,SAAS,WAC3C,QAAO,IAAI;CAGb,MAAM,UACJ,IAAI,gBAAgB,IAAI,cACpB,EACE,SAAS;EACP,GAAI,IAAI,gBAAgB,EAAE,OAAO,IAAI,cAAc;EACnD,GAAI,IAAI,eAAe,EAAE,MAAM,IAAI,aAAa;EACjD,EACF,GACD;AAKN,KACG,IAAI,kBAAkB,IAAI,eAAe,SAAS,KAClD,IAAI,gBAAgB,IAAI,aAAa,SAAS,GAC/C;EACA,MAAM,gCAAgB,IAAI,KAAkC;AAC5D,OAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,EAAE;GAC3C,MAAM,UAAU,OAAO,aACpB,KAAK,eAAe,EAAE,EAAE,KAAK,MAAM,CAAC,GAAG,aAAa,CAAC,CACvD;GACD,MAAM,QAAQ,cAAc,IAAI,KAAK,OAAO,IAAI,EAAE;AAClD,SAAM,KAAK;IACT,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;IAC3C,WAAW,CAAC,EAAE,SAAS,CAAC;IACzB,CAAC;AACF,iBAAc,IAAI,KAAK,QAAQ,MAAM;;AAEvC,OAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE,EAAE;GACzC,MAAM,QAAQ,cAAc,IAAI,KAAK,OAAO,IAAI,EAAE;AAClD,SAAM,KAAK;IACT,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;IAC3C,YAAY,KAAK;IAClB,CAAC;AACF,iBAAc,IAAI,KAAK,QAAQ,MAAM;;EAGvC,MAAMA,QAA6C,EAAE;AACrD,OAAK,MAAM,UAAU,IAAI,kBAAkB,EAAE,CAC3C,OAAM,UAAU,cAAc,IAAI,OAAO,IAAI,EAAE;AAGjD,OAAK,MAAM,QAAQ,CAAC,GAAI,IAAI,kBAAkB,EAAE,EAAG,GAAI,IAAI,gBAAgB,EAAE,CAAE,CAC7E,KAAI,EAAE,KAAK,UAAU,OACnB,OAAM,KAAK,UAAU,cAAc,IAAI,KAAK,OAAO,IAAI,EAAE;AAI7D,SAAO;GAAE;GAAO,GAAG;GAAS;;AAG9B,QAAO;EACL,GAAI,IAAI,kBAAkB,EAAE,OAAO,IAAI,gBAAgB;EACvD,GAAG;EACJ"}
|
|
@@ -1,52 +1,36 @@
|
|
|
1
1
|
//#region src/utils/network-policy.ts
|
|
2
2
|
function toAPINetworkPolicy(policy) {
|
|
3
|
-
if (policy === "allow-all") return { mode:
|
|
4
|
-
|
|
5
|
-
if (policy.allow && !Array.isArray(policy.allow)) {
|
|
6
|
-
const allowedDomains = Object.keys(policy.allow);
|
|
7
|
-
const injectionRules = [];
|
|
8
|
-
for (const [domain, rules] of Object.entries(policy.allow)) {
|
|
9
|
-
const merged = {};
|
|
10
|
-
for (const rule of rules) for (const t of rule.transform ?? []) Object.assign(merged, t.headers);
|
|
11
|
-
if (Object.keys(merged).length > 0) injectionRules.push({
|
|
12
|
-
domain,
|
|
13
|
-
headers: merged
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
return {
|
|
17
|
-
mode: "custom",
|
|
18
|
-
...allowedDomains.length > 0 && { allowedDomains },
|
|
19
|
-
...injectionRules.length > 0 && { injectionRules },
|
|
20
|
-
...policy.subnets?.allow && { allowedCIDRs: policy.subnets.allow },
|
|
21
|
-
...policy.subnets?.deny && { deniedCIDRs: policy.subnets.deny }
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
mode: "custom",
|
|
26
|
-
...policy.allow && { allowedDomains: policy.allow },
|
|
27
|
-
...policy.subnets?.allow && { allowedCIDRs: policy.subnets.allow },
|
|
28
|
-
...policy.subnets?.deny && { deniedCIDRs: policy.subnets.deny }
|
|
29
|
-
};
|
|
3
|
+
if (policy === "allow-all" || policy === "deny-all") return { mode: policy };
|
|
4
|
+
return policy;
|
|
30
5
|
}
|
|
31
6
|
function fromAPINetworkPolicy(api) {
|
|
32
|
-
if (api.mode === "allow-all"
|
|
33
|
-
if (api.mode === "deny-all") return "deny-all";
|
|
7
|
+
if (api.mode === "allow-all" || api.mode === "deny-all") return api.mode;
|
|
34
8
|
const subnets = api.allowedCIDRs || api.deniedCIDRs ? { subnets: {
|
|
35
9
|
...api.allowedCIDRs && { allow: api.allowedCIDRs },
|
|
36
10
|
...api.deniedCIDRs && { deny: api.deniedCIDRs }
|
|
37
11
|
} } : void 0;
|
|
38
|
-
if (api.injectionRules && api.injectionRules.length > 0) {
|
|
39
|
-
const rulesByDomain = new Map(
|
|
40
|
-
const
|
|
41
|
-
for (const domain of api.allowedDomains ?? []) {
|
|
42
|
-
const headerNames = rulesByDomain.get(domain);
|
|
43
|
-
if (headerNames && headerNames.length > 0) allow[domain] = [{ transform: [{ headers: Object.fromEntries(headerNames.map((n) => [n, "<redacted>"])) }] }];
|
|
44
|
-
else allow[domain] = [];
|
|
45
|
-
}
|
|
46
|
-
for (const rule of api.injectionRules) if (!(rule.domain in allow)) {
|
|
12
|
+
if (api.injectionRules && api.injectionRules.length > 0 || api.forwardRules && api.forwardRules.length > 0) {
|
|
13
|
+
const rulesByDomain = /* @__PURE__ */ new Map();
|
|
14
|
+
for (const rule of api.injectionRules ?? []) {
|
|
47
15
|
const headers = Object.fromEntries((rule.headerNames ?? []).map((n) => [n, "<redacted>"]));
|
|
48
|
-
|
|
16
|
+
const rules = rulesByDomain.get(rule.domain) ?? [];
|
|
17
|
+
rules.push({
|
|
18
|
+
...rule.match ? { match: rule.match } : {},
|
|
19
|
+
transform: [{ headers }]
|
|
20
|
+
});
|
|
21
|
+
rulesByDomain.set(rule.domain, rules);
|
|
49
22
|
}
|
|
23
|
+
for (const rule of api.forwardRules ?? []) {
|
|
24
|
+
const rules = rulesByDomain.get(rule.domain) ?? [];
|
|
25
|
+
rules.push({
|
|
26
|
+
...rule.match ? { match: rule.match } : {},
|
|
27
|
+
forwardURL: rule.forwardURL
|
|
28
|
+
});
|
|
29
|
+
rulesByDomain.set(rule.domain, rules);
|
|
30
|
+
}
|
|
31
|
+
const allow = {};
|
|
32
|
+
for (const domain of api.allowedDomains ?? []) allow[domain] = rulesByDomain.get(domain) ?? [];
|
|
33
|
+
for (const rule of [...api.injectionRules ?? [], ...api.forwardRules ?? []]) if (!(rule.domain in allow)) allow[rule.domain] = rulesByDomain.get(rule.domain) ?? [];
|
|
50
34
|
return {
|
|
51
35
|
allow,
|
|
52
36
|
...subnets
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-policy.js","names":["
|
|
1
|
+
{"version":3,"file":"network-policy.js","names":["allow: Record<string, NetworkPolicyRule[]>"],"sources":["../../src/utils/network-policy.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { NetworkPolicy, NetworkPolicyRule } from \"../network-policy.js\";\nimport {\n NetworkPolicyRequestValidator,\n NetworkPolicyResponseValidator,\n} from \"../api-client/validators.js\";\n\ntype APIRequestNetworkPolicy = z.infer<typeof NetworkPolicyRequestValidator>;\ntype APIResponseNetworkPolicy = z.infer<typeof NetworkPolicyResponseValidator>;\n\nexport function toAPINetworkPolicy(\n policy: NetworkPolicy,\n): APIRequestNetworkPolicy {\n if (policy === \"allow-all\" || policy === \"deny-all\") {\n return { mode: policy };\n }\n\n return policy;\n}\n\nexport function fromAPINetworkPolicy(\n api: APIResponseNetworkPolicy,\n): NetworkPolicy {\n if (api.mode === \"allow-all\" || api.mode === \"deny-all\") {\n return api.mode;\n }\n\n const subnets =\n api.allowedCIDRs || api.deniedCIDRs\n ? {\n subnets: {\n ...(api.allowedCIDRs && { allow: api.allowedCIDRs }),\n ...(api.deniedCIDRs && { deny: api.deniedCIDRs }),\n },\n }\n : undefined;\n\n // If L7 rules are present, reconstruct the record form.\n // The API returns headerNames (secret values are stripped), so we\n // populate each header value with \"<redacted>\".\n if (\n (api.injectionRules && api.injectionRules.length > 0) ||\n (api.forwardRules && api.forwardRules.length > 0)\n ) {\n const rulesByDomain = new Map<string, NetworkPolicyRule[]>();\n for (const rule of api.injectionRules ?? []) {\n const headers = Object.fromEntries(\n (rule.headerNames ?? []).map((n) => [n, \"<redacted>\"]),\n );\n const rules = rulesByDomain.get(rule.domain) ?? [];\n rules.push({\n ...(rule.match ? { match: rule.match } : {}),\n transform: [{ headers }],\n });\n rulesByDomain.set(rule.domain, rules);\n }\n for (const rule of api.forwardRules ?? []) {\n const rules = rulesByDomain.get(rule.domain) ?? [];\n rules.push({\n ...(rule.match ? { match: rule.match } : {}),\n forwardURL: rule.forwardURL,\n });\n rulesByDomain.set(rule.domain, rules);\n }\n\n const allow: Record<string, NetworkPolicyRule[]> = {};\n for (const domain of api.allowedDomains ?? []) {\n allow[domain] = rulesByDomain.get(domain) ?? [];\n }\n // Include L7 rules for domains not in allowedDomains\n for (const rule of [...(api.injectionRules ?? []), ...(api.forwardRules ?? [])]) {\n if (!(rule.domain in allow)) {\n allow[rule.domain] = rulesByDomain.get(rule.domain) ?? [];\n }\n }\n\n return { allow, ...subnets };\n }\n\n return {\n ...(api.allowedDomains && { allow: api.allowedDomains }),\n ...subnets,\n };\n}\n"],"mappings":";AAUA,SAAgB,mBACd,QACyB;AACzB,KAAI,WAAW,eAAe,WAAW,WACvC,QAAO,EAAE,MAAM,QAAQ;AAGzB,QAAO;;AAGT,SAAgB,qBACd,KACe;AACf,KAAI,IAAI,SAAS,eAAe,IAAI,SAAS,WAC3C,QAAO,IAAI;CAGb,MAAM,UACJ,IAAI,gBAAgB,IAAI,cACpB,EACE,SAAS;EACP,GAAI,IAAI,gBAAgB,EAAE,OAAO,IAAI,cAAc;EACnD,GAAI,IAAI,eAAe,EAAE,MAAM,IAAI,aAAa;EACjD,EACF,GACD;AAKN,KACG,IAAI,kBAAkB,IAAI,eAAe,SAAS,KAClD,IAAI,gBAAgB,IAAI,aAAa,SAAS,GAC/C;EACA,MAAM,gCAAgB,IAAI,KAAkC;AAC5D,OAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,EAAE;GAC3C,MAAM,UAAU,OAAO,aACpB,KAAK,eAAe,EAAE,EAAE,KAAK,MAAM,CAAC,GAAG,aAAa,CAAC,CACvD;GACD,MAAM,QAAQ,cAAc,IAAI,KAAK,OAAO,IAAI,EAAE;AAClD,SAAM,KAAK;IACT,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;IAC3C,WAAW,CAAC,EAAE,SAAS,CAAC;IACzB,CAAC;AACF,iBAAc,IAAI,KAAK,QAAQ,MAAM;;AAEvC,OAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE,EAAE;GACzC,MAAM,QAAQ,cAAc,IAAI,KAAK,OAAO,IAAI,EAAE;AAClD,SAAM,KAAK;IACT,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;IAC3C,YAAY,KAAK;IAClB,CAAC;AACF,iBAAc,IAAI,KAAK,QAAQ,MAAM;;EAGvC,MAAMA,QAA6C,EAAE;AACrD,OAAK,MAAM,UAAU,IAAI,kBAAkB,EAAE,CAC3C,OAAM,UAAU,cAAc,IAAI,OAAO,IAAI,EAAE;AAGjD,OAAK,MAAM,QAAQ,CAAC,GAAI,IAAI,kBAAkB,EAAE,EAAG,GAAI,IAAI,gBAAgB,EAAE,CAAE,CAC7E,KAAI,EAAE,KAAK,UAAU,OACnB,OAAM,KAAK,UAAU,cAAc,IAAI,KAAK,OAAO,IAAI,EAAE;AAI7D,SAAO;GAAE;GAAO,GAAG;GAAS;;AAG9B,QAAO;EACL,GAAI,IAAI,kBAAkB,EAAE,OAAO,IAAI,gBAAgB;EACvD,GAAG;EACJ"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/paginator.ts
|
|
3
|
+
function attachPaginator(firstPage, options) {
|
|
4
|
+
const { itemsKey, fetchNext, signal } = options;
|
|
5
|
+
async function* iteratePages() {
|
|
6
|
+
throwIfAborted(signal);
|
|
7
|
+
let page = firstPage;
|
|
8
|
+
yield page;
|
|
9
|
+
while (page.pagination.next !== null) {
|
|
10
|
+
throwIfAborted(signal);
|
|
11
|
+
page = await fetchNext(page.pagination.next);
|
|
12
|
+
yield page;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function* iterateItems() {
|
|
16
|
+
for await (const page of iteratePages()) {
|
|
17
|
+
const items = page[itemsKey];
|
|
18
|
+
for (const item of items) {
|
|
19
|
+
throwIfAborted(signal);
|
|
20
|
+
yield item;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
...firstPage,
|
|
26
|
+
[Symbol.asyncIterator]: iterateItems,
|
|
27
|
+
pages: iteratePages,
|
|
28
|
+
toArray: async () => {
|
|
29
|
+
const all = [];
|
|
30
|
+
for await (const item of iterateItems()) all.push(item);
|
|
31
|
+
return all;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function throwIfAborted(signal) {
|
|
36
|
+
if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
exports.attachPaginator = attachPaginator;
|
|
41
|
+
//# sourceMappingURL=paginator.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginator.cjs","names":["all: ItemOf<Page, Key>[]"],"sources":["../../src/utils/paginator.ts"],"sourcesContent":["type CursorPaginationMeta = {\n count: number;\n next: string | null;\n};\n\ntype HasPagination = { pagination: CursorPaginationMeta };\n\ntype ItemOf<Page, Key extends keyof Page> = Page[Key] extends Array<infer Item>\n ? Item\n : never;\n\nexport type Paginator<Page extends HasPagination, Key extends keyof Page> =\n Page &\n AsyncIterable<ItemOf<Page, Key>> & {\n pages(): AsyncIterable<Page>;\n toArray(): Promise<ItemOf<Page, Key>[]>;\n };\n\ntype AttachPaginatorOptions<Page extends HasPagination, Key extends keyof Page> = {\n itemsKey: Key;\n fetchNext: (cursor: string) => Promise<Page>;\n signal?: AbortSignal;\n};\n\nexport function attachPaginator<\n Page extends HasPagination,\n Key extends keyof Page,\n>(\n firstPage: Page,\n options: AttachPaginatorOptions<Page, Key>,\n): Paginator<Page, Key> {\n const { itemsKey, fetchNext, signal } = options;\n\n async function* iteratePages(): AsyncGenerator<Page> {\n throwIfAborted(signal);\n let page = firstPage;\n yield page;\n while (page.pagination.next !== null) {\n throwIfAborted(signal);\n page = await fetchNext(page.pagination.next);\n yield page;\n }\n }\n\n async function* iterateItems(): AsyncGenerator<ItemOf<Page, Key>> {\n for await (const page of iteratePages()) {\n const items = page[itemsKey] as unknown as ItemOf<Page, Key>[];\n for (const item of items) {\n throwIfAborted(signal);\n yield item;\n }\n }\n }\n\n return {\n ...firstPage,\n [Symbol.asyncIterator]: iterateItems,\n pages: iteratePages,\n toArray: async () => {\n const all: ItemOf<Page, Key>[] = [];\n for await (const item of iterateItems()) {\n all.push(item);\n }\n return all;\n },\n };\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n }\n}\n"],"mappings":";;AAwBA,SAAgB,gBAId,WACA,SACsB;CACtB,MAAM,EAAE,UAAU,WAAW,WAAW;CAExC,gBAAgB,eAAqC;AACnD,iBAAe,OAAO;EACtB,IAAI,OAAO;AACX,QAAM;AACN,SAAO,KAAK,WAAW,SAAS,MAAM;AACpC,kBAAe,OAAO;AACtB,UAAO,MAAM,UAAU,KAAK,WAAW,KAAK;AAC5C,SAAM;;;CAIV,gBAAgB,eAAkD;AAChE,aAAW,MAAM,QAAQ,cAAc,EAAE;GACvC,MAAM,QAAQ,KAAK;AACnB,QAAK,MAAM,QAAQ,OAAO;AACxB,mBAAe,OAAO;AACtB,UAAM;;;;AAKZ,QAAO;EACL,GAAG;GACF,OAAO,gBAAgB;EACxB,OAAO;EACP,SAAS,YAAY;GACnB,MAAMA,MAA2B,EAAE;AACnC,cAAW,MAAM,QAAQ,cAAc,CACrC,KAAI,KAAK,KAAK;AAEhB,UAAO;;EAEV;;AAGH,SAAS,eAAe,QAA4B;AAClD,KAAI,QAAQ,QACV,OAAM,OAAO,UAAU,IAAI,aAAa,WAAW,aAAa"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/utils/paginator.d.ts
|
|
2
|
+
type CursorPaginationMeta = {
|
|
3
|
+
count: number;
|
|
4
|
+
next: string | null;
|
|
5
|
+
};
|
|
6
|
+
type HasPagination = {
|
|
7
|
+
pagination: CursorPaginationMeta;
|
|
8
|
+
};
|
|
9
|
+
type ItemOf<Page, Key extends keyof Page> = Page[Key] extends Array<infer Item> ? Item : never;
|
|
10
|
+
type Paginator<Page extends HasPagination, Key extends keyof Page> = Page & AsyncIterable<ItemOf<Page, Key>> & {
|
|
11
|
+
pages(): AsyncIterable<Page>;
|
|
12
|
+
toArray(): Promise<ItemOf<Page, Key>[]>;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Paginator };
|
|
16
|
+
//# sourceMappingURL=paginator.d.cts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/utils/paginator.d.ts
|
|
2
|
+
type CursorPaginationMeta = {
|
|
3
|
+
count: number;
|
|
4
|
+
next: string | null;
|
|
5
|
+
};
|
|
6
|
+
type HasPagination = {
|
|
7
|
+
pagination: CursorPaginationMeta;
|
|
8
|
+
};
|
|
9
|
+
type ItemOf<Page, Key extends keyof Page> = Page[Key] extends Array<infer Item> ? Item : never;
|
|
10
|
+
type Paginator<Page extends HasPagination, Key extends keyof Page> = Page & AsyncIterable<ItemOf<Page, Key>> & {
|
|
11
|
+
pages(): AsyncIterable<Page>;
|
|
12
|
+
toArray(): Promise<ItemOf<Page, Key>[]>;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Paginator };
|
|
16
|
+
//# sourceMappingURL=paginator.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/utils/paginator.ts
|
|
2
|
+
function attachPaginator(firstPage, options) {
|
|
3
|
+
const { itemsKey, fetchNext, signal } = options;
|
|
4
|
+
async function* iteratePages() {
|
|
5
|
+
throwIfAborted(signal);
|
|
6
|
+
let page = firstPage;
|
|
7
|
+
yield page;
|
|
8
|
+
while (page.pagination.next !== null) {
|
|
9
|
+
throwIfAborted(signal);
|
|
10
|
+
page = await fetchNext(page.pagination.next);
|
|
11
|
+
yield page;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async function* iterateItems() {
|
|
15
|
+
for await (const page of iteratePages()) {
|
|
16
|
+
const items = page[itemsKey];
|
|
17
|
+
for (const item of items) {
|
|
18
|
+
throwIfAborted(signal);
|
|
19
|
+
yield item;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
...firstPage,
|
|
25
|
+
[Symbol.asyncIterator]: iterateItems,
|
|
26
|
+
pages: iteratePages,
|
|
27
|
+
toArray: async () => {
|
|
28
|
+
const all = [];
|
|
29
|
+
for await (const item of iterateItems()) all.push(item);
|
|
30
|
+
return all;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function throwIfAborted(signal) {
|
|
35
|
+
if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { attachPaginator };
|
|
40
|
+
//# sourceMappingURL=paginator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginator.js","names":["all: ItemOf<Page, Key>[]"],"sources":["../../src/utils/paginator.ts"],"sourcesContent":["type CursorPaginationMeta = {\n count: number;\n next: string | null;\n};\n\ntype HasPagination = { pagination: CursorPaginationMeta };\n\ntype ItemOf<Page, Key extends keyof Page> = Page[Key] extends Array<infer Item>\n ? Item\n : never;\n\nexport type Paginator<Page extends HasPagination, Key extends keyof Page> =\n Page &\n AsyncIterable<ItemOf<Page, Key>> & {\n pages(): AsyncIterable<Page>;\n toArray(): Promise<ItemOf<Page, Key>[]>;\n };\n\ntype AttachPaginatorOptions<Page extends HasPagination, Key extends keyof Page> = {\n itemsKey: Key;\n fetchNext: (cursor: string) => Promise<Page>;\n signal?: AbortSignal;\n};\n\nexport function attachPaginator<\n Page extends HasPagination,\n Key extends keyof Page,\n>(\n firstPage: Page,\n options: AttachPaginatorOptions<Page, Key>,\n): Paginator<Page, Key> {\n const { itemsKey, fetchNext, signal } = options;\n\n async function* iteratePages(): AsyncGenerator<Page> {\n throwIfAborted(signal);\n let page = firstPage;\n yield page;\n while (page.pagination.next !== null) {\n throwIfAborted(signal);\n page = await fetchNext(page.pagination.next);\n yield page;\n }\n }\n\n async function* iterateItems(): AsyncGenerator<ItemOf<Page, Key>> {\n for await (const page of iteratePages()) {\n const items = page[itemsKey] as unknown as ItemOf<Page, Key>[];\n for (const item of items) {\n throwIfAborted(signal);\n yield item;\n }\n }\n }\n\n return {\n ...firstPage,\n [Symbol.asyncIterator]: iterateItems,\n pages: iteratePages,\n toArray: async () => {\n const all: ItemOf<Page, Key>[] = [];\n for await (const item of iterateItems()) {\n all.push(item);\n }\n return all;\n },\n };\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n }\n}\n"],"mappings":";AAwBA,SAAgB,gBAId,WACA,SACsB;CACtB,MAAM,EAAE,UAAU,WAAW,WAAW;CAExC,gBAAgB,eAAqC;AACnD,iBAAe,OAAO;EACtB,IAAI,OAAO;AACX,QAAM;AACN,SAAO,KAAK,WAAW,SAAS,MAAM;AACpC,kBAAe,OAAO;AACtB,UAAO,MAAM,UAAU,KAAK,WAAW,KAAK;AAC5C,SAAM;;;CAIV,gBAAgB,eAAkD;AAChE,aAAW,MAAM,QAAQ,cAAc,EAAE;GACvC,MAAM,QAAQ,KAAK;AACnB,QAAK,MAAM,QAAQ,OAAO;AACxB,mBAAe,OAAO;AACtB,UAAM;;;;AAKZ,QAAO;EACL,GAAG;GACF,OAAO,gBAAgB;EACxB,OAAO;EACP,SAAS,YAAY;GACnB,MAAMA,MAA2B,EAAE;AACnC,cAAW,MAAM,QAAQ,cAAc,CACrC,KAAI,KAAK,KAAK;AAEhB,UAAO;;EAEV;;AAGH,SAAS,eAAe,QAA4B;AAClD,KAAI,QAAQ,QACV,OAAM,OAAO,UAAU,IAAI,aAAa,WAAW,aAAa"}
|
package/dist/version.cjs
CHANGED
package/dist/version.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.cjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Autogenerated by inject-version.ts\nexport const VERSION = \"2.0.0-beta.
|
|
1
|
+
{"version":3,"file":"version.cjs","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Autogenerated by inject-version.ts\nexport const VERSION = \"2.0.0-beta.18\";\n"],"mappings":";;AACA,MAAa,UAAU"}
|
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Autogenerated by inject-version.ts\nexport const VERSION = \"2.0.0-beta.
|
|
1
|
+
{"version":3,"file":"version.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["// Autogenerated by inject-version.ts\nexport const VERSION = \"2.0.0-beta.18\";\n"],"mappings":";AACA,MAAa,UAAU"}
|