init
This commit is contained in:
10
.u8.json
10
.u8.json
@@ -96,6 +96,16 @@
|
|||||||
"packageVersion": "1.0.0",
|
"packageVersion": "1.0.0",
|
||||||
"packageName": "bootstrap"
|
"packageName": "bootstrap"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2025-10-23T12:52:15.389Z",
|
||||||
|
"template": "pkg",
|
||||||
|
"values": {
|
||||||
|
"monoRepo": true,
|
||||||
|
"packagePrefix": "@morten-olsen/box-",
|
||||||
|
"packageVersion": "1.0.0",
|
||||||
|
"packageName": "resource-cloudflare"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,39 @@
|
|||||||
import { KubeConfig } from '@kubernetes/client-node';
|
import { ApiextensionsV1Api, CustomObjectsApi, KubeConfig, KubernetesObjectApi } from '@kubernetes/client-node';
|
||||||
|
class K8sConfig {
|
||||||
|
#config: KubeConfig;
|
||||||
|
#objectsApi?: KubernetesObjectApi;
|
||||||
|
#customObjectsApi?: CustomObjectsApi;
|
||||||
|
#extensionsApi?: ApiextensionsV1Api;
|
||||||
|
|
||||||
class K8sConfig extends KubeConfig {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
this.#config = new KubeConfig();
|
||||||
this.loadFromDefault();
|
this.#config.loadFromDefault();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public get kubeConfig() {
|
||||||
|
return this.#config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get objectsApi() {
|
||||||
|
if (!this.#objectsApi) {
|
||||||
|
this.#objectsApi = this.#config.makeApiClient(KubernetesObjectApi)
|
||||||
|
}
|
||||||
|
return this.#objectsApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get customObjectsApi() {
|
||||||
|
if (!this.#customObjectsApi) {
|
||||||
|
this.#customObjectsApi = this.#config.makeApiClient(CustomObjectsApi);
|
||||||
|
}
|
||||||
|
return this.#customObjectsApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get extensionsApi() {
|
||||||
|
if (!this.#extensionsApi) {
|
||||||
|
this.#extensionsApi = this.#config.makeApiClient(ApiextensionsV1Api)
|
||||||
|
}
|
||||||
|
return this.#extensionsApi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1CustomResourceDefinition } from '@kubernetes/client-node';
|
import type { V1CustomResourceDefinition } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class CRD extends Resource<V1CustomResourceDefinition> {
|
class CRD extends Resource<V1CustomResourceDefinition> {
|
||||||
public static readonly apiVersion = 'apiextensions.k8s.io/v1';
|
public static readonly apiVersion = 'apiextensions.k8s.io/v1';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1Deployment } from '@kubernetes/client-node';
|
import type { V1Deployment } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class Deployment extends Resource<V1Deployment> {
|
class Deployment extends Resource<V1Deployment> {
|
||||||
public static readonly apiVersion = 'apps/v1';
|
public static readonly apiVersion = 'apps/v1';
|
||||||
public static readonly kind = 'Deployment';
|
public static readonly kind = 'Deployment';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1Namespace } from '@kubernetes/client-node';
|
import type { V1Namespace } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class Namespace extends Resource<V1Namespace> {
|
class Namespace extends Resource<V1Namespace> {
|
||||||
public static readonly apiVersion = 'v1';
|
public static readonly apiVersion = 'v1';
|
||||||
public static readonly kind = 'Namespace';
|
public static readonly kind = 'Namespace';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1PersistentVolume } from '@kubernetes/client-node';
|
import type { V1PersistentVolume } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class PersistentVolume extends Resource<V1PersistentVolume> {
|
class PersistentVolume extends Resource<V1PersistentVolume> {
|
||||||
public static readonly apiVersion = 'v1';
|
public static readonly apiVersion = 'v1';
|
||||||
public static readonly kind = 'PersistentVolume';
|
public static readonly kind = 'PersistentVolume';
|
||||||
|
|||||||
@@ -1,23 +1,19 @@
|
|||||||
import { Resource, type ResourceOptions } from '../resources/resource/resource.js';
|
|
||||||
import type { KubernetesObject, V1Secret } from '@kubernetes/client-node';
|
import type { KubernetesObject, V1Secret } from '@kubernetes/client-node';
|
||||||
import { decodeSecret, encodeSecret } from '../utils/utils.secrets.js';
|
|
||||||
|
|
||||||
|
import { decodeSecret, encodeSecret } from '../utils/utils.secrets.js';
|
||||||
|
import { Resource } from '../exports.js';
|
||||||
|
|
||||||
type SetOptions<T extends Record<string, string | undefined>> = T | ((current: T | undefined) => T | Promise<T>);
|
type SetOptions<T extends Record<string, string | undefined>> = T | ((current: T | undefined) => T | Promise<T>);
|
||||||
|
|
||||||
class Secret<T extends Record<string, string> = Record<string, string>> extends Resource<V1Secret> {
|
class Secret extends Resource<V1Secret> {
|
||||||
public static readonly apiVersion = 'v1';
|
public static readonly apiVersion = 'v1';
|
||||||
public static readonly kind = 'Secret';
|
public static readonly kind = 'Secret';
|
||||||
|
|
||||||
constructor(options: ResourceOptions<V1Secret>) {
|
|
||||||
super(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get value() {
|
public get value() {
|
||||||
return decodeSecret(this.data) as T | undefined;
|
return decodeSecret(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public set = async (options: SetOptions<T>, data?: KubernetesObject) => {
|
public set = async (options: SetOptions<Record<string, string>>, data?: KubernetesObject) => {
|
||||||
const value = typeof options === 'function' ? await Promise.resolve(options(this.value)) : options;
|
const value = typeof options === 'function' ? await Promise.resolve(options(this.value)) : options;
|
||||||
await this.ensure({
|
await this.ensure({
|
||||||
...data,
|
...data,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1Service } from '@kubernetes/client-node';
|
import type { V1Service } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class Service extends Resource<V1Service> {
|
class Service extends Resource<V1Service> {
|
||||||
public static readonly apiVersion = 'v1';
|
public static readonly apiVersion = 'v1';
|
||||||
public static readonly kind = 'Service';
|
public static readonly kind = 'Service';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1StatefulSet } from '@kubernetes/client-node';
|
import type { V1StatefulSet } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class StatefulSet extends Resource<V1StatefulSet> {
|
class StatefulSet extends Resource<V1StatefulSet> {
|
||||||
public static readonly apiVersion = 'apps/v1';
|
public static readonly apiVersion = 'apps/v1';
|
||||||
public static readonly kind = 'StatefulSet';
|
public static readonly kind = 'StatefulSet';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Resource } from '../resources/resource/resource.js';
|
|
||||||
import type { V1StorageClass } from '@kubernetes/client-node';
|
import type { V1StorageClass } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
import { Resource } from '../resources/resource/resource.js';
|
||||||
|
|
||||||
class StorageClass extends Resource<V1StorageClass> {
|
class StorageClass extends Resource<V1StorageClass> {
|
||||||
public static readonly apiVersion = 'storage.k8s.io/v1';
|
public static readonly apiVersion = 'storage.k8s.io/v1';
|
||||||
public static readonly kind = 'StorageClass';
|
public static readonly kind = 'StorageClass';
|
||||||
|
|||||||
@@ -1,19 +1,10 @@
|
|||||||
import { CRD } from "./core.crd.js";
|
import { CRD } from './core.crd.js';
|
||||||
import { Deployment } from "./core.deployment.js";
|
import { Deployment } from './core.deployment.js';
|
||||||
import { Namespace } from "./core.namespace.js";
|
import { Namespace } from './core.namespace.js';
|
||||||
import { PersistentVolume } from "./core.pv.js";
|
import { PersistentVolume } from './core.pv.js';
|
||||||
import { Secret } from "./core.secret.js";
|
import { Secret } from './core.secret.js';
|
||||||
import { Service } from "./core.service.js";
|
import { Service } from './core.service.js';
|
||||||
import { StatefulSet } from "./core.stateful-set.js";
|
import { StatefulSet } from './core.stateful-set.js';
|
||||||
import { StorageClass } from "./core.storage-class.js";
|
import { StorageClass } from './core.storage-class.js';
|
||||||
|
|
||||||
export {
|
export { CRD, Deployment, Namespace, PersistentVolume, Secret, Service, StatefulSet, StorageClass };
|
||||||
CRD,
|
|
||||||
Deployment,
|
|
||||||
Namespace,
|
|
||||||
PersistentVolume,
|
|
||||||
Secret,
|
|
||||||
Service,
|
|
||||||
StatefulSet,
|
|
||||||
StorageClass,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Services } from '@morten-olsen/box-utils/services';
|
import { Services } from '@morten-olsen/box-utils/services';
|
||||||
|
|
||||||
import { ResourceService } from './resources/resources.js';
|
import { ResourceService } from './resources/resources.js';
|
||||||
|
|
||||||
class K8sOperator {
|
class K8sOperator {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { z, type ZodType } from 'zod';
|
import { z, type ZodType } from 'zod';
|
||||||
import { CustomObjectsApi, PatchStrategy, setHeaderOptions, type KubernetesObject } from '@kubernetes/client-node';
|
import { PatchStrategy, setHeaderOptions, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import { CronJob, CronTime } from 'cron';
|
import { CronJob, CronTime } from 'cron';
|
||||||
|
|
||||||
import { K8sConfig } from '../../config/config.js';
|
|
||||||
|
|
||||||
import { CoalescingQueue } from '@morten-olsen/box-utils/coalescing-queue';
|
import { CoalescingQueue } from '@morten-olsen/box-utils/coalescing-queue';
|
||||||
|
import { FINALIZER } from '@morten-olsen/box-utils/consts';
|
||||||
|
|
||||||
|
import { NotReadyError } from '../../errors/errors.js';
|
||||||
|
|
||||||
import { Resource, type ResourceOptions } from './resource.js';
|
import { Resource, type ResourceOptions } from './resource.js';
|
||||||
import { NotReadyError } from '../../errors/errors.js'
|
import { K8sConfig } from '../../config/config.js';
|
||||||
|
import type { ResourceClass } from '../resources.service.js';
|
||||||
|
|
||||||
const customResourceStatusSchema = z.object({
|
const customResourceStatusSchema = z.object({
|
||||||
observedGeneration: z.number().optional(),
|
observedGeneration: z.number().optional(),
|
||||||
@@ -35,7 +37,7 @@ class CustomResource<TSpec extends ZodType> extends Resource<
|
|||||||
public static readonly apiVersion: string;
|
public static readonly apiVersion: string;
|
||||||
public static readonly status = customResourceStatusSchema;
|
public static readonly status = customResourceStatusSchema;
|
||||||
public static readonly labels: Record<string, string> = {};
|
public static readonly labels: Record<string, string> = {};
|
||||||
public static readonly dependsOn?: Resource<KubernetesObject>[];
|
public static readonly dependsOn?: ResourceClass<ExplicitAny>[];
|
||||||
|
|
||||||
#reconcileQueue: CoalescingQueue<void>;
|
#reconcileQueue: CoalescingQueue<void>;
|
||||||
#cron: CronJob;
|
#cron: CronJob;
|
||||||
@@ -45,9 +47,31 @@ class CustomResource<TSpec extends ZodType> extends Resource<
|
|||||||
this.#reconcileQueue = new CoalescingQueue({
|
this.#reconcileQueue = new CoalescingQueue({
|
||||||
action: async () => {
|
action: async () => {
|
||||||
try {
|
try {
|
||||||
if (!this.exists || this.manifest?.metadata?.deletionTimestamp) {
|
if (!this.exists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// TODO: Read FINALIZER
|
||||||
|
// const finalizers = this.metadata?.finalizers || [];
|
||||||
|
if (this.manifest?.metadata?.deletionTimestamp) {
|
||||||
|
await this.destroy?.();
|
||||||
|
// if (this.metadata?.finalizers?.includes(FINALIZER)) {
|
||||||
|
// await this.patch({
|
||||||
|
// metadata: {
|
||||||
|
// finalizers: finalizers.filter((f) => f !== FINALIZER),
|
||||||
|
// deletionTimestamp: this.metadata?.deletionTimestamp,
|
||||||
|
// },
|
||||||
|
// } as any)
|
||||||
|
// }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if (this.destroy && !finalizers.includes(FINALIZER)) {
|
||||||
|
// return await this.patch({
|
||||||
|
// metadata: {
|
||||||
|
// finalizers: [...finalizers, FINALIZER]
|
||||||
|
// },
|
||||||
|
// spec: this.spec!,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
await this.markSeen();
|
await this.markSeen();
|
||||||
await this.reconcile?.();
|
await this.reconcile?.();
|
||||||
await this.markReady();
|
await this.markReady();
|
||||||
@@ -111,6 +135,8 @@ class CustomResource<TSpec extends ZodType> extends Resource<
|
|||||||
};
|
};
|
||||||
|
|
||||||
public reconcile?: () => Promise<void>;
|
public reconcile?: () => Promise<void>;
|
||||||
|
public destroy?: () => Promise<void>;
|
||||||
|
|
||||||
public queueReconcile = () => {
|
public queueReconcile = () => {
|
||||||
return this.#reconcileQueue.run();
|
return this.#reconcileQueue.run();
|
||||||
};
|
};
|
||||||
@@ -151,7 +177,7 @@ class CustomResource<TSpec extends ZodType> extends Resource<
|
|||||||
public patchStatus = (status: Partial<z.infer<typeof customResourceStatusSchema>>) =>
|
public patchStatus = (status: Partial<z.infer<typeof customResourceStatusSchema>>) =>
|
||||||
this.queue.add(async () => {
|
this.queue.add(async () => {
|
||||||
const config = this.services.get(K8sConfig);
|
const config = this.services.get(K8sConfig);
|
||||||
const customObjectsApi = config.makeApiClient(CustomObjectsApi);
|
const customObjectsApi = config.customObjectsApi;
|
||||||
if (this.scope === 'Cluster') {
|
if (this.scope === 'Cluster') {
|
||||||
await customObjectsApi.patchClusterCustomObjectStatus(
|
await customObjectsApi.patchClusterCustomObjectStatus(
|
||||||
{
|
{
|
||||||
@@ -180,4 +206,3 @@ class CustomResource<TSpec extends ZodType> extends Resource<
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { CustomResource, type CustomResourceOptions };
|
export { CustomResource, type CustomResourceOptions };
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
||||||
|
|
||||||
import type { ResourceClass } from '../resources.js';
|
import type { ResourceClass } from '../resources.js';
|
||||||
|
|
||||||
import type { ResourceEvents } from './resource.js';
|
import type { ResourceEvents } from './resource.js';
|
||||||
@@ -19,6 +20,9 @@ class ResourceReference<T extends ResourceClass<ExplicitAny>> extends EventEmitt
|
|||||||
}
|
}
|
||||||
|
|
||||||
public set current(value: InstanceType<T> | undefined) {
|
public set current(value: InstanceType<T> | undefined) {
|
||||||
|
if (value === this.#current?.instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const previous = this.#current;
|
const previous = this.#current;
|
||||||
this.#current?.unsubscribe();
|
this.#current?.unsubscribe();
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { ApiException, KubernetesObjectApi, PatchStrategy, type KubernetesObject } from '@kubernetes/client-node';
|
import { ApiException, KubernetesObjectApi, PatchStrategy, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
|
|
||||||
import { ResourceService } from '../resources.service.js';
|
|
||||||
import type { Services } from '@morten-olsen/box-utils/services';
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
||||||
import { Queue } from '@morten-olsen/box-utils/queue';
|
import { Queue } from '@morten-olsen/box-utils/queue';
|
||||||
import { isDeepSubset } from '@morten-olsen/box-utils/objects';
|
import { isDeepSubset } from '@morten-olsen/box-utils/objects';
|
||||||
|
|
||||||
|
import { ResourceService } from '../resources.service.js';
|
||||||
import { K8sConfig } from '../../config/config.js';
|
import { K8sConfig } from '../../config/config.js';
|
||||||
|
|
||||||
type ResourceSelector = {
|
type ResourceSelector = {
|
||||||
@@ -41,7 +41,7 @@ class Resource<T extends KubernetesObject> extends EventEmitter<ResourceEvents<T
|
|||||||
return this.#queue;
|
return this.#queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get services() {
|
public get services(): Services {
|
||||||
return this.#options.services;
|
return this.#options.services;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ class Resource<T extends KubernetesObject> extends EventEmitter<ResourceEvents<T
|
|||||||
this.#queue.add(async () => {
|
this.#queue.add(async () => {
|
||||||
const { services } = this.#options;
|
const { services } = this.#options;
|
||||||
const config = services.get(K8sConfig);
|
const config = services.get(K8sConfig);
|
||||||
const objectsApi = config.makeApiClient(KubernetesObjectApi);
|
const { objectsApi } = config;
|
||||||
const body = {
|
const body = {
|
||||||
...patch,
|
...patch,
|
||||||
apiVersion: this.selector.apiVersion,
|
apiVersion: this.selector.apiVersion,
|
||||||
@@ -190,4 +190,3 @@ class Resource<T extends KubernetesObject> extends EventEmitter<ResourceEvents<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { Resource, type ResourceOptions, type ResourceEvents };
|
export { Resource, type ResourceOptions, type ResourceEvents };
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
|
|
||||||
import { ApiException, ApiextensionsV1Api, type KubernetesObject } from '@kubernetes/client-node';
|
import { ApiException, ApiextensionsV1Api, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import type { ZodType } from 'zod';
|
import type { ZodType } from 'zod';
|
||||||
|
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
||||||
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
|
|
||||||
import { WatcherService } from '../watchers/watchers.js';
|
import { WatcherService } from '../watchers/watchers.js';
|
||||||
import { K8sConfig } from '../config/config.js';
|
import { K8sConfig } from '../config/config.js';
|
||||||
|
|
||||||
import { createManifest } from './resources.utils.js';
|
import { createManifest } from './resources.utils.js';
|
||||||
import { Resource, type ResourceOptions } from './resource/resource.js';
|
import { Resource, type ResourceOptions } from './resource/resource.js';
|
||||||
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
|
||||||
import type { Services } from '@morten-olsen/box-utils/services';
|
|
||||||
|
|
||||||
type ResourceClass<T extends KubernetesObject> = (new (options: ResourceOptions<T>) => InstanceType<typeof Resource<T>>) & {
|
type ResourceClass<T extends KubernetesObject> = (new (
|
||||||
|
options: ResourceOptions<T>,
|
||||||
|
) => InstanceType<typeof Resource<T>>) & {
|
||||||
apiVersion: string;
|
apiVersion: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
plural?: string;
|
plural?: string;
|
||||||
@@ -47,13 +48,17 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
|
|
||||||
public register = async (...resources: ResourceClass<ExplicitAny>[]) => {
|
public register = async (...resources: ResourceClass<ExplicitAny>[]) => {
|
||||||
for (const resource of resources) {
|
for (const resource of resources) {
|
||||||
if (!this.#registry.has(resource)) {
|
if (this.#registry.has(resource)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.#registry.set(resource, {
|
this.#registry.set(resource, {
|
||||||
apiVersion: resource.apiVersion,
|
apiVersion: resource.apiVersion,
|
||||||
kind: resource.kind,
|
kind: resource.kind,
|
||||||
plural: resource.plural,
|
plural: resource.plural,
|
||||||
resources: [],
|
resources: [],
|
||||||
});
|
});
|
||||||
|
if ('dependsOn' in resource && Array.isArray(resource.dependsOn)) {
|
||||||
|
await this.register(...resource.dependsOn as ResourceClass<ExplicitAny>[]);
|
||||||
}
|
}
|
||||||
const watcherService = this.#services.get(WatcherService);
|
const watcherService = this.#services.get(WatcherService);
|
||||||
const watcher = watcherService.create({
|
const watcher = watcherService.create({
|
||||||
@@ -65,7 +70,7 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
if (!name) {
|
if (!name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const current = this.get(resource, name, namespace);
|
const current = this.#get(resource, name, namespace, manifest);
|
||||||
current.manifest = manifest;
|
current.manifest = manifest;
|
||||||
});
|
});
|
||||||
await watcher.start();
|
await watcher.start();
|
||||||
@@ -76,7 +81,7 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
return (this.#registry.get(type)?.resources?.filter((r) => r.exists) as InstanceType<T>[]) || [];
|
return (this.#registry.get(type)?.resources?.filter((r) => r.exists) as InstanceType<T>[]) || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
public get = <T extends ResourceClass<ExplicitAny>>(type: T, name: string, namespace?: string) => {
|
#get = <T extends ResourceClass<ExplicitAny>>(type: T, name: string, namespace?: string, manifest?: unknown) => {
|
||||||
let resourceRegistry = this.#registry.get(type);
|
let resourceRegistry = this.#registry.get(type);
|
||||||
if (!resourceRegistry) {
|
if (!resourceRegistry) {
|
||||||
resourceRegistry = {
|
resourceRegistry = {
|
||||||
@@ -98,6 +103,7 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
namespace,
|
namespace,
|
||||||
},
|
},
|
||||||
services: this.#services,
|
services: this.#services,
|
||||||
|
manifest,
|
||||||
});
|
});
|
||||||
current.on('changed', this.emit.bind(this, 'changed', current));
|
current.on('changed', this.emit.bind(this, 'changed', current));
|
||||||
resources.push(current);
|
resources.push(current);
|
||||||
@@ -105,9 +111,13 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
return current as InstanceType<T>;
|
return current as InstanceType<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public get = <T extends ResourceClass<ExplicitAny>>(type: T, name: string, namespace?: string) => {
|
||||||
|
return this.#get(type, name, namespace);
|
||||||
|
};
|
||||||
|
|
||||||
public install = async (...resources: InstallableResourceClass<ExplicitAny>[]) => {
|
public install = async (...resources: InstallableResourceClass<ExplicitAny>[]) => {
|
||||||
const config = this.#services.get(K8sConfig);
|
const config = this.#services.get(K8sConfig);
|
||||||
const extensionsApi = config.makeApiClient(ApiextensionsV1Api);
|
const { extensionsApi } = config;
|
||||||
for (const resource of resources) {
|
for (const resource of resources) {
|
||||||
try {
|
try {
|
||||||
const manifest = createManifest(resource);
|
const manifest = createManifest(resource);
|
||||||
@@ -136,4 +146,3 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { ResourceService, Resource, type ResourceOptions, type ResourceClass, type InstallableResourceClass };
|
export { ResourceService, Resource, type ResourceOptions, type ResourceClass, type InstallableResourceClass };
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
export { CustomResource, type CustomResourceOptions } from './resource/resource.custom.js';
|
export { CustomResource, type CustomResourceOptions } from './resource/resource.custom.js';
|
||||||
export { ResourceReference } from './resource/resource.reference.js';
|
export { ResourceReference } from './resource/resource.reference.js';
|
||||||
export { ResourceService, Resource, type ResourceOptions, type ResourceClass, type InstallableResourceClass } from './resources.service.js';
|
export {
|
||||||
|
ResourceService,
|
||||||
|
Resource,
|
||||||
|
type ResourceOptions,
|
||||||
|
type ResourceClass,
|
||||||
|
type InstallableResourceClass,
|
||||||
|
} from './resources.service.js';
|
||||||
|
|||||||
@@ -52,4 +52,3 @@ const createManifest = (defintion: InstallableResourceClass<ExplicitAny>) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export { createManifest };
|
export { createManifest };
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { KubernetesObjectApi, makeInformer, type Informer, type KubernetesObject } from '@kubernetes/client-node';
|
import { KubernetesObjectApi, makeInformer, type Informer, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
||||||
import type { Services } from '@morten-olsen/box-utils/services';
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
|
|
||||||
import { K8sConfig } from '../../config/config.js';
|
import { K8sConfig } from '../../config/config.js';
|
||||||
|
|
||||||
type ResourceChangedAction = 'add' | 'update' | 'delete';
|
type ResourceChangedAction = 'add' | 'update' | 'delete';
|
||||||
@@ -32,11 +33,10 @@ class Watcher<T extends KubernetesObject> extends EventEmitter<WatcherEvents<T>>
|
|||||||
const { services, apiVersion, kind, selector } = this.#options;
|
const { services, apiVersion, kind, selector } = this.#options;
|
||||||
const plural = this.#options.plural ?? kind.toLowerCase() + 's';
|
const plural = this.#options.plural ?? kind.toLowerCase() + 's';
|
||||||
const [version, group] = apiVersion.split('/').toReversed();
|
const [version, group] = apiVersion.split('/').toReversed();
|
||||||
const config = services.get(K8sConfig);
|
const { kubeConfig, objectsApi } = services.get(K8sConfig);
|
||||||
const path = group ? `/apis/${group}/${version}/${plural}` : `/api/${version}/${plural}`;
|
const path = group ? `/apis/${group}/${version}/${plural}` : `/api/${version}/${plural}`;
|
||||||
const objectsApi = config.makeApiClient(KubernetesObjectApi);
|
|
||||||
const informer = makeInformer<T>(
|
const informer = makeInformer<T>(
|
||||||
config,
|
kubeConfig,
|
||||||
path,
|
path,
|
||||||
async () => {
|
async () => {
|
||||||
return objectsApi.list(apiVersion, kind);
|
return objectsApi.list(apiVersion, kind);
|
||||||
@@ -67,4 +67,3 @@ class Watcher<T extends KubernetesObject> extends EventEmitter<WatcherEvents<T>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { Watcher, type WatcherOptions, type ResourceChangedAction };
|
export { Watcher, type WatcherOptions, type ResourceChangedAction };
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Services, destroy } from "@morten-olsen/box-utils/services";
|
import { Services, destroy } from '@morten-olsen/box-utils/services';
|
||||||
import { Watcher, type WatcherOptions } from "./watcher/watcher.js";
|
|
||||||
|
import { Watcher, type WatcherOptions } from './watcher/watcher.js';
|
||||||
|
|
||||||
class WatcherService {
|
class WatcherService {
|
||||||
#services: Services;
|
#services: Services;
|
||||||
|
|||||||
1
packages/k8s/tsconfig.tsbuildinfo
Normal file
1
packages/k8s/tsconfig.tsbuildinfo
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"root":["./src/exports.ts","./src/global.d.ts","./src/operator.ts","./src/config/config.ts","./src/core/core.crd.ts","./src/core/core.deployment.ts","./src/core/core.namespace.ts","./src/core/core.pv.ts","./src/core/core.secret.ts","./src/core/core.service.ts","./src/core/core.stateful-set.ts","./src/core/core.storage-class.ts","./src/core/core.ts","./src/errors/errors.ts","./src/resources/resources.service.ts","./src/resources/resources.ts","./src/resources/resources.utils.ts","./src/resources/resource/resource.custom.ts","./src/resources/resource/resource.reference.ts","./src/resources/resource/resource.ts","./src/utils/utils.secrets.ts","./src/watchers/watchers.ts","./src/watchers/watcher/watcher.ts"],"version":"5.9.3"}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { z } from "@morten-olsen/box-k8s";
|
import { z } from '@morten-olsen/box-k8s';
|
||||||
|
|
||||||
const valueOrSecret = z.object({
|
const valueOrSecret = z.object({
|
||||||
value: z.string().optional(),
|
value: z.string().optional(),
|
||||||
@@ -16,9 +16,11 @@ const serverSpec = z.object({
|
|||||||
database: z.object({
|
database: z.object({
|
||||||
url: valueOrSecret,
|
url: valueOrSecret,
|
||||||
}),
|
}),
|
||||||
clients: z.object({
|
clients: z
|
||||||
substitutions: z.record(z.string(), z.string()).optional()
|
.object({
|
||||||
}).optional(),
|
substitutions: z.record(z.string(), z.string()).optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export { serverSpec };
|
export { serverSpec };
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import { CustomResource, Secret, type CustomResourceOptions } from "@morten-olsen/box-k8s";
|
import { CustomResource, NotReadyError, Secret, type CustomResourceOptions } from '@morten-olsen/box-k8s';
|
||||||
import { serverSpec } from "./server.schemas.js";
|
|
||||||
import { API_VERSION } from '@morten-olsen/box-utils/consts';
|
import { API_VERSION } from '@morten-olsen/box-utils/consts';
|
||||||
|
|
||||||
type SecretData = {
|
import { serverSpec } from './server.schemas.js';
|
||||||
secret: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AuthentikServer extends CustomResource<typeof serverSpec> {
|
class AuthentikServer extends CustomResource<typeof serverSpec> {
|
||||||
public static readonly apiVersion = API_VERSION;
|
public static readonly apiVersion = API_VERSION;
|
||||||
@@ -12,16 +9,30 @@ class AuthentikServer extends CustomResource<typeof serverSpec> {
|
|||||||
public static readonly spec = serverSpec;
|
public static readonly spec = serverSpec;
|
||||||
public static readonly scope = 'Namespaced';
|
public static readonly scope = 'Namespaced';
|
||||||
|
|
||||||
#secret: Secret<SecretData>;
|
#secret: Secret;
|
||||||
|
|
||||||
constructor(options: CustomResourceOptions<typeof serverSpec>) {
|
constructor(options: CustomResourceOptions<typeof serverSpec>) {
|
||||||
super(options);
|
super(options);
|
||||||
this.#secret = this.resources.get(Secret<SecretData>, `${this.name}-secret`, this.namespace);
|
this.#secret = this.resources.get(Secret, `${this.name}-secret`, this.namespace);
|
||||||
this.#secret.on('changed', this.queueReconcile);
|
this.#secret.on('changed', this.queueReconcile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public reconcile = async () => {
|
public reconcile = async () => {
|
||||||
|
if (!this.#secret.value?.secret) {
|
||||||
|
await this.#secret.set(
|
||||||
|
{
|
||||||
|
secret: crypto.randomUUID(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
metadata: {
|
||||||
|
ownerReferences: [this.ref],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
throw new NotReadyError();
|
||||||
|
}
|
||||||
|
const { secret } = this.#secret.value;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { AuthentikServer }
|
export { AuthentikServer };
|
||||||
|
|||||||
1
packages/resource-authentik/tsconfig.tsbuildinfo
Normal file
1
packages/resource-authentik/tsconfig.tsbuildinfo
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"root":["./src/exports.ts","./src/global.d.ts","./src/resources/oidc-client/oidc-client.ts","./src/resources/server/server.schemas.ts","./src/resources/server/server.ts"],"version":"5.9.3"}
|
||||||
4
packages/resource-cloudflare/.gitignore
vendored
Normal file
4
packages/resource-cloudflare/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/node_modules/
|
||||||
|
/dist/
|
||||||
|
/coverage/
|
||||||
|
/.env
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: playground.homelab.olsen.cloud/v1
|
||||||
|
kind: CloudflareAccount
|
||||||
|
metadata:
|
||||||
|
name: main
|
||||||
|
spec:
|
||||||
|
token:
|
||||||
|
secret: cloudflare
|
||||||
|
namespace: homelab
|
||||||
|
key: token
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: playground.homelab.olsen.cloud/v1
|
||||||
|
kind: CloudflareDnsRecord
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
spec:
|
||||||
|
account: main
|
||||||
|
domain: olsen.cloud
|
||||||
|
subdomain: testing1
|
||||||
|
type: CNAME
|
||||||
|
value: hello
|
||||||
33
packages/resource-cloudflare/package.json
Normal file
33
packages/resource-cloudflare/package.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/exports.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tsx --watch src/start.ts",
|
||||||
|
"build": "tsc --build",
|
||||||
|
"test:unit": "vitest --run --passWithNoTests",
|
||||||
|
"test": "pnpm run \"/^test:/\""
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.6.0",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"exports": {
|
||||||
|
".": "./dist/exports.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@morten-olsen/box-configs": "workspace:*",
|
||||||
|
"@morten-olsen/box-tests": "workspace:*",
|
||||||
|
"@types/node": "24.9.1",
|
||||||
|
"@vitest/coverage-v8": "4.0.1",
|
||||||
|
"tsx": "^4.20.6",
|
||||||
|
"typescript": "5.9.3",
|
||||||
|
"vitest": "4.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@morten-olsen/box-k8s": "workspace:*",
|
||||||
|
"@morten-olsen/box-utils": "workspace:*",
|
||||||
|
"cloudflare": "^5.2.0"
|
||||||
|
},
|
||||||
|
"name": "@morten-olsen/box-resource-cloudflare",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
0
packages/resource-cloudflare/src/exports.ts
Normal file
0
packages/resource-cloudflare/src/exports.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { z } from '@morten-olsen/box-k8s';
|
||||||
|
|
||||||
|
const cloudflareAccountSchema = z.object({
|
||||||
|
token: z.object({
|
||||||
|
secret: z.string(),
|
||||||
|
namespace: z.string(),
|
||||||
|
key: z.string(),
|
||||||
|
}),
|
||||||
|
allowedNamespaces: z.array(z.string()).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export { cloudflareAccountSchema };
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { CustomResource, NotReadyError, ResourceReference, Secret, type CustomResourceOptions } from "@morten-olsen/box-k8s";
|
||||||
|
import { cloudflareAccountSchema } from "./account.schemas.js";
|
||||||
|
import { API_VERSION } from "@morten-olsen/box-utils/consts";
|
||||||
|
|
||||||
|
class CloudflareAccountResource extends CustomResource<typeof cloudflareAccountSchema> {
|
||||||
|
public static readonly apiVersion = API_VERSION;
|
||||||
|
public static readonly kind = "CloudflareAccount";
|
||||||
|
public static readonly spec = cloudflareAccountSchema;
|
||||||
|
public static readonly scope = "Cluster";
|
||||||
|
public static readonly dependsOn = [Secret];
|
||||||
|
|
||||||
|
#secret: ResourceReference<typeof Secret>;
|
||||||
|
|
||||||
|
constructor(options: CustomResourceOptions<typeof cloudflareAccountSchema>) {
|
||||||
|
super(options);
|
||||||
|
this.#secret = new ResourceReference(this.#getSecret());
|
||||||
|
this.#secret.on('changed', this.queueReconcile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get token() {
|
||||||
|
const spec = this.spec;
|
||||||
|
if (!spec) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this.#secret.current?.value?.[spec.token.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
#getSecret = () => {
|
||||||
|
const spec = this.spec;
|
||||||
|
if (!spec) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this.resources.get(
|
||||||
|
Secret,
|
||||||
|
spec.token.secret,
|
||||||
|
spec.token.namespace,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public reconcile = async () => {
|
||||||
|
this.#secret.current = this.#getSecret();
|
||||||
|
if (!this.token) {
|
||||||
|
throw new NotReadyError('Token not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CloudflareAccountResource };
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { z } from '@morten-olsen/box-k8s';
|
||||||
|
|
||||||
|
const cloudflareDnsRecordSchema = z.object({
|
||||||
|
account: z.string(),
|
||||||
|
domain: z.string(),
|
||||||
|
subdomain: z.string().optional(),
|
||||||
|
type: z.enum(['A', 'CNAME', 'MX']),
|
||||||
|
proxy: z.boolean().optional(),
|
||||||
|
value: z.string(),
|
||||||
|
ttl: z.number().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export { cloudflareDnsRecordSchema };
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { CustomResource, NotReadyError } from '@morten-olsen/box-k8s';
|
||||||
|
|
||||||
|
import { CloudflareService } from '../../services/cloudflare/cloudflare.js';
|
||||||
|
|
||||||
|
import { cloudflareDnsRecordSchema } from './dns-record.schemas.js';
|
||||||
|
import { API_VERSION } from '@morten-olsen/box-utils/consts';
|
||||||
|
import { CloudflareAccountResource } from '../account/account.js';
|
||||||
|
|
||||||
|
class CloudflareDnsRecordResource extends CustomResource<typeof cloudflareDnsRecordSchema> {
|
||||||
|
public static readonly apiVersion = API_VERSION;
|
||||||
|
public static readonly kind = "CloudflareDnsRecord";
|
||||||
|
public static readonly spec = cloudflareDnsRecordSchema;
|
||||||
|
public static readonly scope = "Namespaced";
|
||||||
|
public static readonly dependsOn = [CloudflareAccountResource];
|
||||||
|
|
||||||
|
public get dnsId() {
|
||||||
|
return `homelab|${this.namespace}|${this.name}`
|
||||||
|
}
|
||||||
|
|
||||||
|
public reconcile = async () => {
|
||||||
|
if (!this.spec) {
|
||||||
|
throw new NotReadyError('Missing spec');
|
||||||
|
}
|
||||||
|
const service = this.services.get(CloudflareService);
|
||||||
|
const { getDnsRecord, ensrureDnsRecord } = service.getAccount(this.spec.account);
|
||||||
|
await ensrureDnsRecord(this.dnsId, this.spec);
|
||||||
|
};
|
||||||
|
|
||||||
|
public destroy = async () => {
|
||||||
|
|
||||||
|
if (!this.spec) {
|
||||||
|
throw new NotReadyError('Missing spec');
|
||||||
|
}
|
||||||
|
const service = this.services.get(CloudflareService);
|
||||||
|
const { removeDnsRecord } = service.getAccount(this.spec.account);
|
||||||
|
await removeDnsRecord(this.dnsId, this.spec.domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CloudflareDnsRecordResource, cloudflareDnsRecordSchema };
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import type { Services } from "@morten-olsen/box-utils/services";
|
||||||
|
import type { CloudflareAccountResource } from "../../resources/account/account.js"
|
||||||
|
import API from 'cloudflare';
|
||||||
|
import type { Zone } from "cloudflare/resources/zones/zones.mjs";
|
||||||
|
import type { z } from "@morten-olsen/box-k8s";
|
||||||
|
import type { cloudflareDnsRecordSchema } from "../../resources/dns-record/dns-record.schemas.js";
|
||||||
|
|
||||||
|
type CloudflareAccountOptions = {
|
||||||
|
services: Services;
|
||||||
|
resource: CloudflareAccountResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CloudflareAccount {
|
||||||
|
#options: CloudflareAccountOptions;
|
||||||
|
#api?: API;
|
||||||
|
#zones: Map<string, Promise<Zone | undefined>>
|
||||||
|
|
||||||
|
constructor(options: CloudflareAccountOptions) {
|
||||||
|
this.#zones = new Map();
|
||||||
|
this.#options = options;
|
||||||
|
this.#api = new API({
|
||||||
|
apiToken: this.token,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public get token() {
|
||||||
|
return this.#options.resource.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get api() {
|
||||||
|
if (!this.#api) {
|
||||||
|
this.#api = new API({
|
||||||
|
apiToken: this.token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return this.#api;
|
||||||
|
}
|
||||||
|
|
||||||
|
#getZone = async (name: string) => {
|
||||||
|
const zones = await this.api.zones.list({
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
const [zone] = zones.result;
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getZone = async (name: string) => {
|
||||||
|
if (!this.#zones.has(name)) {
|
||||||
|
this.#zones.set(name, this.#getZone(name));
|
||||||
|
}
|
||||||
|
const current = this.#zones.get(name);
|
||||||
|
return await current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDnsRecord = async (id: string, domain: string) => {
|
||||||
|
const zone = await this.getZone(domain);
|
||||||
|
|
||||||
|
if (!zone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dnsRecords = await this.api.dns.records.list({
|
||||||
|
zone_id: zone.id,
|
||||||
|
comment: {
|
||||||
|
exact: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const [dnsRecord] = dnsRecords.result;
|
||||||
|
|
||||||
|
return dnsRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeDnsRecord = async (id: string, domain: string) => {
|
||||||
|
const zone = await this.getZone(domain);
|
||||||
|
if (!zone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const record = await this.getDnsRecord(id, domain);
|
||||||
|
if (!record) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.api.dns.records.delete(record.id, {
|
||||||
|
zone_id: zone.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ensrureDnsRecord = async (id: string, options: z.infer<typeof cloudflareDnsRecordSchema>) => {
|
||||||
|
const { domain, subdomain, value, type, ttl = 1, proxy } = options;
|
||||||
|
const zone = await this.getZone(options.domain);
|
||||||
|
if (!zone) {
|
||||||
|
throw new Error('Zone not found');
|
||||||
|
}
|
||||||
|
const current = await this.getDnsRecord(id, domain);
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
await this.api.dns.records.create({
|
||||||
|
zone_id: zone.id,
|
||||||
|
type,
|
||||||
|
name: subdomain ? `${subdomain}.${domain}` : domain,
|
||||||
|
content: value,
|
||||||
|
comment: id,
|
||||||
|
ttl,
|
||||||
|
proxied: proxy,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
|
||||||
|
await this.api.dns.records.update(current.id, {
|
||||||
|
zone_id: zone.id,
|
||||||
|
type,
|
||||||
|
name: subdomain ? `${subdomain}.${domain}` : domain,
|
||||||
|
content: value,
|
||||||
|
comment: id,
|
||||||
|
ttl,
|
||||||
|
proxied: proxy,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CloudflareAccount };
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Services } from "@morten-olsen/box-utils/services";
|
||||||
|
import { CloudflareAccount } from "./cloudflare.account.js";
|
||||||
|
import { ResourceService } from "@morten-olsen/box-k8s";
|
||||||
|
import { CloudflareAccountResource } from "../../resources/account/account.js";
|
||||||
|
|
||||||
|
class CloudflareService {
|
||||||
|
#services: Services;
|
||||||
|
#instances: Map<string, CloudflareAccount>;
|
||||||
|
|
||||||
|
constructor(services: Services) {
|
||||||
|
this.#services = services;
|
||||||
|
this.#instances = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAccount = (name: string) => {
|
||||||
|
if (!this.#instances.has(name)) {
|
||||||
|
const resourceService = this.#services.get(ResourceService);
|
||||||
|
const resource = resourceService.get(CloudflareAccountResource, name);
|
||||||
|
this.#instances.set(name, new CloudflareAccount({
|
||||||
|
resource,
|
||||||
|
services: this.#services,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
const current = this.#instances.get(name);
|
||||||
|
if (!current) {
|
||||||
|
throw new Error('Could not get cloudflare account');
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { CloudflareService };
|
||||||
13
packages/resource-cloudflare/src/start.ts
Normal file
13
packages/resource-cloudflare/src/start.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { K8sOperator } from '@morten-olsen/box-k8s';
|
||||||
|
import { CloudflareAccountResource } from './resources/account/account.js';
|
||||||
|
import { CloudflareDnsRecordResource } from './resources/dns-record/dns-record.js';
|
||||||
|
|
||||||
|
const operator = new K8sOperator();
|
||||||
|
await operator.resources.install(
|
||||||
|
CloudflareAccountResource,
|
||||||
|
CloudflareDnsRecordResource,
|
||||||
|
)
|
||||||
|
await operator.resources.register(
|
||||||
|
CloudflareAccountResource,
|
||||||
|
CloudflareDnsRecordResource,
|
||||||
|
)
|
||||||
9
packages/resource-cloudflare/tsconfig.json
Normal file
9
packages/resource-cloudflare/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"extends": "@morten-olsen/box-configs/tsconfig.json"
|
||||||
|
}
|
||||||
12
packages/resource-cloudflare/vitest.config.ts
Normal file
12
packages/resource-cloudflare/vitest.config.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
import { getAliases } from '@morten-olsen/box-tests/vitest';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default defineConfig(async () => {
|
||||||
|
const aliases = await getAliases();
|
||||||
|
return {
|
||||||
|
resolve: {
|
||||||
|
alias: aliases,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
1
packages/resource-redis/tsconfig.tsbuildinfo
Normal file
1
packages/resource-redis/tsconfig.tsbuildinfo
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"root":["./src/exports.ts"],"version":"5.9.3"}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
const API_GROUP = 'playground.homelab.olsen.cloud';
|
const API_GROUP = 'playground.homelab.olsen.cloud';
|
||||||
const API_VERSION = `${API_GROUP}/v1`;
|
const API_VERSION = `${API_GROUP}/v1`;
|
||||||
|
const FINALIZER = `finalizer.${API_GROUP}`;
|
||||||
|
|
||||||
export { API_VERSION, API_GROUP };
|
export { API_VERSION, API_GROUP, FINALIZER };
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class EventEmitter<T extends Record<string, (...args: ExplicitAny[]) => void | P
|
|||||||
abortController.signal.addEventListener('abort', () => {
|
abortController.signal.addEventListener('abort', () => {
|
||||||
this.#listeners.set(event, listeners?.difference(new Set([callbackClone])));
|
this.#listeners.set(event, listeners?.difference(new Set([callbackClone])));
|
||||||
});
|
});
|
||||||
return abortController.abort;
|
return () => abortController.abort();
|
||||||
};
|
};
|
||||||
|
|
||||||
once = <K extends keyof T>(event: K, callback: EventListener<Parameters<T[K]>>, options: OnOptions = {}) => {
|
once = <K extends keyof T>(event: K, callback: EventListener<Parameters<T[K]>>, options: OnOptions = {}) => {
|
||||||
@@ -62,4 +62,3 @@ class EventEmitter<T extends Record<string, (...args: ExplicitAny[]) => void | P
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { EventEmitter };
|
export { EventEmitter };
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ function isDeepSubset<T>(actual: ExplicitAny, expected: T): expected is T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
export { isDeepSubset };
|
export { isDeepSubset };
|
||||||
|
|||||||
@@ -38,4 +38,3 @@ class Queue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { Queue };
|
export { Queue };
|
||||||
|
|
||||||
|
|||||||
194
pnpm-lock.yaml
generated
194
pnpm-lock.yaml
generated
@@ -34,7 +34,7 @@ importers:
|
|||||||
version: 6.0.9(@pnpm/logger@5.2.0)
|
version: 6.0.9(@pnpm/logger@5.2.0)
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
eslint:
|
eslint:
|
||||||
specifier: 9.38.0
|
specifier: 9.38.0
|
||||||
version: 9.38.0
|
version: 9.38.0
|
||||||
@@ -61,7 +61,7 @@ importers:
|
|||||||
version: 8.46.2(eslint@9.38.0)(typescript@5.9.3)
|
version: 8.46.2(eslint@9.38.0)(typescript@5.9.3)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/bootstrap:
|
packages/bootstrap:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -76,13 +76,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/configs: {}
|
packages/configs: {}
|
||||||
|
|
||||||
@@ -118,13 +118,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/operator:
|
packages/operator:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -137,13 +137,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/resource-authentik:
|
packages/resource-authentik:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -165,13 +165,47 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
|
packages/resource-cloudflare:
|
||||||
|
dependencies:
|
||||||
|
'@morten-olsen/box-k8s':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../k8s
|
||||||
|
'@morten-olsen/box-utils':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../utils
|
||||||
|
cloudflare:
|
||||||
|
specifier: ^5.2.0
|
||||||
|
version: 5.2.0
|
||||||
|
devDependencies:
|
||||||
|
'@morten-olsen/box-configs':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../configs
|
||||||
|
'@morten-olsen/box-tests':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../tests
|
||||||
|
'@types/node':
|
||||||
|
specifier: 24.9.1
|
||||||
|
version: 24.9.1
|
||||||
|
'@vitest/coverage-v8':
|
||||||
|
specifier: 4.0.1
|
||||||
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
|
tsx:
|
||||||
|
specifier: ^4.20.6
|
||||||
|
version: 4.20.6
|
||||||
|
typescript:
|
||||||
|
specifier: 5.9.3
|
||||||
|
version: 5.9.3
|
||||||
|
vitest:
|
||||||
|
specifier: 4.0.1
|
||||||
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/resource-postgres:
|
packages/resource-postgres:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -193,13 +227,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/resource-redis:
|
packages/resource-redis:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -221,13 +255,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/tests:
|
packages/tests:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -243,13 +277,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages/utils:
|
packages/utils:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -271,13 +305,13 @@ importers:
|
|||||||
version: 24.9.1
|
version: 24.9.1
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1))
|
version: 4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.0.1(@types/node@24.9.1)
|
version: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -845,6 +879,9 @@ packages:
|
|||||||
'@types/node-fetch@2.6.13':
|
'@types/node-fetch@2.6.13':
|
||||||
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
|
resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==}
|
||||||
|
|
||||||
|
'@types/node@18.19.130':
|
||||||
|
resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
|
||||||
|
|
||||||
'@types/node@24.9.1':
|
'@types/node@24.9.1':
|
||||||
resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==}
|
resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==}
|
||||||
|
|
||||||
@@ -956,6 +993,10 @@ packages:
|
|||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
abort-controller@3.0.0:
|
||||||
|
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||||
|
engines: {node: '>=6.5'}
|
||||||
|
|
||||||
acorn-jsx@5.3.2:
|
acorn-jsx@5.3.2:
|
||||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -970,6 +1011,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
agentkeepalive@4.6.0:
|
||||||
|
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
||||||
|
engines: {node: '>= 8.0.0'}
|
||||||
|
|
||||||
ajv@6.12.6:
|
ajv@6.12.6:
|
||||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||||
|
|
||||||
@@ -1171,6 +1216,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
cloudflare@5.2.0:
|
||||||
|
resolution: {integrity: sha512-dVzqDpPFYR9ApEC9e+JJshFJZXcw4HzM8W+3DHzO5oy9+8rLC53G7x6fEf9A7/gSuSCxuvndzui5qJKftfIM9A==}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@@ -1417,6 +1465,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
event-target-shim@5.0.1:
|
||||||
|
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
eventemitter3@5.0.1:
|
eventemitter3@5.0.1:
|
||||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||||
|
|
||||||
@@ -1488,10 +1540,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
form-data-encoder@1.7.2:
|
||||||
|
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||||
|
|
||||||
form-data@4.0.4:
|
form-data@4.0.4:
|
||||||
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
|
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
formdata-node@4.4.1:
|
||||||
|
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
||||||
|
engines: {node: '>= 12.20'}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@@ -1530,6 +1589,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
|
resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
get-tsconfig@4.13.0:
|
||||||
|
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
||||||
|
|
||||||
glob-parent@5.1.2:
|
glob-parent@5.1.2:
|
||||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -1597,6 +1659,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||||
engines: {node: '>=10.17.0'}
|
engines: {node: '>=10.17.0'}
|
||||||
|
|
||||||
|
humanize-ms@1.2.1:
|
||||||
|
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||||
|
|
||||||
ignore@5.3.2:
|
ignore@5.3.2:
|
||||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
@@ -1942,6 +2007,11 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
node-domexception@1.0.0:
|
||||||
|
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||||
|
engines: {node: '>=10.5.0'}
|
||||||
|
deprecated: Use your platform's native DOMException instead
|
||||||
|
|
||||||
node-fetch@2.7.0:
|
node-fetch@2.7.0:
|
||||||
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
||||||
engines: {node: 4.x || >=6.0.0}
|
engines: {node: 4.x || >=6.0.0}
|
||||||
@@ -2168,6 +2238,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
resolve-pkg-maps@1.0.0:
|
||||||
|
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||||
|
|
||||||
resolve@1.22.11:
|
resolve@1.22.11:
|
||||||
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -2420,6 +2493,11 @@ packages:
|
|||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
tsx@4.20.6:
|
||||||
|
resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
turbo-darwin-64@2.5.8:
|
turbo-darwin-64@2.5.8:
|
||||||
resolution: {integrity: sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ==}
|
resolution: {integrity: sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
@@ -2498,6 +2576,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
undici-types@5.26.5:
|
||||||
|
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||||
|
|
||||||
undici-types@7.16.0:
|
undici-types@7.16.0:
|
||||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
@@ -2588,6 +2669,10 @@ packages:
|
|||||||
wcwidth@1.0.1:
|
wcwidth@1.0.1:
|
||||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||||
|
|
||||||
|
web-streams-polyfill@4.0.0-beta.3:
|
||||||
|
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
webidl-conversions@3.0.1:
|
webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
@@ -3213,6 +3298,10 @@ snapshots:
|
|||||||
'@types/node': 24.9.1
|
'@types/node': 24.9.1
|
||||||
form-data: 4.0.4
|
form-data: 4.0.4
|
||||||
|
|
||||||
|
'@types/node@18.19.130':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 5.26.5
|
||||||
|
|
||||||
'@types/node@24.9.1':
|
'@types/node@24.9.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.16.0
|
||||||
@@ -3318,7 +3407,7 @@ snapshots:
|
|||||||
'@typescript-eslint/types': 8.46.2
|
'@typescript-eslint/types': 8.46.2
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
|
|
||||||
'@vitest/coverage-v8@4.0.1(vitest@4.0.1(@types/node@24.9.1))':
|
'@vitest/coverage-v8@4.0.1(vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@bcoe/v8-coverage': 1.0.2
|
'@bcoe/v8-coverage': 1.0.2
|
||||||
'@vitest/utils': 4.0.1
|
'@vitest/utils': 4.0.1
|
||||||
@@ -3331,7 +3420,7 @@ snapshots:
|
|||||||
magicast: 0.3.5
|
magicast: 0.3.5
|
||||||
std-env: 3.10.0
|
std-env: 3.10.0
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vitest: 4.0.1(@types/node@24.9.1)
|
vitest: 4.0.1(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -3344,13 +3433,13 @@ snapshots:
|
|||||||
chai: 6.2.0
|
chai: 6.2.0
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
|
|
||||||
'@vitest/mocker@4.0.1(vite@7.1.12(@types/node@24.9.1))':
|
'@vitest/mocker@4.0.1(vite@7.1.12(@types/node@24.9.1)(tsx@4.20.6))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 4.0.1
|
'@vitest/spy': 4.0.1
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.19
|
magic-string: 0.30.19
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 7.1.12(@types/node@24.9.1)
|
vite: 7.1.12(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
|
|
||||||
'@vitest/pretty-format@4.0.1':
|
'@vitest/pretty-format@4.0.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3378,6 +3467,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
|
|
||||||
|
abort-controller@3.0.0:
|
||||||
|
dependencies:
|
||||||
|
event-target-shim: 5.0.1
|
||||||
|
|
||||||
acorn-jsx@5.3.2(acorn@8.15.0):
|
acorn-jsx@5.3.2(acorn@8.15.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
@@ -3386,6 +3479,10 @@ snapshots:
|
|||||||
|
|
||||||
agent-base@7.1.4: {}
|
agent-base@7.1.4: {}
|
||||||
|
|
||||||
|
agentkeepalive@4.6.0:
|
||||||
|
dependencies:
|
||||||
|
humanize-ms: 1.2.1
|
||||||
|
|
||||||
ajv@6.12.6:
|
ajv@6.12.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
@@ -3613,6 +3710,18 @@ snapshots:
|
|||||||
|
|
||||||
clone@1.0.4: {}
|
clone@1.0.4: {}
|
||||||
|
|
||||||
|
cloudflare@5.2.0:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 18.19.130
|
||||||
|
'@types/node-fetch': 2.6.13
|
||||||
|
abort-controller: 3.0.0
|
||||||
|
agentkeepalive: 4.6.0
|
||||||
|
form-data-encoder: 1.7.2
|
||||||
|
formdata-node: 4.4.1
|
||||||
|
node-fetch: 2.7.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- encoding
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
@@ -3991,6 +4100,8 @@ snapshots:
|
|||||||
|
|
||||||
esutils@2.0.3: {}
|
esutils@2.0.3: {}
|
||||||
|
|
||||||
|
event-target-shim@5.0.1: {}
|
||||||
|
|
||||||
eventemitter3@5.0.1: {}
|
eventemitter3@5.0.1: {}
|
||||||
|
|
||||||
events-universal@1.0.1:
|
events-universal@1.0.1:
|
||||||
@@ -4065,6 +4176,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-callable: 1.2.7
|
is-callable: 1.2.7
|
||||||
|
|
||||||
|
form-data-encoder@1.7.2: {}
|
||||||
|
|
||||||
form-data@4.0.4:
|
form-data@4.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
asynckit: 0.4.0
|
asynckit: 0.4.0
|
||||||
@@ -4073,6 +4186,11 @@ snapshots:
|
|||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
|
|
||||||
|
formdata-node@4.4.1:
|
||||||
|
dependencies:
|
||||||
|
node-domexception: 1.0.0
|
||||||
|
web-streams-polyfill: 4.0.0-beta.3
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -4122,6 +4240,10 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
get-intrinsic: 1.3.0
|
get-intrinsic: 1.3.0
|
||||||
|
|
||||||
|
get-tsconfig@4.13.0:
|
||||||
|
dependencies:
|
||||||
|
resolve-pkg-maps: 1.0.0
|
||||||
|
|
||||||
glob-parent@5.1.2:
|
glob-parent@5.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
@@ -4173,6 +4295,10 @@ snapshots:
|
|||||||
|
|
||||||
human-signals@2.1.0: {}
|
human-signals@2.1.0: {}
|
||||||
|
|
||||||
|
humanize-ms@1.2.1:
|
||||||
|
dependencies:
|
||||||
|
ms: 2.1.3
|
||||||
|
|
||||||
ignore@5.3.2: {}
|
ignore@5.3.2: {}
|
||||||
|
|
||||||
ignore@7.0.5: {}
|
ignore@7.0.5: {}
|
||||||
@@ -4488,6 +4614,8 @@ snapshots:
|
|||||||
split2: 3.2.2
|
split2: 3.2.2
|
||||||
through2: 4.0.2
|
through2: 4.0.2
|
||||||
|
|
||||||
|
node-domexception@1.0.0: {}
|
||||||
|
|
||||||
node-fetch@2.7.0:
|
node-fetch@2.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
@@ -4707,6 +4835,8 @@ snapshots:
|
|||||||
|
|
||||||
resolve-from@4.0.0: {}
|
resolve-from@4.0.0: {}
|
||||||
|
|
||||||
|
resolve-pkg-maps@1.0.0: {}
|
||||||
|
|
||||||
resolve@1.22.11:
|
resolve@1.22.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-core-module: 2.16.1
|
is-core-module: 2.16.1
|
||||||
@@ -5023,6 +5153,13 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
tsx@4.20.6:
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.25.11
|
||||||
|
get-tsconfig: 4.13.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
turbo-darwin-64@2.5.8:
|
turbo-darwin-64@2.5.8:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -5111,6 +5248,8 @@ snapshots:
|
|||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
which-boxed-primitive: 1.1.1
|
which-boxed-primitive: 1.1.1
|
||||||
|
|
||||||
|
undici-types@5.26.5: {}
|
||||||
|
|
||||||
undici-types@7.16.0: {}
|
undici-types@7.16.0: {}
|
||||||
|
|
||||||
unique-string@2.0.0:
|
unique-string@2.0.0:
|
||||||
@@ -5123,7 +5262,7 @@ snapshots:
|
|||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
vite@7.1.12(@types/node@24.9.1):
|
vite@7.1.12(@types/node@24.9.1)(tsx@4.20.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.11
|
esbuild: 0.25.11
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -5134,11 +5273,12 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 24.9.1
|
'@types/node': 24.9.1
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
tsx: 4.20.6
|
||||||
|
|
||||||
vitest@4.0.1(@types/node@24.9.1):
|
vitest@4.0.1(@types/node@24.9.1)(tsx@4.20.6):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 4.0.1
|
'@vitest/expect': 4.0.1
|
||||||
'@vitest/mocker': 4.0.1(vite@7.1.12(@types/node@24.9.1))
|
'@vitest/mocker': 4.0.1(vite@7.1.12(@types/node@24.9.1)(tsx@4.20.6))
|
||||||
'@vitest/pretty-format': 4.0.1
|
'@vitest/pretty-format': 4.0.1
|
||||||
'@vitest/runner': 4.0.1
|
'@vitest/runner': 4.0.1
|
||||||
'@vitest/snapshot': 4.0.1
|
'@vitest/snapshot': 4.0.1
|
||||||
@@ -5155,7 +5295,7 @@ snapshots:
|
|||||||
tinyexec: 0.3.2
|
tinyexec: 0.3.2
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vite: 7.1.12(@types/node@24.9.1)
|
vite: 7.1.12(@types/node@24.9.1)(tsx@4.20.6)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 24.9.1
|
'@types/node': 24.9.1
|
||||||
@@ -5177,6 +5317,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
defaults: 1.0.4
|
defaults: 1.0.4
|
||||||
|
|
||||||
|
web-streams-polyfill@4.0.0-beta.3: {}
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
||||||
whatwg-url@5.0.0:
|
whatwg-url@5.0.0:
|
||||||
|
|||||||
Reference in New Issue
Block a user