@hasna/uptime 0.1.3 → 0.1.5

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.
@@ -0,0 +1,113 @@
1
+ export interface AwsDeploymentPlanOptions {
2
+ accountName?: string;
3
+ region?: string;
4
+ stage?: string;
5
+ servicePrefix?: string;
6
+ hostname?: string;
7
+ workspaceId?: string;
8
+ vpcId?: string;
9
+ rdsInstanceId?: string;
10
+ ecrRepository?: string;
11
+ image?: string;
12
+ evidenceBucket?: string;
13
+ hostedTokenSecretName?: string;
14
+ databaseSecretName?: string;
15
+ appEnvSecretName?: string;
16
+ publicProbeSecretName?: string;
17
+ privateProbeSecretName?: string;
18
+ reportingSecretName?: string;
19
+ }
20
+ export interface AwsDeploymentPlan {
21
+ kind: "open-uptime.aws-deployment-plan";
22
+ version: 1;
23
+ generatedAt: string;
24
+ status: "blocked";
25
+ canApply: false;
26
+ accountName: string;
27
+ region: string;
28
+ stage: string;
29
+ servicePrefix: string;
30
+ hostname: string;
31
+ workspaceId: string;
32
+ mode: "hosted";
33
+ resources: {
34
+ ecrRepository: string;
35
+ ecsCluster: string;
36
+ services: AwsServicePlan[];
37
+ vpcId: string;
38
+ rdsInstanceId: string;
39
+ evidenceBucket: string;
40
+ loadBalancer: string;
41
+ targetGroups: string[];
42
+ securityGroups: string[];
43
+ secrets: Record<string, string>;
44
+ logGroups: string[];
45
+ alarms: string[];
46
+ };
47
+ image: {
48
+ repository: string;
49
+ uri: string;
50
+ buildCommand: string;
51
+ pushCommands: string[];
52
+ };
53
+ runbook: {
54
+ preflight: string[];
55
+ provision: string[];
56
+ deploy: string[];
57
+ rollback: string[];
58
+ spark01: string[];
59
+ };
60
+ blockers: string[];
61
+ requiredEvidence: string[];
62
+ safety: {
63
+ liveAwsMutation: false;
64
+ plaintextSecrets: false;
65
+ hostedLocalSqliteAllowed: false;
66
+ notes: string[];
67
+ };
68
+ }
69
+ export interface AwsServicePlan {
70
+ name: string;
71
+ role: "web" | "scheduler" | "public-probe" | "reporter" | "migration";
72
+ desiredCount: number;
73
+ taskRole: string;
74
+ executionRole: string;
75
+ logGroup: string;
76
+ healthCommand?: string;
77
+ environment: Record<string, string>;
78
+ secrets: Record<string, string>;
79
+ }
80
+ export interface Spark01CloudConfigOptions {
81
+ apiUrl?: string;
82
+ workspaceId?: string;
83
+ probeId?: string;
84
+ probePrivateKeyFile?: string;
85
+ machineId?: string;
86
+ logLevel?: string;
87
+ }
88
+ export interface Spark01CloudConfig {
89
+ kind: "open-uptime.spark01-cloud-config";
90
+ version: 1;
91
+ generatedAt: string;
92
+ status: "blocked";
93
+ canStart: false;
94
+ machineId: string;
95
+ mode: "private-probe";
96
+ env: Record<string, string>;
97
+ files: Array<{
98
+ path: string;
99
+ mode: string;
100
+ purpose: string;
101
+ }>;
102
+ commands: string[];
103
+ blockers: string[];
104
+ safety: {
105
+ privateKeyInline: false;
106
+ tokenInline: false;
107
+ notes: string[];
108
+ };
109
+ }
110
+ export declare function buildAwsDeploymentPlan(options?: AwsDeploymentPlanOptions): AwsDeploymentPlan;
111
+ export declare function buildSpark01CloudConfig(options?: Spark01CloudConfigOptions): Spark01CloudConfig;
112
+ export declare function renderSpark01Env(config: Spark01CloudConfig): string;
113
+ //# sourceMappingURL=cloud-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-plan.d.ts","sourceRoot":"","sources":["../src/cloud-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,267 @@
1
+ // @bun
2
+ // src/cloud-plan.ts
3
+ var DEFAULT_ACCOUNT = "hasna-xyz-infra";
4
+ var DEFAULT_REGION = "us-east-1";
5
+ var DEFAULT_STAGE = "prod";
6
+ var DEFAULT_PREFIX = "open-uptime";
7
+ var DEFAULT_HOSTNAME = "uptime.hasna.xyz";
8
+ var DEFAULT_WORKSPACE_ID = "wks_2tyysw05cwap";
9
+ var DEFAULT_VPC_ID = "vpc-04c7f7abc1d3c3f56";
10
+ var DEFAULT_RDS = "hasna-xyz-infra-apps-prod-postgres";
11
+ function buildAwsDeploymentPlan(options = {}) {
12
+ const region = clean(options.region, DEFAULT_REGION);
13
+ const stage = clean(options.stage, DEFAULT_STAGE);
14
+ const prefix = clean(options.servicePrefix, DEFAULT_PREFIX);
15
+ const accountName = clean(options.accountName, DEFAULT_ACCOUNT);
16
+ const hostname = clean(options.hostname, DEFAULT_HOSTNAME);
17
+ const workspaceId = clean(options.workspaceId, DEFAULT_WORKSPACE_ID);
18
+ const ecrRepository = clean(options.ecrRepository, `hasna/opensource/${prefix}`);
19
+ const image = clean(options.image, `<account-id>.dkr.ecr.${region}.amazonaws.com/${ecrRepository}:<git-sha>`);
20
+ const evidenceBucket = clean(options.evidenceBucket, `hasna-${stage}-${prefix}-evidence`);
21
+ const cluster = `${prefix}-${stage}`;
22
+ const secrets = {
23
+ database: clean(options.databaseSecretName, `hasna/xyz/opensource/uptime/${stage}/rds`),
24
+ appEnv: clean(options.appEnvSecretName, `hasna/xyz/opensource/uptime/${stage}/app/env`),
25
+ hostedToken: clean(options.hostedTokenSecretName, `hasna/xyz/opensource/uptime/${stage}/hosted-token`),
26
+ publicProbe: clean(options.publicProbeSecretName, `hasna/xyz/opensource/uptime/${stage}/probe/public`),
27
+ privateProbe: clean(options.privateProbeSecretName, `hasna/xyz/opensource/uptime/${stage}/probe/private`),
28
+ reporting: clean(options.reportingSecretName, `hasna/xyz/opensource/uptime/${stage}/reporting`)
29
+ };
30
+ const services = [
31
+ servicePlan(prefix, stage, "web", 2, image, workspaceId, secrets, {
32
+ HASNA_UPTIME_MODE: "hosted",
33
+ HASNA_UPTIME_WORKSPACE_ID: workspaceId,
34
+ HASNA_UPTIME_HOSTNAME: hostname
35
+ }),
36
+ servicePlan(prefix, stage, "scheduler", 1, image, workspaceId, secrets, {
37
+ HASNA_UPTIME_MODE: "hosted",
38
+ HASNA_UPTIME_WORKSPACE_ID: workspaceId,
39
+ HASNA_UPTIME_COMPONENT: "scheduler"
40
+ }),
41
+ servicePlan(prefix, stage, "public-probe", 1, image, workspaceId, secrets, {
42
+ HASNA_UPTIME_MODE: "hosted",
43
+ HASNA_UPTIME_WORKSPACE_ID: workspaceId,
44
+ HASNA_UPTIME_COMPONENT: "public-probe",
45
+ HASNA_UPTIME_PROBE_LOCATION: region
46
+ }),
47
+ servicePlan(prefix, stage, "reporter", 1, image, workspaceId, secrets, {
48
+ HASNA_UPTIME_MODE: "hosted",
49
+ HASNA_UPTIME_WORKSPACE_ID: workspaceId,
50
+ HASNA_UPTIME_COMPONENT: "reporter"
51
+ }),
52
+ servicePlan(prefix, stage, "migration", 0, image, workspaceId, secrets, {
53
+ HASNA_UPTIME_MODE: "hosted",
54
+ HASNA_UPTIME_WORKSPACE_ID: workspaceId,
55
+ HASNA_UPTIME_COMPONENT: "migration"
56
+ })
57
+ ];
58
+ return {
59
+ kind: "open-uptime.aws-deployment-plan",
60
+ version: 1,
61
+ generatedAt: new Date().toISOString(),
62
+ status: "blocked",
63
+ canApply: false,
64
+ accountName,
65
+ region,
66
+ stage,
67
+ servicePrefix: prefix,
68
+ hostname,
69
+ workspaceId,
70
+ mode: "hosted",
71
+ resources: {
72
+ ecrRepository,
73
+ ecsCluster: cluster,
74
+ services,
75
+ vpcId: clean(options.vpcId, DEFAULT_VPC_ID),
76
+ rdsInstanceId: clean(options.rdsInstanceId, DEFAULT_RDS),
77
+ evidenceBucket,
78
+ loadBalancer: `${prefix}-${stage}-alb`,
79
+ targetGroups: [`${prefix}-${stage}-web-tg`],
80
+ securityGroups: [
81
+ `${prefix}-${stage}-alb-sg`,
82
+ `${prefix}-${stage}-web-sg`,
83
+ `${prefix}-${stage}-scheduler-sg`,
84
+ `${prefix}-${stage}-public-probe-sg`,
85
+ `${prefix}-${stage}-rds-client-sg`
86
+ ],
87
+ secrets,
88
+ logGroups: services.map((service) => service.logGroup),
89
+ alarms: [
90
+ `${prefix}-${stage}-web-5xx`,
91
+ `${prefix}-${stage}-scheduler-stalled`,
92
+ `${prefix}-${stage}-probe-stale`,
93
+ `${prefix}-${stage}-report-delivery-failures`
94
+ ]
95
+ },
96
+ image: {
97
+ repository: ecrRepository,
98
+ uri: image,
99
+ buildCommand: "BLOCKED: add a reviewed Dockerfile/container build target before running docker build",
100
+ pushCommands: [
101
+ "BLOCKED: push only from approved CI/CD after the ECR repository and image digest policy exist",
102
+ "BLOCKED: deploy services by immutable image digest, not by mutable tags"
103
+ ]
104
+ },
105
+ runbook: {
106
+ preflight: [
107
+ `aws sts get-caller-identity --profile ${accountName}`,
108
+ `aws rds describe-db-instances --db-instance-identifier ${clean(options.rdsInstanceId, DEFAULT_RDS)} --region ${region}`,
109
+ `aws ec2 describe-vpcs --vpc-ids ${clean(options.vpcId, DEFAULT_VPC_ID)} --region ${region}`,
110
+ "Confirm the infra repository and Terraform/CloudFormation owner before live mutation."
111
+ ],
112
+ provision: [
113
+ `Infra PR must declare or update ECR repository ${ecrRepository}.`,
114
+ `Infra PR must declare hardened S3 evidence bucket ${evidenceBucket} with KMS, versioning, lifecycle, and public access block.`,
115
+ `Infra PR must declare ECS/Fargate cluster ${cluster}, ALB, target groups, security groups, IAM roles, CloudWatch log groups, and Secrets Manager refs.`,
116
+ "Only apply the infra plan from the approved infrastructure repository after review evidence is attached."
117
+ ],
118
+ deploy: [
119
+ "Build and publish the image only after the Dockerfile/container target is reviewed.",
120
+ "Run the migration task with the migrator role before web/scheduler/probe services.",
121
+ `Register task definitions for ${services.map((service) => service.name).join(", ")} using valueFrom secrets.`,
122
+ `Update ECS services in cluster ${cluster} one component at a time through the approved deploy pipeline.`,
123
+ `Create Route53/edge record for ${hostname} only after ALB health checks pass and auth denial smokes succeed.`
124
+ ],
125
+ rollback: [
126
+ "Keep previous task definition ARNs before each service update.",
127
+ "Rollback through the approved deploy pipeline to the previously recorded task definition ARNs.",
128
+ "Disable scheduler/reporter services before data rollback.",
129
+ "Restore RDS snapshot only after explicit operator approval and audit record."
130
+ ],
131
+ spark01: [
132
+ "Create a private probe identity with a caller-managed public key.",
133
+ "Install @hasna/uptime on Spark01 and write the generated env file with mode 0600.",
134
+ "Run the private probe against the hosted /api/v1 probe endpoint once it exists."
135
+ ]
136
+ },
137
+ blockers: [
138
+ "The hasna-xyz-infra infrastructure owner repository was not found in this workspace.",
139
+ "The repo has no reviewed Dockerfile/container build target for image build and publish automation.",
140
+ "Hosted Postgres storage adapter and migrations are not implemented.",
141
+ "Hosted production auth/RBAC must replace broad static hosted-token operation before exposure.",
142
+ "Public probe execution still needs DNS, redirect, and rebinding SSRF enforcement plus cloud check-job leases.",
143
+ "Spark01 hosted probe enrollment, claim, submit, heartbeat, revocation, and rotation are not cloud-backed yet."
144
+ ],
145
+ requiredEvidence: [
146
+ "Infrastructure PR/synth/plan from the approved infra repository.",
147
+ "Container build smoke and immutable image digest.",
148
+ "ECS task definitions using secrets.valueFrom only.",
149
+ "ALB/TLS/DNS/auth denial smokes.",
150
+ "RDS TLS, backups/PITR, scoped roles, and migration dry-run evidence.",
151
+ "S3 bucket KMS, versioning, lifecycle, and public-access-block evidence.",
152
+ "Spark01 private-probe registration, key-file mode, heartbeat, and revocation evidence."
153
+ ],
154
+ safety: {
155
+ liveAwsMutation: false,
156
+ plaintextSecrets: false,
157
+ hostedLocalSqliteAllowed: false,
158
+ notes: [
159
+ "This plan generator does not call AWS.",
160
+ "Hosted runtime must use Postgres; SQLite remains local/dev fallback only.",
161
+ "Secrets are represented as secret names/refs and must be injected with valueFrom.",
162
+ "Actual deploy belongs in the deploy_release_operate_final goal node after infra review."
163
+ ]
164
+ }
165
+ };
166
+ }
167
+ function buildSpark01CloudConfig(options = {}) {
168
+ const apiUrl = clean(options.apiUrl, `https://${DEFAULT_HOSTNAME}/api/v1`);
169
+ const workspaceId = clean(options.workspaceId, DEFAULT_WORKSPACE_ID);
170
+ const machineId = clean(options.machineId, "spark01");
171
+ const privateKeyFile = clean(options.probePrivateKeyFile, "~/.hasna/uptime/probes/spark01.key.pem");
172
+ const probeId = options.probeId?.trim();
173
+ const blockers = [
174
+ ...probeId ? [] : ["Cloud-registered private probe id is required before writing a sourceable env file."],
175
+ "Hosted probe claim and submit routes still fail closed until cloud check_jobs and workspace stores are implemented.",
176
+ "Spark01 enrollment, heartbeat, revocation, rotation, and bounded offline lease handling are not implemented yet."
177
+ ];
178
+ const env = {
179
+ HASNA_UPTIME_MODE: "hosted",
180
+ HASNA_UPTIME_API_URL: apiUrl,
181
+ HASNA_UPTIME_WORKSPACE_ID: workspaceId,
182
+ HASNA_UPTIME_MACHINE_ID: machineId,
183
+ HASNA_UPTIME_PRIVATE_PROBE_KEY_FILE: privateKeyFile,
184
+ HASNA_UPTIME_PROBE_CLASS: "private",
185
+ HASNA_UPTIME_LOG_LEVEL: clean(options.logLevel, "info")
186
+ };
187
+ if (probeId)
188
+ env.HASNA_UPTIME_PRIVATE_PROBE_ID = probeId;
189
+ return {
190
+ kind: "open-uptime.spark01-cloud-config",
191
+ version: 1,
192
+ generatedAt: new Date().toISOString(),
193
+ status: "blocked",
194
+ canStart: false,
195
+ machineId,
196
+ mode: "private-probe",
197
+ env,
198
+ files: [
199
+ {
200
+ path: privateKeyFile,
201
+ mode: "0600",
202
+ purpose: "Ed25519 private key generated on Spark01; never paste into cloud config."
203
+ },
204
+ {
205
+ path: "~/.hasna/uptime/cloud.env",
206
+ mode: "0600",
207
+ purpose: "Non-secret cloud/probe runtime environment; token values stay in the machine secret store."
208
+ }
209
+ ],
210
+ commands: [
211
+ "bun install -g @hasna/uptime@latest",
212
+ "Generate the Spark01 private key locally and register only its public key with the hosted control plane once registration exists.",
213
+ "Write ~/.hasna/uptime/cloud.env from this plan, then source it for the private probe service.",
214
+ "Start the private probe worker only after hosted /api/v1 probe claim/submit routes are backed by cloud jobs."
215
+ ],
216
+ blockers,
217
+ safety: {
218
+ privateKeyInline: false,
219
+ tokenInline: false,
220
+ notes: [
221
+ "This config is cloud-primary: Spark01 submits to hosted API state instead of local SQLite.",
222
+ "The private key file path is referenced, not embedded.",
223
+ "Hosted token or probe auth material must come from the machine secret store, not this generated config."
224
+ ]
225
+ }
226
+ };
227
+ }
228
+ function renderSpark01Env(config) {
229
+ const required = ["HASNA_UPTIME_PRIVATE_PROBE_ID"];
230
+ const missing = required.filter((key) => !config.env[key]);
231
+ if (missing.length > 0) {
232
+ throw new Error(`Spark01 env output requires ${missing.join(", ")}`);
233
+ }
234
+ return Object.entries(config.env).map(([key, value]) => `${key}=${shellEscape(value)}`).join(`
235
+ `);
236
+ }
237
+ function servicePlan(prefix, stage, role, desiredCount, image, workspaceId, secrets, environment) {
238
+ const name = `${prefix}-${stage}-${role}`;
239
+ return {
240
+ name,
241
+ role,
242
+ desiredCount,
243
+ taskRole: `${name}-task-role`,
244
+ executionRole: `${prefix}-${stage}-execution-role`,
245
+ logGroup: `/ecs/${name}`,
246
+ healthCommand: role === "web" ? "GET /health" : undefined,
247
+ environment: {
248
+ HASNA_UPTIME_IMAGE: image,
249
+ ...environment
250
+ },
251
+ secrets: role === "public-probe" ? { DATABASE_URL: secrets.database, PROBE_CONFIG: secrets.publicProbe } : role === "reporter" ? { DATABASE_URL: secrets.database, REPORTING_CONFIG: secrets.reporting } : { DATABASE_URL: secrets.database, APP_ENV: secrets.appEnv }
252
+ };
253
+ }
254
+ function clean(value, fallback) {
255
+ const normalized = value?.trim();
256
+ return normalized || fallback;
257
+ }
258
+ function shellEscape(value) {
259
+ if (/^[A-Za-z0-9_./:@~-]+$/.test(value))
260
+ return value;
261
+ return `'${value.replace(/'/g, "'\\''")}'`;
262
+ }
263
+ export {
264
+ renderSpark01Env,
265
+ buildSpark01CloudConfig,
266
+ buildAwsDeploymentPlan
267
+ };
package/dist/index.d.ts CHANGED
@@ -5,11 +5,13 @@ export { createApiHandler, serveUptime } from "./api.js";
5
5
  export { applyImport, previewImport, rollbackImport } from "./imports.js";
