@grapity/grapity 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/dist/assets/index-Dq5tdnlb.js.map +1 -1
- package/dist/cli/index.js +631 -75
- package/dist/registry/{index-Baj_sSgl.d.ts → index-DUPbMrAe.d.ts} +3 -11
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +1 -3
- package/dist/registry/serve.d.ts +95 -5
- package/dist/registry/serve.js +517 -19
- package/package.json +1 -5
package/dist/registry/serve.js
CHANGED
|
@@ -1635,9 +1635,9 @@ var RegistryService = class {
|
|
|
1635
1635
|
return { spec, version, compatReport, isNewSpec };
|
|
1636
1636
|
}
|
|
1637
1637
|
async listSpecs(filters) {
|
|
1638
|
-
const
|
|
1638
|
+
const specs3 = await this.store.listSpecs(filters);
|
|
1639
1639
|
return Promise.all(
|
|
1640
|
-
|
|
1640
|
+
specs3.map(async (spec) => {
|
|
1641
1641
|
const latestVersion = await this.store.getLatestVersion(spec.name);
|
|
1642
1642
|
return { ...spec, latestVersion: latestVersion ?? void 0 };
|
|
1643
1643
|
})
|
|
@@ -1895,8 +1895,8 @@ var listRoute = new Hono3().get("/", async (c) => {
|
|
|
1895
1895
|
const type = c.req.query("type");
|
|
1896
1896
|
const owner = c.req.query("owner");
|
|
1897
1897
|
const tags = c.req.query("tags")?.split(",");
|
|
1898
|
-
const
|
|
1899
|
-
return c.json({ data:
|
|
1898
|
+
const specs3 = await service.listSpecs({ type, owner, tags });
|
|
1899
|
+
return c.json({ data: specs3 });
|
|
1900
1900
|
});
|
|
1901
1901
|
|
|
1902
1902
|
// src/registry/routes/get-spec.ts
|
|
@@ -2530,8 +2530,7 @@ function switchTab(tab) {
|
|
|
2530
2530
|
}
|
|
2531
2531
|
var welcomeRoute = new Hono12().get("/", (c) => {
|
|
2532
2532
|
const config = c.get("config");
|
|
2533
|
-
|
|
2534
|
-
return c.html(buildPage(config.port, mode));
|
|
2533
|
+
return c.html(buildPage(config.port, "local"));
|
|
2535
2534
|
});
|
|
2536
2535
|
|
|
2537
2536
|
// src/registry/routes/push-gateway-config.ts
|
|
@@ -2872,7 +2871,6 @@ var ingestGatewayLogRoute = new Hono18().post("/ingest/:provider/:environment",
|
|
|
2872
2871
|
await service.ingestLog(provider, environment, payload);
|
|
2873
2872
|
return c.json({ status: "ok" }, 201);
|
|
2874
2873
|
} catch (err) {
|
|
2875
|
-
console.error("Gateway log ingest error:", err);
|
|
2876
2874
|
return c.json({
|
|
2877
2875
|
error: "bad_request",
|
|
2878
2876
|
message: err instanceof Error ? err.message : "Invalid log payload",
|
|
@@ -2985,9 +2983,7 @@ function createApp(config, store) {
|
|
|
2985
2983
|
// src/registry/config.ts
|
|
2986
2984
|
var defaultConfig = {
|
|
2987
2985
|
port: 3750,
|
|
2988
|
-
database: "sqlite"
|
|
2989
|
-
sqlitePath: void 0,
|
|
2990
|
-
gracePeriodDays: 30
|
|
2986
|
+
database: "sqlite"
|
|
2991
2987
|
};
|
|
2992
2988
|
|
|
2993
2989
|
// src/registry/storage/sqlite.ts
|
|
@@ -3493,27 +3489,529 @@ var SQLiteSpecStore = class {
|
|
|
3493
3489
|
}
|
|
3494
3490
|
};
|
|
3495
3491
|
|
|
3492
|
+
// src/registry/storage/postgresql.ts
|
|
3493
|
+
import { Pool } from "pg";
|
|
3494
|
+
import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
|
|
3495
|
+
import { migrate as migrate2 } from "drizzle-orm/node-postgres/migrator";
|
|
3496
|
+
import { eq as eq2, and as and2, desc as desc2, sql as sql2 } from "drizzle-orm";
|
|
3497
|
+
|
|
3498
|
+
// src/registry/storage/schema-pg.ts
|
|
3499
|
+
import { pgTable, text as text2, timestamp, boolean, jsonb, index as index2, integer as integer2 } from "drizzle-orm/pg-core";
|
|
3500
|
+
var specs2 = pgTable("specs", {
|
|
3501
|
+
id: text2("id").primaryKey(),
|
|
3502
|
+
name: text2("name").notNull().unique(),
|
|
3503
|
+
type: text2("type", { enum: ["openapi", "asyncapi"] }).notNull(),
|
|
3504
|
+
description: text2("description"),
|
|
3505
|
+
owner: text2("owner"),
|
|
3506
|
+
sourceRepo: text2("source_repo"),
|
|
3507
|
+
tags: jsonb("tags").$type().default([]),
|
|
3508
|
+
createdAt: timestamp("created_at").notNull(),
|
|
3509
|
+
updatedAt: timestamp("updated_at").notNull()
|
|
3510
|
+
});
|
|
3511
|
+
var specVersions2 = pgTable("spec_versions", {
|
|
3512
|
+
id: text2("id").primaryKey(),
|
|
3513
|
+
specId: text2("spec_id").notNull().references(() => specs2.id),
|
|
3514
|
+
semver: text2("semver").notNull(),
|
|
3515
|
+
content: text2("content").notNull(),
|
|
3516
|
+
checksum: text2("checksum").notNull(),
|
|
3517
|
+
gitRef: text2("git_ref"),
|
|
3518
|
+
pushedBy: text2("pushed_by"),
|
|
3519
|
+
compatibility: jsonb("compatibility").$type(),
|
|
3520
|
+
previousVersion: text2("previous_version"),
|
|
3521
|
+
forceReason: text2("force_reason"),
|
|
3522
|
+
isPrerelease: boolean("is_prerelease").notNull().default(false),
|
|
3523
|
+
createdAt: timestamp("created_at").notNull()
|
|
3524
|
+
}, (table) => [
|
|
3525
|
+
index2("idx_spec_versions_spec_id").on(table.specId),
|
|
3526
|
+
index2("idx_spec_versions_semver").on(table.specId, table.semver)
|
|
3527
|
+
]);
|
|
3528
|
+
var auditLog2 = pgTable("audit_log", {
|
|
3529
|
+
id: text2("id").primaryKey(),
|
|
3530
|
+
action: text2("action", { enum: ["spec.push", "spec.push.force", "spec.delete"] }).notNull(),
|
|
3531
|
+
actor: text2("actor").notNull(),
|
|
3532
|
+
specName: text2("spec_name").notNull(),
|
|
3533
|
+
version: text2("version"),
|
|
3534
|
+
details: jsonb("details").$type(),
|
|
3535
|
+
createdAt: timestamp("created_at").notNull()
|
|
3536
|
+
}, (table) => [
|
|
3537
|
+
index2("idx_audit_log_spec_name").on(table.specName),
|
|
3538
|
+
index2("idx_audit_log_created_at").on(table.createdAt)
|
|
3539
|
+
]);
|
|
3540
|
+
var gatewayConfigs2 = pgTable("gateway_configs", {
|
|
3541
|
+
id: text2("id").primaryKey(),
|
|
3542
|
+
name: text2("name").notNull().unique(),
|
|
3543
|
+
provider: text2("provider", { enum: ["kong"] }).notNull(),
|
|
3544
|
+
specName: text2("spec_name").notNull(),
|
|
3545
|
+
specSemver: text2("spec_semver").notNull(),
|
|
3546
|
+
createdAt: timestamp("created_at").notNull(),
|
|
3547
|
+
updatedAt: timestamp("updated_at").notNull()
|
|
3548
|
+
});
|
|
3549
|
+
var gatewayConfigVersions2 = pgTable("gateway_config_versions", {
|
|
3550
|
+
id: text2("id").primaryKey(),
|
|
3551
|
+
gatewayConfigId: text2("gateway_config_id").notNull().references(() => gatewayConfigs2.id),
|
|
3552
|
+
routes: jsonb("routes").$type().notNull(),
|
|
3553
|
+
environments: jsonb("environments").$type().notNull(),
|
|
3554
|
+
callerIdentification: jsonb("caller_identification").$type(),
|
|
3555
|
+
content: text2("content").notNull(),
|
|
3556
|
+
checksum: text2("checksum").notNull(),
|
|
3557
|
+
pushedBy: text2("pushed_by"),
|
|
3558
|
+
createdAt: timestamp("created_at").notNull()
|
|
3559
|
+
}, (table) => [
|
|
3560
|
+
index2("idx_gateway_config_versions_config_id").on(table.gatewayConfigId)
|
|
3561
|
+
]);
|
|
3562
|
+
var httpLogs2 = pgTable("http_logs", {
|
|
3563
|
+
id: text2("id").primaryKey(),
|
|
3564
|
+
provider: text2("provider").notNull(),
|
|
3565
|
+
gatewayConfigName: text2("gateway_config_name").notNull(),
|
|
3566
|
+
environment: text2("environment").notNull(),
|
|
3567
|
+
method: text2("method").notNull(),
|
|
3568
|
+
path: text2("path").notNull(),
|
|
3569
|
+
routePath: text2("route_path"),
|
|
3570
|
+
status: integer2("status").notNull(),
|
|
3571
|
+
callerId: text2("caller_id"),
|
|
3572
|
+
callerSource: text2("caller_source"),
|
|
3573
|
+
callerConfidence: text2("caller_confidence").notNull(),
|
|
3574
|
+
occurredAt: timestamp("occurred_at").notNull(),
|
|
3575
|
+
createdAt: timestamp("created_at").notNull()
|
|
3576
|
+
}, (table) => [
|
|
3577
|
+
index2("idx_http_logs_config_env").on(table.gatewayConfigName, table.environment),
|
|
3578
|
+
index2("idx_http_logs_occurred_at").on(table.occurredAt),
|
|
3579
|
+
index2("idx_http_logs_caller").on(table.gatewayConfigName, table.environment, table.callerId)
|
|
3580
|
+
]);
|
|
3581
|
+
var provisions2 = pgTable("provisions", {
|
|
3582
|
+
id: text2("id").primaryKey(),
|
|
3583
|
+
gatewayConfigName: text2("gateway_config_name").notNull(),
|
|
3584
|
+
gatewayConfigVersion: text2("gateway_config_version").notNull(),
|
|
3585
|
+
environment: text2("environment").notNull(),
|
|
3586
|
+
provider: text2("provider", { enum: ["kong"] }).notNull(),
|
|
3587
|
+
synced: boolean("synced").notNull().default(false),
|
|
3588
|
+
actor: text2("actor").notNull(),
|
|
3589
|
+
details: jsonb("details").$type(),
|
|
3590
|
+
createdAt: timestamp("created_at").notNull()
|
|
3591
|
+
}, (table) => [
|
|
3592
|
+
index2("idx_provisions_config_name").on(table.gatewayConfigName),
|
|
3593
|
+
index2("idx_provisions_created_at").on(table.createdAt)
|
|
3594
|
+
]);
|
|
3595
|
+
|
|
3596
|
+
// src/registry/storage/postgresql.ts
|
|
3597
|
+
import { v4 as uuid6 } from "uuid";
|
|
3598
|
+
var MIGRATIONS_FOLDER2 = PG_MIGRATIONS_FOLDER;
|
|
3599
|
+
var PostgreSQLSpecStore = class {
|
|
3600
|
+
db;
|
|
3601
|
+
pool;
|
|
3602
|
+
constructor(postgresUrl) {
|
|
3603
|
+
this.pool = new Pool({ connectionString: postgresUrl });
|
|
3604
|
+
this.db = drizzle2(this.pool);
|
|
3605
|
+
}
|
|
3606
|
+
async migrate() {
|
|
3607
|
+
await migrate2(this.db, {
|
|
3608
|
+
migrationsFolder: MIGRATIONS_FOLDER2
|
|
3609
|
+
});
|
|
3610
|
+
}
|
|
3611
|
+
async end() {
|
|
3612
|
+
await this.pool.end();
|
|
3613
|
+
}
|
|
3614
|
+
async getSpec(name) {
|
|
3615
|
+
const rows = await this.db.select().from(specs2).where(eq2(specs2.name, name)).limit(1);
|
|
3616
|
+
if (rows.length === 0) return null;
|
|
3617
|
+
return this.mapSpecRow(rows[0]);
|
|
3618
|
+
}
|
|
3619
|
+
async getSpecVersion(name, semver) {
|
|
3620
|
+
const spec = await this.getSpec(name);
|
|
3621
|
+
if (!spec) return null;
|
|
3622
|
+
const rows = await this.db.select().from(specVersions2).where(and2(eq2(specVersions2.specId, spec.id), eq2(specVersions2.semver, semver))).limit(1);
|
|
3623
|
+
if (rows.length === 0) return null;
|
|
3624
|
+
return this.mapVersionRow(rows[0]);
|
|
3625
|
+
}
|
|
3626
|
+
async getLatestVersion(name) {
|
|
3627
|
+
const spec = await this.getSpec(name);
|
|
3628
|
+
if (!spec) return null;
|
|
3629
|
+
const rows = await this.db.select().from(specVersions2).where(eq2(specVersions2.specId, spec.id)).orderBy(desc2(specVersions2.createdAt), desc2(specVersions2.id)).limit(1);
|
|
3630
|
+
if (rows.length === 0) return null;
|
|
3631
|
+
return this.mapVersionRow(rows[0]);
|
|
3632
|
+
}
|
|
3633
|
+
async listSpecs(filters) {
|
|
3634
|
+
const conditions = [];
|
|
3635
|
+
if (filters?.type) conditions.push(eq2(specs2.type, filters.type));
|
|
3636
|
+
if (filters?.owner) conditions.push(eq2(specs2.owner, filters.owner));
|
|
3637
|
+
let rows = conditions.length > 0 ? await this.db.select().from(specs2).where(and2(...conditions)) : await this.db.select().from(specs2);
|
|
3638
|
+
if (filters?.tags && filters.tags.length > 0) {
|
|
3639
|
+
rows = rows.filter((row) => {
|
|
3640
|
+
const rowTags = row.tags ?? [];
|
|
3641
|
+
return filters.tags.every((tag) => rowTags.includes(tag));
|
|
3642
|
+
});
|
|
3643
|
+
}
|
|
3644
|
+
return rows.map((r) => this.mapSpecRow(r));
|
|
3645
|
+
}
|
|
3646
|
+
async listVersions(name, options) {
|
|
3647
|
+
const spec = await this.getSpec(name);
|
|
3648
|
+
if (!spec) return { versions: [], total: 0 };
|
|
3649
|
+
const limit = options?.limit ?? 10;
|
|
3650
|
+
const offset = options?.offset ?? 0;
|
|
3651
|
+
const [countRow] = await this.db.select({ count: sql2`count(*)` }).from(specVersions2).where(eq2(specVersions2.specId, spec.id));
|
|
3652
|
+
const total = Number(countRow?.count ?? 0);
|
|
3653
|
+
const rows = await this.db.select().from(specVersions2).where(eq2(specVersions2.specId, spec.id)).orderBy(desc2(specVersions2.createdAt), desc2(specVersions2.id)).limit(limit).offset(offset);
|
|
3654
|
+
return { versions: rows.map((r) => this.mapVersionRow(r)), total };
|
|
3655
|
+
}
|
|
3656
|
+
async pushSpecVersion(spec, version) {
|
|
3657
|
+
const existingSpec = await this.getSpec(spec.name);
|
|
3658
|
+
if (!existingSpec) {
|
|
3659
|
+
await this.db.insert(specs2).values({
|
|
3660
|
+
id: spec.id,
|
|
3661
|
+
name: spec.name,
|
|
3662
|
+
type: spec.type,
|
|
3663
|
+
description: spec.description ?? null,
|
|
3664
|
+
owner: spec.owner ?? null,
|
|
3665
|
+
sourceRepo: spec.sourceRepo ?? null,
|
|
3666
|
+
tags: spec.tags ?? [],
|
|
3667
|
+
createdAt: spec.createdAt,
|
|
3668
|
+
updatedAt: spec.updatedAt
|
|
3669
|
+
});
|
|
3670
|
+
} else {
|
|
3671
|
+
await this.db.update(specs2).set({ updatedAt: /* @__PURE__ */ new Date() }).where(eq2(specs2.id, existingSpec.id));
|
|
3672
|
+
}
|
|
3673
|
+
const specId = existingSpec?.id ?? spec.id;
|
|
3674
|
+
await this.db.insert(specVersions2).values({
|
|
3675
|
+
id: version.id,
|
|
3676
|
+
specId,
|
|
3677
|
+
semver: version.semver,
|
|
3678
|
+
content: version.content,
|
|
3679
|
+
checksum: version.checksum,
|
|
3680
|
+
gitRef: version.gitRef ?? null,
|
|
3681
|
+
pushedBy: version.pushedBy ?? null,
|
|
3682
|
+
compatibility: version.compatibility ?? null,
|
|
3683
|
+
previousVersion: version.previousVersion ?? null,
|
|
3684
|
+
forceReason: version.forceReason ?? null,
|
|
3685
|
+
isPrerelease: version.isPrerelease,
|
|
3686
|
+
createdAt: version.createdAt
|
|
3687
|
+
});
|
|
3688
|
+
return version;
|
|
3689
|
+
}
|
|
3690
|
+
async deleteSpec(name) {
|
|
3691
|
+
const existingSpec = await this.getSpec(name);
|
|
3692
|
+
if (!existingSpec) return false;
|
|
3693
|
+
await this.db.delete(specVersions2).where(eq2(specVersions2.specId, existingSpec.id));
|
|
3694
|
+
await this.db.delete(specs2).where(eq2(specs2.id, existingSpec.id));
|
|
3695
|
+
return true;
|
|
3696
|
+
}
|
|
3697
|
+
async getCompatReport(name, semver) {
|
|
3698
|
+
const version = await this.getSpecVersion(name, semver);
|
|
3699
|
+
return version?.compatibility ?? null;
|
|
3700
|
+
}
|
|
3701
|
+
async logAudit(action, actor, specName, version, details) {
|
|
3702
|
+
await this.db.insert(auditLog2).values({
|
|
3703
|
+
id: uuid6(),
|
|
3704
|
+
action,
|
|
3705
|
+
actor,
|
|
3706
|
+
specName,
|
|
3707
|
+
version: version ?? null,
|
|
3708
|
+
details: details ?? null,
|
|
3709
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3710
|
+
});
|
|
3711
|
+
}
|
|
3712
|
+
mapSpecRow(row) {
|
|
3713
|
+
return {
|
|
3714
|
+
id: row.id,
|
|
3715
|
+
name: row.name,
|
|
3716
|
+
type: row.type,
|
|
3717
|
+
description: row.description ?? void 0,
|
|
3718
|
+
owner: row.owner ?? void 0,
|
|
3719
|
+
sourceRepo: row.sourceRepo ?? void 0,
|
|
3720
|
+
tags: row.tags ?? [],
|
|
3721
|
+
createdAt: row.createdAt,
|
|
3722
|
+
updatedAt: row.updatedAt
|
|
3723
|
+
};
|
|
3724
|
+
}
|
|
3725
|
+
mapVersionRow(row) {
|
|
3726
|
+
return {
|
|
3727
|
+
id: row.id,
|
|
3728
|
+
specId: row.specId,
|
|
3729
|
+
semver: row.semver,
|
|
3730
|
+
content: row.content,
|
|
3731
|
+
checksum: row.checksum,
|
|
3732
|
+
gitRef: row.gitRef ?? void 0,
|
|
3733
|
+
pushedBy: row.pushedBy ?? void 0,
|
|
3734
|
+
compatibility: row.compatibility ?? void 0,
|
|
3735
|
+
previousVersion: row.previousVersion ?? void 0,
|
|
3736
|
+
forceReason: row.forceReason ?? void 0,
|
|
3737
|
+
isPrerelease: row.isPrerelease,
|
|
3738
|
+
createdAt: row.createdAt
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3741
|
+
// GatewayConfigStore implementation
|
|
3742
|
+
async getGatewayConfig(name) {
|
|
3743
|
+
const rows = await this.db.select().from(gatewayConfigs2).where(eq2(gatewayConfigs2.name, name)).limit(1);
|
|
3744
|
+
if (rows.length === 0) return null;
|
|
3745
|
+
return this.mapGatewayConfigRow(rows[0]);
|
|
3746
|
+
}
|
|
3747
|
+
async listGatewayConfigs() {
|
|
3748
|
+
const rows = await this.db.select().from(gatewayConfigs2);
|
|
3749
|
+
return rows.map((r) => this.mapGatewayConfigRow(r));
|
|
3750
|
+
}
|
|
3751
|
+
async getGatewayConfigVersion(name, versionId) {
|
|
3752
|
+
const config = await this.getGatewayConfig(name);
|
|
3753
|
+
if (!config) return null;
|
|
3754
|
+
const rows = await this.db.select().from(gatewayConfigVersions2).where(and2(eq2(gatewayConfigVersions2.gatewayConfigId, config.id), eq2(gatewayConfigVersions2.id, versionId))).limit(1);
|
|
3755
|
+
if (rows.length === 0) return null;
|
|
3756
|
+
return this.mapGatewayConfigVersionRow(rows[0]);
|
|
3757
|
+
}
|
|
3758
|
+
async getLatestGatewayConfigVersion(name) {
|
|
3759
|
+
const config = await this.getGatewayConfig(name);
|
|
3760
|
+
if (!config) return null;
|
|
3761
|
+
const rows = await this.db.select().from(gatewayConfigVersions2).where(eq2(gatewayConfigVersions2.gatewayConfigId, config.id)).orderBy(desc2(gatewayConfigVersions2.createdAt), desc2(gatewayConfigVersions2.id)).limit(1);
|
|
3762
|
+
if (rows.length === 0) return null;
|
|
3763
|
+
return this.mapGatewayConfigVersionRow(rows[0]);
|
|
3764
|
+
}
|
|
3765
|
+
async listGatewayConfigVersions(name) {
|
|
3766
|
+
const config = await this.getGatewayConfig(name);
|
|
3767
|
+
if (!config) return [];
|
|
3768
|
+
const rows = await this.db.select().from(gatewayConfigVersions2).where(eq2(gatewayConfigVersions2.gatewayConfigId, config.id)).orderBy(desc2(gatewayConfigVersions2.createdAt), desc2(gatewayConfigVersions2.id)).limit(5);
|
|
3769
|
+
return rows.map((r) => this.mapGatewayConfigVersionRow(r));
|
|
3770
|
+
}
|
|
3771
|
+
async pushGatewayConfigVersion(config, version) {
|
|
3772
|
+
const existingConfig = await this.getGatewayConfig(config.name);
|
|
3773
|
+
if (!existingConfig) {
|
|
3774
|
+
await this.db.insert(gatewayConfigs2).values({
|
|
3775
|
+
id: config.id,
|
|
3776
|
+
name: config.name,
|
|
3777
|
+
provider: config.provider,
|
|
3778
|
+
specName: config.specName,
|
|
3779
|
+
specSemver: config.specSemver,
|
|
3780
|
+
createdAt: config.createdAt,
|
|
3781
|
+
updatedAt: config.updatedAt
|
|
3782
|
+
});
|
|
3783
|
+
} else {
|
|
3784
|
+
await this.db.update(gatewayConfigs2).set({ updatedAt: /* @__PURE__ */ new Date(), specSemver: config.specSemver }).where(eq2(gatewayConfigs2.id, existingConfig.id));
|
|
3785
|
+
}
|
|
3786
|
+
const configId = existingConfig?.id ?? config.id;
|
|
3787
|
+
await this.db.insert(gatewayConfigVersions2).values({
|
|
3788
|
+
id: version.id,
|
|
3789
|
+
gatewayConfigId: configId,
|
|
3790
|
+
routes: version.routes,
|
|
3791
|
+
environments: version.environments,
|
|
3792
|
+
callerIdentification: version.callerIdentification ?? null,
|
|
3793
|
+
content: version.content,
|
|
3794
|
+
checksum: version.checksum,
|
|
3795
|
+
pushedBy: version.pushedBy ?? null,
|
|
3796
|
+
createdAt: version.createdAt
|
|
3797
|
+
});
|
|
3798
|
+
const versions = await this.db.select().from(gatewayConfigVersions2).where(eq2(gatewayConfigVersions2.gatewayConfigId, configId)).orderBy(desc2(gatewayConfigVersions2.createdAt), desc2(gatewayConfigVersions2.id));
|
|
3799
|
+
if (versions.length > 5) {
|
|
3800
|
+
const toDelete = versions.slice(5);
|
|
3801
|
+
for (const v of toDelete) {
|
|
3802
|
+
await this.db.delete(gatewayConfigVersions2).where(eq2(gatewayConfigVersions2.id, v.id));
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
return version;
|
|
3806
|
+
}
|
|
3807
|
+
async recordProvision(provision) {
|
|
3808
|
+
await this.db.insert(provisions2).values({
|
|
3809
|
+
id: provision.id,
|
|
3810
|
+
gatewayConfigName: provision.gatewayConfigName,
|
|
3811
|
+
gatewayConfigVersion: provision.gatewayConfigVersion,
|
|
3812
|
+
environment: provision.environment,
|
|
3813
|
+
provider: provision.provider,
|
|
3814
|
+
synced: provision.synced,
|
|
3815
|
+
actor: provision.actor,
|
|
3816
|
+
details: provision.details ?? null,
|
|
3817
|
+
createdAt: provision.createdAt
|
|
3818
|
+
});
|
|
3819
|
+
}
|
|
3820
|
+
async listProvisions(gatewayConfigName) {
|
|
3821
|
+
const rows = gatewayConfigName ? await this.db.select().from(provisions2).where(eq2(provisions2.gatewayConfigName, gatewayConfigName)).orderBy(desc2(provisions2.createdAt)) : await this.db.select().from(provisions2).orderBy(desc2(provisions2.createdAt));
|
|
3822
|
+
return rows.map((r) => ({
|
|
3823
|
+
id: r.id,
|
|
3824
|
+
gatewayConfigName: r.gatewayConfigName,
|
|
3825
|
+
gatewayConfigVersion: r.gatewayConfigVersion,
|
|
3826
|
+
environment: r.environment,
|
|
3827
|
+
provider: r.provider,
|
|
3828
|
+
synced: r.synced,
|
|
3829
|
+
actor: r.actor,
|
|
3830
|
+
details: r.details ?? void 0,
|
|
3831
|
+
createdAt: r.createdAt
|
|
3832
|
+
}));
|
|
3833
|
+
}
|
|
3834
|
+
mapGatewayConfigRow(row) {
|
|
3835
|
+
return {
|
|
3836
|
+
id: row.id,
|
|
3837
|
+
name: row.name,
|
|
3838
|
+
provider: row.provider,
|
|
3839
|
+
specName: row.specName,
|
|
3840
|
+
specSemver: row.specSemver,
|
|
3841
|
+
createdAt: row.createdAt,
|
|
3842
|
+
updatedAt: row.updatedAt
|
|
3843
|
+
};
|
|
3844
|
+
}
|
|
3845
|
+
mapGatewayConfigVersionRow(row) {
|
|
3846
|
+
return {
|
|
3847
|
+
id: row.id,
|
|
3848
|
+
gatewayConfigId: row.gatewayConfigId,
|
|
3849
|
+
routes: row.routes,
|
|
3850
|
+
environments: row.environments,
|
|
3851
|
+
callerIdentification: row.callerIdentification ?? void 0,
|
|
3852
|
+
content: row.content,
|
|
3853
|
+
checksum: row.checksum,
|
|
3854
|
+
pushedBy: row.pushedBy ?? void 0,
|
|
3855
|
+
createdAt: row.createdAt
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
async recordGatewayLog(log) {
|
|
3859
|
+
await this.db.insert(httpLogs2).values({
|
|
3860
|
+
id: log.id,
|
|
3861
|
+
provider: log.provider,
|
|
3862
|
+
gatewayConfigName: log.gatewayConfigName,
|
|
3863
|
+
environment: log.environment,
|
|
3864
|
+
method: log.method,
|
|
3865
|
+
path: log.path,
|
|
3866
|
+
routePath: log.routePath ?? null,
|
|
3867
|
+
status: log.status,
|
|
3868
|
+
callerId: log.callerId ?? null,
|
|
3869
|
+
callerSource: log.callerSource ?? null,
|
|
3870
|
+
callerConfidence: log.callerConfidence,
|
|
3871
|
+
occurredAt: log.occurredAt,
|
|
3872
|
+
createdAt: log.createdAt
|
|
3873
|
+
});
|
|
3874
|
+
}
|
|
3875
|
+
async listGatewayLogs(filters) {
|
|
3876
|
+
const limit = filters.limit ?? 50;
|
|
3877
|
+
const offset = filters.offset ?? 0;
|
|
3878
|
+
let query = this.db.select().from(httpLogs2);
|
|
3879
|
+
const conditions = [];
|
|
3880
|
+
if (filters.gatewayConfigName) {
|
|
3881
|
+
conditions.push(eq2(httpLogs2.gatewayConfigName, filters.gatewayConfigName));
|
|
3882
|
+
}
|
|
3883
|
+
if (filters.environment) {
|
|
3884
|
+
conditions.push(eq2(httpLogs2.environment, filters.environment));
|
|
3885
|
+
}
|
|
3886
|
+
if (filters.path) {
|
|
3887
|
+
conditions.push(eq2(httpLogs2.path, filters.path));
|
|
3888
|
+
}
|
|
3889
|
+
if (filters.method) {
|
|
3890
|
+
conditions.push(eq2(httpLogs2.method, filters.method));
|
|
3891
|
+
}
|
|
3892
|
+
if (filters.status !== void 0) {
|
|
3893
|
+
conditions.push(eq2(httpLogs2.status, filters.status));
|
|
3894
|
+
}
|
|
3895
|
+
if (filters.from) {
|
|
3896
|
+
conditions.push(sql2`${httpLogs2.occurredAt} >= ${filters.from}`);
|
|
3897
|
+
}
|
|
3898
|
+
if (filters.to) {
|
|
3899
|
+
conditions.push(sql2`${httpLogs2.occurredAt} <= ${filters.to}`);
|
|
3900
|
+
}
|
|
3901
|
+
if (conditions.length > 0) {
|
|
3902
|
+
query = query.where(and2(...conditions));
|
|
3903
|
+
}
|
|
3904
|
+
const countResult = await this.db.select({ count: sql2`count(*)` }).from(httpLogs2).where(conditions.length > 0 ? and2(...conditions) : void 0);
|
|
3905
|
+
const total = countResult[0]?.count ?? 0;
|
|
3906
|
+
const rows = await query.orderBy(desc2(httpLogs2.occurredAt)).limit(limit).offset(offset);
|
|
3907
|
+
return {
|
|
3908
|
+
logs: rows.map((r) => ({
|
|
3909
|
+
id: r.id,
|
|
3910
|
+
provider: r.provider,
|
|
3911
|
+
gatewayConfigName: r.gatewayConfigName,
|
|
3912
|
+
environment: r.environment,
|
|
3913
|
+
method: r.method,
|
|
3914
|
+
path: r.path,
|
|
3915
|
+
routePath: r.routePath ?? void 0,
|
|
3916
|
+
status: r.status,
|
|
3917
|
+
callerId: r.callerId ?? void 0,
|
|
3918
|
+
callerSource: r.callerSource ?? void 0,
|
|
3919
|
+
callerConfidence: r.callerConfidence,
|
|
3920
|
+
occurredAt: r.occurredAt,
|
|
3921
|
+
createdAt: r.createdAt
|
|
3922
|
+
})),
|
|
3923
|
+
total
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
async getGatewayLog(id) {
|
|
3927
|
+
const rows = await this.db.select().from(httpLogs2).where(eq2(httpLogs2.id, id)).limit(1);
|
|
3928
|
+
if (rows.length === 0) return null;
|
|
3929
|
+
const r = rows[0];
|
|
3930
|
+
return {
|
|
3931
|
+
id: r.id,
|
|
3932
|
+
provider: r.provider,
|
|
3933
|
+
gatewayConfigName: r.gatewayConfigName,
|
|
3934
|
+
environment: r.environment,
|
|
3935
|
+
method: r.method,
|
|
3936
|
+
path: r.path,
|
|
3937
|
+
routePath: r.routePath ?? void 0,
|
|
3938
|
+
status: r.status,
|
|
3939
|
+
callerId: r.callerId ?? void 0,
|
|
3940
|
+
callerSource: r.callerSource ?? void 0,
|
|
3941
|
+
callerConfidence: r.callerConfidence,
|
|
3942
|
+
occurredAt: r.occurredAt,
|
|
3943
|
+
createdAt: r.createdAt
|
|
3944
|
+
};
|
|
3945
|
+
}
|
|
3946
|
+
async getGatewayLogStats(_filters) {
|
|
3947
|
+
const conditions = [];
|
|
3948
|
+
if (_filters.gatewayConfigName) {
|
|
3949
|
+
conditions.push(eq2(httpLogs2.gatewayConfigName, _filters.gatewayConfigName));
|
|
3950
|
+
}
|
|
3951
|
+
if (_filters.environment) {
|
|
3952
|
+
conditions.push(eq2(httpLogs2.environment, _filters.environment));
|
|
3953
|
+
}
|
|
3954
|
+
if (_filters.from) {
|
|
3955
|
+
conditions.push(sql2`${httpLogs2.occurredAt} >= ${_filters.from}`);
|
|
3956
|
+
}
|
|
3957
|
+
if (_filters.to) {
|
|
3958
|
+
conditions.push(sql2`${httpLogs2.occurredAt} <= ${_filters.to}`);
|
|
3959
|
+
}
|
|
3960
|
+
const whereClause = conditions.length > 0 ? and2(...conditions) : void 0;
|
|
3961
|
+
const rows = await this.db.select({
|
|
3962
|
+
gatewayConfigName: httpLogs2.gatewayConfigName,
|
|
3963
|
+
environment: httpLogs2.environment,
|
|
3964
|
+
method: httpLogs2.method,
|
|
3965
|
+
routePath: httpLogs2.routePath,
|
|
3966
|
+
lastSeenAt: sql2`max(${httpLogs2.occurredAt})`,
|
|
3967
|
+
totalCalls: sql2`count(*)`,
|
|
3968
|
+
uniqueCallerIds: sql2`count(distinct ${httpLogs2.callerId})`
|
|
3969
|
+
}).from(httpLogs2).where(whereClause).groupBy(httpLogs2.gatewayConfigName, httpLogs2.environment, httpLogs2.method, httpLogs2.routePath);
|
|
3970
|
+
return rows.map((r) => ({
|
|
3971
|
+
gatewayConfigName: r.gatewayConfigName,
|
|
3972
|
+
environment: r.environment,
|
|
3973
|
+
method: r.method,
|
|
3974
|
+
routePath: r.routePath ?? "/",
|
|
3975
|
+
lastSeenAt: new Date(r.lastSeenAt),
|
|
3976
|
+
totalCalls: r.totalCalls,
|
|
3977
|
+
uniqueCallerIds: r.uniqueCallerIds
|
|
3978
|
+
}));
|
|
3979
|
+
}
|
|
3980
|
+
async deleteGatewayLogsOlderThan(days) {
|
|
3981
|
+
const cutoff = /* @__PURE__ */ new Date();
|
|
3982
|
+
cutoff.setDate(cutoff.getDate() - days);
|
|
3983
|
+
await this.db.delete(httpLogs2).where(sql2`${httpLogs2.occurredAt} < ${cutoff}`);
|
|
3984
|
+
}
|
|
3985
|
+
};
|
|
3986
|
+
|
|
3496
3987
|
// src/registry/serve.ts
|
|
3497
3988
|
async function startServer(userConfig) {
|
|
3498
3989
|
const config = { ...defaultConfig, ...userConfig };
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3990
|
+
let store;
|
|
3991
|
+
if (config.database === "postgresql") {
|
|
3992
|
+
if (!config.postgresUrl) {
|
|
3993
|
+
throw new Error("PostgreSQL database requested but no postgresUrl provided.");
|
|
3994
|
+
}
|
|
3995
|
+
store = new PostgreSQLSpecStore(config.postgresUrl);
|
|
3996
|
+
} else {
|
|
3997
|
+
const sqlitePath = config.sqlitePath ?? path.join(
|
|
3998
|
+
process.env.HOME || process.env.USERPROFILE || ".",
|
|
3999
|
+
".grapity",
|
|
4000
|
+
"registry.db"
|
|
4001
|
+
);
|
|
4002
|
+
const dir = path.dirname(sqlitePath);
|
|
3505
4003
|
if (!fs.existsSync(dir)) {
|
|
3506
4004
|
fs.mkdirSync(dir, { recursive: true });
|
|
3507
4005
|
}
|
|
4006
|
+
store = new SQLiteSpecStore(sqlitePath);
|
|
3508
4007
|
}
|
|
3509
|
-
const store = new SQLiteSpecStore(config.sqlitePath);
|
|
3510
4008
|
await store.migrate();
|
|
3511
4009
|
const app = createApp(config, store);
|
|
3512
|
-
serve({
|
|
4010
|
+
const server = serve({
|
|
3513
4011
|
fetch: app.fetch,
|
|
3514
4012
|
port: config.port
|
|
3515
4013
|
});
|
|
3516
|
-
return app;
|
|
4014
|
+
return { app, store, server };
|
|
3517
4015
|
}
|
|
3518
4016
|
if (process.argv[1] === new URL(import.meta.url).pathname) {
|
|
3519
4017
|
startServer();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grapity/grapity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "grapity - API spec registry and compatibility guardian",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -59,10 +59,6 @@
|
|
|
59
59
|
"typecheck": "tsc --noEmit",
|
|
60
60
|
"test": "bun test",
|
|
61
61
|
"generate": "bun run scripts/generate-types.ts",
|
|
62
|
-
"db:generate:sqlite": "drizzle-kit generate --config drizzle/config.sqlite.ts",
|
|
63
|
-
"db:generate:pg": "drizzle-kit generate --config drizzle/config.pg.ts",
|
|
64
|
-
"db:migrate:sqlite": "drizzle-kit migrate --config drizzle/config.sqlite.ts",
|
|
65
|
-
"db:migrate:pg": "drizzle-kit migrate --config drizzle/config.pg.ts",
|
|
66
62
|
"prepublishOnly": "bun run build"
|
|
67
63
|
},
|
|
68
64
|
"publishConfig": {
|