6
6
  export { buildUptimeReport, sendUptimeReport } from "./report.js";
7
7
  export { generateProbeKeyPair, probePublicKeyFingerprint, probeResultSigningPayload, signProbeResult, verifyProbeResultSignature } from "./probes.js";
8
+ export { buildAwsDeploymentPlan, buildSpark01CloudConfig, renderSpark01Env } from "./cloud-plan.js";
8
9
  export { uptimeHome, uptimeDbPath, uptimeHostedFallbackDbPath, ensureUptimeHome } from "./paths.js";
9
10
  export type { UptimeBackup, UptimeBackupCheck, UptimeRuntimeMode, UptimeStoreOptions, MonitorProvenance, SaveImportBatchInput, StoredImportBatch, UpsertMonitorProvenanceInput, } from "./store.js";
10
11
  export type { BrowserPageRunner, BrowserPageRunnerResult, FetchLike, } from "./checks.js";
11
12
  export type { ImportAction, ImportApplyItem, ImportApplyResult, ImportCandidate, ImportPreview, ImportPreviewItem, ImportRequest, ImportRollbackItem, ImportRollbackResult, ImportSource, } from "./imports.js";
12
- export type { BrowserFailedRequest, BrowserPageEvidence, CheckAttemptResult, CheckEvidence, CheckResult, CheckStatus, CreateMonitorKind, CreateMonitorInput, ImportedMonitorInput, ImportedUpdateMonitorInput, EvidenceArtifact, Incident, IncidentStatus, ListResultsOptions, Monitor, MonitorKind, MonitorStatus, MonitorSummary, ProbeCheckJob, ProbeCheckJobStatus, ProbeIdentity, ProbeResultSubmission, ProbeSubmissionReceipt, SchedulerHandle, UpdateMonitorInput, UptimeSummary, } from "./types.js";
13
+ export type { BrowserFailedRequest, BrowserPageEvidence, AuditEvent, CheckAttemptResult, CheckEvidence, CheckResult, CheckStatus, CreateMonitorKind, CreateMonitorInput, CreateReportScheduleInput, ImportedMonitorInput, ImportedUpdateMonitorInput, EvidenceArtifact, Incident, IncidentStatus, ListAuditEventsOptions, ListReportRunsOptions, ListResultsOptions, Monitor, MonitorKind, MonitorStatus, MonitorSummary, ProbeCheckJob, ProbeCheckJobStatus, ProbeIdentity, ProbeResultSubmission, ProbeSubmissionReceipt, RecordAuditEventInput, ReportDeliveryChannel, ReportDeliveryRecord, ReportEmailChannelConfig, ReportLogsChannelConfig, ReportRun, ReportRunStatus, ReportSchedule, ReportScheduleChannels, ReportScheduleStatus, ReportSmsChannelConfig, SchedulerHandle, UpdateMonitorInput, UpdateReportScheduleInput, UptimeSummary, } from "./types.js";
13
14
  export type { ProbeKeyPair, ProbeSigningInput } from "./probes.js";
15
+ export type { AwsDeploymentPlan, AwsDeploymentPlanOptions, AwsServicePlan, Spark01CloudConfig, Spark01CloudConfigOptions, } from "./cloud-plan.js";
14
16
  export type { BuildUptimeReportOptions, SendUptimeReportOptions, UptimeEmailReportTarget, UptimeLogsReportTarget, UptimeReport, UptimeReportDelivery, UptimeSmsReportTarget, } from "./report.js";
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACtJ,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpG,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,kBAAkB,EAClB,OAAO,EACP,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACtJ,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpG,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACpG,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,uBAAuB,EACvB,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,OAAO,EACP,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,EACvB,SAAS,EACT,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}