@velora-cms/api-schemas 0.9.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/LICENSE +202 -0
- package/README.md +22 -0
- package/dist/api-error.schema.d.ts +5 -0
- package/dist/api-error.schema.js +6 -0
- package/dist/api-key-api.schema.d.ts +50 -0
- package/dist/api-key-api.schema.js +29 -0
- package/dist/auth.schema.d.ts +40 -0
- package/dist/auth.schema.js +30 -0
- package/dist/content-api.schema.d.ts +188 -0
- package/dist/content-api.schema.js +121 -0
- package/dist/content-trash-api.schema.d.ts +20 -0
- package/dist/content-trash-api.schema.js +23 -0
- package/dist/content-trash.schema.d.ts +31 -0
- package/dist/content-trash.schema.js +26 -0
- package/dist/content-version.schema.d.ts +11 -0
- package/dist/content-version.schema.js +10 -0
- package/dist/content.schema.d.ts +15 -0
- package/dist/content.schema.js +14 -0
- package/dist/data-type-api.schema.d.ts +36 -0
- package/dist/data-type-api.schema.js +32 -0
- package/dist/data-type-config.schema.d.ts +9 -0
- package/dist/data-type-config.schema.js +32 -0
- package/dist/document-type-api.schema.d.ts +202 -0
- package/dist/document-type-api.schema.js +86 -0
- package/dist/document-type.schema.d.ts +90 -0
- package/dist/document-type.schema.js +103 -0
- package/dist/health.schema.d.ts +6 -0
- package/dist/health.schema.js +5 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +27 -0
- package/dist/marketplace-listing-api.schema.d.ts +205 -0
- package/dist/marketplace-listing-api.schema.js +115 -0
- package/dist/media-api.schema.d.ts +36 -0
- package/dist/media-api.schema.js +23 -0
- package/dist/media.schema.d.ts +11 -0
- package/dist/media.schema.js +10 -0
- package/dist/plugin-management-api.schema.d.ts +145 -0
- package/dist/plugin-management-api.schema.js +186 -0
- package/dist/plugin-registry-api.schema.d.ts +31 -0
- package/dist/plugin-registry-api.schema.js +25 -0
- package/dist/plugin-storage-api.schema.d.ts +15 -0
- package/dist/plugin-storage-api.schema.js +24 -0
- package/dist/public-api.schema.d.ts +211 -0
- package/dist/public-api.schema.js +185 -0
- package/dist/setup-api.schema.d.ts +78 -0
- package/dist/setup-api.schema.js +88 -0
- package/dist/snapshot-api.schema.d.ts +43 -0
- package/dist/snapshot-api.schema.js +25 -0
- package/dist/snapshot.schema.d.ts +28 -0
- package/dist/snapshot.schema.js +17 -0
- package/dist/template-api.schema.d.ts +33 -0
- package/dist/template-api.schema.js +28 -0
- package/dist/template.schema.d.ts +7 -0
- package/dist/template.schema.js +13 -0
- package/dist/theme-api.schema.d.ts +21 -0
- package/dist/theme-api.schema.js +14 -0
- package/dist/user-api.schema.d.ts +79 -0
- package/dist/user-api.schema.js +36 -0
- package/package.json +26 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const MarketplaceListingVersionSchema = z.object({
|
|
3
|
+
version: z.string(),
|
|
4
|
+
supportedDialects: z.array(z.string()),
|
|
5
|
+
permissions: z.record(z.string(), z.boolean()),
|
|
6
|
+
license: z.string(),
|
|
7
|
+
cmsVersion: z.string(),
|
|
8
|
+
verified: z.boolean(),
|
|
9
|
+
createdAt: z.string(),
|
|
10
|
+
});
|
|
11
|
+
export const MarketplaceListingSchema = z.object({
|
|
12
|
+
pluginId: z.string(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
type: z.string(),
|
|
15
|
+
description: z.string(),
|
|
16
|
+
author: z.string(),
|
|
17
|
+
priceCents: z.number().int(),
|
|
18
|
+
coverImagePath: z.string().nullable(),
|
|
19
|
+
latestVersion: MarketplaceListingVersionSchema.nullable(),
|
|
20
|
+
// Computed SERVER-SIDE against this CMS's active dialect — the admin
|
|
21
|
+
// client never guesses compatibility from raw dialect lists.
|
|
22
|
+
compatible: z.boolean(),
|
|
23
|
+
});
|
|
24
|
+
// S148: a starter frontend the marketplace hosts as a versioned archive
|
|
25
|
+
// (Global Constraints — a bundledTemplate WITHOUT an archive stays legal,
|
|
26
|
+
// hence hasArchive rather than always assuming a download exists) and the
|
|
27
|
+
// document types a template/section listing provisions on install. Both
|
|
28
|
+
// are projected server-side by the marketplace (starter-projection.ts) and
|
|
29
|
+
// only ever appear on the DETAIL surface, never on browse — see
|
|
30
|
+
// MarketplaceListingDetailVersionSchema below.
|
|
31
|
+
export const MarketplaceStarterSchema = z.object({
|
|
32
|
+
name: z.string(),
|
|
33
|
+
description: z.string().nullable(),
|
|
34
|
+
repository: z.string().nullable(),
|
|
35
|
+
hasArchive: z.boolean(),
|
|
36
|
+
});
|
|
37
|
+
export const MarketplaceDocumentTypeSummarySchema = z.object({
|
|
38
|
+
name: z.string(),
|
|
39
|
+
fields: z.array(z.string()),
|
|
40
|
+
});
|
|
41
|
+
// S153: a bundle's enriched member projection — snapshotted at ingest by
|
|
42
|
+
// the marketplace (bundle-members.ts), detail-only like the S148 starter
|
|
43
|
+
// fields (same extend-don't-widen browse protection below).
|
|
44
|
+
export const MarketplaceBundleMemberSchema = z.object({
|
|
45
|
+
pluginId: z.string(),
|
|
46
|
+
name: z.string(),
|
|
47
|
+
description: z.string().nullable(),
|
|
48
|
+
type: z.string(),
|
|
49
|
+
priceCents: z.number().int(),
|
|
50
|
+
});
|
|
51
|
+
// Extends the base version shape rather than widening it: browse
|
|
52
|
+
// (MarketplaceListingSchema.latestVersion, MarketplaceListResponseSchema)
|
|
53
|
+
// keeps using MarketplaceListingVersionSchema untouched, so starter/
|
|
54
|
+
// documentTypesSummary can never leak onto the browse screen even though
|
|
55
|
+
// the upstream marketplace's JSON carries them on every version row.
|
|
56
|
+
export const MarketplaceListingDetailVersionSchema = MarketplaceListingVersionSchema.extend({
|
|
57
|
+
starter: MarketplaceStarterSchema.nullable().optional(),
|
|
58
|
+
documentTypesSummary: z.array(MarketplaceDocumentTypeSummarySchema).nullable().optional(),
|
|
59
|
+
bundledMembers: z.array(MarketplaceBundleMemberSchema).nullable().optional(),
|
|
60
|
+
});
|
|
61
|
+
export const MarketplaceListingDetailSchema = MarketplaceListingSchema.extend({
|
|
62
|
+
latestVersion: MarketplaceListingDetailVersionSchema.nullable(),
|
|
63
|
+
versions: z.array(MarketplaceListingDetailVersionSchema),
|
|
64
|
+
activeDialect: z.string(),
|
|
65
|
+
marketplaceBaseUrl: z.string(),
|
|
66
|
+
});
|
|
67
|
+
export const MarketplaceListQuerySchema = z.object({
|
|
68
|
+
q: z.string().optional(),
|
|
69
|
+
type: z.string().optional(),
|
|
70
|
+
db: z.string().optional(),
|
|
71
|
+
cursor: z.string().uuid().optional(),
|
|
72
|
+
limit: z.coerce.number().int().min(1).max(50).default(24),
|
|
73
|
+
});
|
|
74
|
+
export const MarketplaceListResponseSchema = z.object({
|
|
75
|
+
items: z.array(MarketplaceListingSchema),
|
|
76
|
+
nextCursor: z.string().nullable(),
|
|
77
|
+
activeDialect: z.string(),
|
|
78
|
+
marketplaceBaseUrl: z.string(),
|
|
79
|
+
});
|
|
80
|
+
export const MarketplacePluginIdParamsSchema = z.object({ pluginId: z.string().min(1) });
|
|
81
|
+
// Path-safety gate, mirroring install-built-package.ts's own reverse-domain
|
|
82
|
+
// id regex (its manifest.json id check, run before that id becomes a
|
|
83
|
+
// managed-store directory name): pluginId reaches removePluginPackages,
|
|
84
|
+
// which builds a path from it and does a recursive, forced rmSync. Without
|
|
85
|
+
// this, a bare `z.string().min(1)` would let a traversal-shaped id
|
|
86
|
+
// (`"../../etc"`) all the way to that filesystem call.
|
|
87
|
+
const PLUGIN_ID_PATTERN = /^[a-z0-9-]+(\.[a-z0-9-]+)+$/i;
|
|
88
|
+
export const MarketplaceInstallBodySchema = z.object({
|
|
89
|
+
pluginId: z
|
|
90
|
+
.string()
|
|
91
|
+
.min(1)
|
|
92
|
+
.regex(PLUGIN_ID_PATTERN, "pluginId must be a reverse-domain identifier (e.g. com.example.plugin)"),
|
|
93
|
+
version: z.string().min(1),
|
|
94
|
+
licenseKey: z.string().min(1).optional(),
|
|
95
|
+
});
|
|
96
|
+
// S152: a bundle install reports what its fan-out did per member —
|
|
97
|
+
// "installed" (this operation installed it, ownership recorded) or
|
|
98
|
+
// "already-installed" (pre-existing, skipped, never claimed). Optional
|
|
99
|
+
// and absent for every non-bundle install, so single-plugin clients are
|
|
100
|
+
// untouched.
|
|
101
|
+
export const MarketplaceInstallMemberSchema = z.object({
|
|
102
|
+
pluginId: z.string(),
|
|
103
|
+
version: z.string(),
|
|
104
|
+
outcome: z.enum(["installed", "already-installed"]),
|
|
105
|
+
});
|
|
106
|
+
// trustTier is a literal, not the broader TrustTier union — this door
|
|
107
|
+
// (S138) only ever answers 201 for a "verified" result; a non-"verified"
|
|
108
|
+
// verdict is a 422 failure response (ApiErrorSchema), never this shape.
|
|
109
|
+
export const MarketplaceInstallResponseSchema = z.object({
|
|
110
|
+
pluginId: z.string(),
|
|
111
|
+
version: z.string(),
|
|
112
|
+
trustTier: z.literal("verified"),
|
|
113
|
+
licensed: z.boolean(),
|
|
114
|
+
members: z.array(MarketplaceInstallMemberSchema).optional(),
|
|
115
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const MediaFileResponseSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
filename: z.ZodString;
|
|
5
|
+
mimeType: z.ZodString;
|
|
6
|
+
size: z.ZodNumber;
|
|
7
|
+
url: z.ZodString;
|
|
8
|
+
uploadedBy: z.ZodString;
|
|
9
|
+
uploadedAt: z.ZodString;
|
|
10
|
+
downloadUrl: z.ZodString;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
export type MediaFileResponse = z.infer<typeof MediaFileResponseSchema>;
|
|
13
|
+
export declare const MediaDeleteResponseSchema: z.ZodObject<{
|
|
14
|
+
success: z.ZodLiteral<true>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
export type MediaDeleteResponse = z.infer<typeof MediaDeleteResponseSchema>;
|
|
17
|
+
export declare const MediaListQuerySchema: z.ZodObject<{
|
|
18
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
19
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
20
|
+
search: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export type MediaListQuery = z.infer<typeof MediaListQuerySchema>;
|
|
23
|
+
export declare const MediaListResponseSchema: z.ZodObject<{
|
|
24
|
+
items: z.ZodArray<z.ZodObject<{
|
|
25
|
+
id: z.ZodString;
|
|
26
|
+
filename: z.ZodString;
|
|
27
|
+
mimeType: z.ZodString;
|
|
28
|
+
size: z.ZodNumber;
|
|
29
|
+
url: z.ZodString;
|
|
30
|
+
uploadedBy: z.ZodString;
|
|
31
|
+
uploadedAt: z.ZodString;
|
|
32
|
+
downloadUrl: z.ZodString;
|
|
33
|
+
}, z.core.$strip>>;
|
|
34
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
export type MediaListResponse = z.infer<typeof MediaListResponseSchema>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { MediaFileSchema } from "./media.schema.js";
|
|
3
|
+
// downloadUrl is generated per response (time-limited presigned GET) —
|
|
4
|
+
// it is never the persisted canonical `url` and must not be stored.
|
|
5
|
+
export const MediaFileResponseSchema = MediaFileSchema.extend({
|
|
6
|
+
downloadUrl: z.string().url(),
|
|
7
|
+
});
|
|
8
|
+
export const MediaDeleteResponseSchema = z.object({
|
|
9
|
+
success: z.literal(true),
|
|
10
|
+
});
|
|
11
|
+
// GET /api/media — newest-first pages; cursor = id of the previous
|
|
12
|
+
// page's last item. `search` filters by filename substring,
|
|
13
|
+
// case-insensitive.
|
|
14
|
+
export const MediaListQuerySchema = z.object({
|
|
15
|
+
cursor: z.string().uuid().optional(),
|
|
16
|
+
limit: z.coerce.number().int().min(1).max(100).default(24),
|
|
17
|
+
search: z.string().min(1).optional(),
|
|
18
|
+
});
|
|
19
|
+
export const MediaListResponseSchema = z.object({
|
|
20
|
+
items: z.array(MediaFileResponseSchema),
|
|
21
|
+
// null = no more pages.
|
|
22
|
+
nextCursor: z.string().uuid().nullable(),
|
|
23
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const MediaFileSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
filename: z.ZodString;
|
|
5
|
+
mimeType: z.ZodString;
|
|
6
|
+
size: z.ZodNumber;
|
|
7
|
+
url: z.ZodString;
|
|
8
|
+
uploadedBy: z.ZodString;
|
|
9
|
+
uploadedAt: z.ZodString;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
export type MediaFile = z.infer<typeof MediaFileSchema>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const MediaFileSchema = z.object({
|
|
3
|
+
id: z.string().uuid(),
|
|
4
|
+
filename: z.string().min(1),
|
|
5
|
+
mimeType: z.string().min(1),
|
|
6
|
+
size: z.number().int().nonnegative(),
|
|
7
|
+
url: z.string().url(),
|
|
8
|
+
uploadedBy: z.string().uuid(),
|
|
9
|
+
uploadedAt: z.string().datetime(),
|
|
10
|
+
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ManagedPluginSchema: z.ZodObject<{
|
|
3
|
+
pluginId: z.ZodString;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
type: z.ZodString;
|
|
6
|
+
version: z.ZodString;
|
|
7
|
+
trustTier: z.ZodEnum<{
|
|
8
|
+
verified: "verified";
|
|
9
|
+
unverified: "unverified";
|
|
10
|
+
}>;
|
|
11
|
+
storageType: z.ZodEnum<{
|
|
12
|
+
simple: "simple";
|
|
13
|
+
structured: "structured";
|
|
14
|
+
}>;
|
|
15
|
+
enabled: z.ZodBoolean;
|
|
16
|
+
licenseStatus: z.ZodNullable<z.ZodString>;
|
|
17
|
+
licenseReason: z.ZodNullable<z.ZodString>;
|
|
18
|
+
licenseLastValidatedAt: z.ZodNullable<z.ZodString>;
|
|
19
|
+
licenseLastAttemptError: z.ZodNullable<z.ZodString>;
|
|
20
|
+
boundDomain: z.ZodNullable<z.ZodString>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export type ManagedPlugin = z.infer<typeof ManagedPluginSchema>;
|
|
23
|
+
export declare const ManagedPluginListQuerySchema: z.ZodObject<{
|
|
24
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
25
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export declare const ManagedPluginListResponseSchema: z.ZodObject<{
|
|
28
|
+
items: z.ZodArray<z.ZodObject<{
|
|
29
|
+
pluginId: z.ZodString;
|
|
30
|
+
name: z.ZodString;
|
|
31
|
+
type: z.ZodString;
|
|
32
|
+
version: z.ZodString;
|
|
33
|
+
trustTier: z.ZodEnum<{
|
|
34
|
+
verified: "verified";
|
|
35
|
+
unverified: "unverified";
|
|
36
|
+
}>;
|
|
37
|
+
storageType: z.ZodEnum<{
|
|
38
|
+
simple: "simple";
|
|
39
|
+
structured: "structured";
|
|
40
|
+
}>;
|
|
41
|
+
enabled: z.ZodBoolean;
|
|
42
|
+
licenseStatus: z.ZodNullable<z.ZodString>;
|
|
43
|
+
licenseReason: z.ZodNullable<z.ZodString>;
|
|
44
|
+
licenseLastValidatedAt: z.ZodNullable<z.ZodString>;
|
|
45
|
+
licenseLastAttemptError: z.ZodNullable<z.ZodString>;
|
|
46
|
+
boundDomain: z.ZodNullable<z.ZodString>;
|
|
47
|
+
}, z.core.$strip>>;
|
|
48
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
export declare const PluginIdParamsSchema: z.ZodObject<{
|
|
51
|
+
pluginId: z.ZodString;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export declare const UninstallPluginBodySchema: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
54
|
+
confirmStructuredDataCleanup: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
}, z.core.$strip>>>;
|
|
56
|
+
export declare const UninstallConfirmationRequiredSchema: z.ZodObject<{
|
|
57
|
+
requiresConfirmation: z.ZodLiteral<true>;
|
|
58
|
+
snapshotGroupId: z.ZodString;
|
|
59
|
+
message: z.ZodString;
|
|
60
|
+
}, z.core.$strip>;
|
|
61
|
+
export declare const BundleUninstallConfirmationRequiredSchema: z.ZodObject<{
|
|
62
|
+
requiresConfirmation: z.ZodLiteral<true>;
|
|
63
|
+
memberSnapshots: z.ZodArray<z.ZodObject<{
|
|
64
|
+
pluginId: z.ZodString;
|
|
65
|
+
snapshotGroupId: z.ZodString;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
message: z.ZodString;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
export declare const UninstallSucceededSchema: z.ZodObject<{
|
|
70
|
+
snapshotGroupId: z.ZodNullable<z.ZodString>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
export type UninstallSucceeded = z.infer<typeof UninstallSucceededSchema>;
|
|
73
|
+
export declare const BundleUninstallSucceededSchema: z.ZodObject<{
|
|
74
|
+
memberSnapshots: z.ZodArray<z.ZodObject<{
|
|
75
|
+
pluginId: z.ZodString;
|
|
76
|
+
snapshotGroupId: z.ZodString;
|
|
77
|
+
}, z.core.$strip>>;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
export type BundleUninstallSucceeded = z.infer<typeof BundleUninstallSucceededSchema>;
|
|
80
|
+
export declare const LicenseRecheckResponseSchema: z.ZodObject<{
|
|
81
|
+
pluginId: z.ZodString;
|
|
82
|
+
checked: z.ZodBoolean;
|
|
83
|
+
status: z.ZodNullable<z.ZodString>;
|
|
84
|
+
reason: z.ZodNullable<z.ZodString>;
|
|
85
|
+
lastValidatedAt: z.ZodNullable<z.ZodString>;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
export type LicenseRecheckResponse = z.infer<typeof LicenseRecheckResponseSchema>;
|
|
88
|
+
export declare const SnapshotGroupSchema: z.ZodObject<{
|
|
89
|
+
snapshotGroupId: z.ZodString;
|
|
90
|
+
takenAt: z.ZodString;
|
|
91
|
+
trigger: z.ZodNullable<z.ZodString>;
|
|
92
|
+
tableNames: z.ZodArray<z.ZodString>;
|
|
93
|
+
totalTableCount: z.ZodNumber;
|
|
94
|
+
status: z.ZodEnum<{
|
|
95
|
+
complete: "complete";
|
|
96
|
+
partial: "partial";
|
|
97
|
+
}>;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
export type SnapshotGroup = z.infer<typeof SnapshotGroupSchema>;
|
|
100
|
+
export declare const SnapshotGroupListQuerySchema: z.ZodObject<{
|
|
101
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
102
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
export declare const SnapshotGroupListResponseSchema: z.ZodObject<{
|
|
105
|
+
pluginId: z.ZodString;
|
|
106
|
+
items: z.ZodArray<z.ZodObject<{
|
|
107
|
+
snapshotGroupId: z.ZodString;
|
|
108
|
+
takenAt: z.ZodString;
|
|
109
|
+
trigger: z.ZodNullable<z.ZodString>;
|
|
110
|
+
tableNames: z.ZodArray<z.ZodString>;
|
|
111
|
+
totalTableCount: z.ZodNumber;
|
|
112
|
+
status: z.ZodEnum<{
|
|
113
|
+
complete: "complete";
|
|
114
|
+
partial: "partial";
|
|
115
|
+
}>;
|
|
116
|
+
}, z.core.$strip>>;
|
|
117
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
118
|
+
}, z.core.$strip>;
|
|
119
|
+
export type SnapshotGroupListResponse = z.infer<typeof SnapshotGroupListResponseSchema>;
|
|
120
|
+
export declare const RestorePlanEntrySchema: z.ZodObject<{
|
|
121
|
+
tableName: z.ZodString;
|
|
122
|
+
snapshotGroupId: z.ZodString;
|
|
123
|
+
groupTakenAt: z.ZodString;
|
|
124
|
+
}, z.core.$strip>;
|
|
125
|
+
export type RestorePlanEntry = z.infer<typeof RestorePlanEntrySchema>;
|
|
126
|
+
export declare const RestoreConfirmationRequiredSchema: z.ZodObject<{
|
|
127
|
+
requiresConfirmation: z.ZodLiteral<true>;
|
|
128
|
+
plan: z.ZodArray<z.ZodObject<{
|
|
129
|
+
tableName: z.ZodString;
|
|
130
|
+
snapshotGroupId: z.ZodString;
|
|
131
|
+
groupTakenAt: z.ZodString;
|
|
132
|
+
}, z.core.$strip>>;
|
|
133
|
+
planHash: z.ZodString;
|
|
134
|
+
message: z.ZodString;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
export type RestoreConfirmationRequired = z.infer<typeof RestoreConfirmationRequiredSchema>;
|
|
137
|
+
export declare const RestoreSucceededSchema: z.ZodObject<{
|
|
138
|
+
preRestoreSnapshotGroupId: z.ZodNullable<z.ZodString>;
|
|
139
|
+
restoredTables: z.ZodArray<z.ZodString>;
|
|
140
|
+
}, z.core.$strip>;
|
|
141
|
+
export type RestoreSucceeded = z.infer<typeof RestoreSucceededSchema>;
|
|
142
|
+
export declare const RestoreBodySchema: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
143
|
+
confirmRestore: z.ZodOptional<z.ZodBoolean>;
|
|
144
|
+
planHash: z.ZodOptional<z.ZodString>;
|
|
145
|
+
}, z.core.$strip>>>;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// The ADMIN management view of the registry (S135): unlike the public
|
|
3
|
+
// GET /api/plugins (enabled-only, boot-loader metadata), this surface
|
|
4
|
+
// lists every installed plugin, disabled included. licenseStatus reflects
|
|
5
|
+
// the PluginLicense row's last verdict ("valid" | "revoked" |
|
|
6
|
+
// "domain_mismatch" | "unknown"), or null when the plugin has no license
|
|
7
|
+
// row at all (free plugins, or a paid plugin never validated yet,
|
|
8
|
+
// S138/S139). The three fields below (S139 Task 5) ride along so the
|
|
9
|
+
// admin's license cell can render an honest state without a second
|
|
10
|
+
// request per row: licenseReason mirrors PluginLicense.lastReason (the
|
|
11
|
+
// server's explanation for a non-valid verdict), licenseLastValidatedAt
|
|
12
|
+
// mirrors lastValidatedAt (the last SUCCESSFUL verdict), and
|
|
13
|
+
// licenseLastAttemptError mirrors lastAttemptError (why the most recent
|
|
14
|
+
// ATTEMPT — successful or not — failed to reach a verdict; null when it
|
|
15
|
+
// didn't). Together the last two let the cell compute "unreachable since"
|
|
16
|
+
// itself. boundDomain mirrors PluginLicense.boundDomain (the domain this
|
|
17
|
+
// site bound the license to at S138 install; never mutated by later
|
|
18
|
+
// revalidation — see revalidate-license.ts) so a domain_mismatch warning
|
|
19
|
+
// can name the actual bound domain instead of the raw upstream reason
|
|
20
|
+
// token (S139 fix wave, spec section 6). Never add `key` here — see the
|
|
21
|
+
// route's comment on the same prisma select.
|
|
22
|
+
export const ManagedPluginSchema = z.object({
|
|
23
|
+
pluginId: z.string(),
|
|
24
|
+
name: z.string(),
|
|
25
|
+
type: z.string(),
|
|
26
|
+
version: z.string(),
|
|
27
|
+
trustTier: z.enum(["verified", "unverified"]),
|
|
28
|
+
storageType: z.enum(["simple", "structured"]),
|
|
29
|
+
enabled: z.boolean(),
|
|
30
|
+
licenseStatus: z.string().nullable(),
|
|
31
|
+
licenseReason: z.string().nullable(),
|
|
32
|
+
licenseLastValidatedAt: z.string().nullable(),
|
|
33
|
+
licenseLastAttemptError: z.string().nullable(),
|
|
34
|
+
boundDomain: z.string().nullable(),
|
|
35
|
+
});
|
|
36
|
+
export const ManagedPluginListQuerySchema = z.object({
|
|
37
|
+
cursor: z.string().uuid().optional(),
|
|
38
|
+
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
39
|
+
});
|
|
40
|
+
export const ManagedPluginListResponseSchema = z.object({
|
|
41
|
+
items: z.array(ManagedPluginSchema),
|
|
42
|
+
nextCursor: z.string().uuid().nullable(),
|
|
43
|
+
});
|
|
44
|
+
export const PluginIdParamsSchema = z.object({
|
|
45
|
+
pluginId: z.string().min(1),
|
|
46
|
+
});
|
|
47
|
+
// Fastify substitutes `null` for a genuinely absent body before handing it
|
|
48
|
+
// to the validator (lib/validation.js's validateParam: `isUndefined ? null
|
|
49
|
+
// : request[paramName]`) — a DELETE sent with no payload at all lands here
|
|
50
|
+
// as `null`, not `undefined`. `.nullish()` (not `.optional()`) is required
|
|
51
|
+
// so an absent body validates; `request.body?.confirmStructuredDataCleanup`
|
|
52
|
+
// in the route handler already tolerates both null and undefined.
|
|
53
|
+
export const UninstallPluginBodySchema = z
|
|
54
|
+
.object({
|
|
55
|
+
confirmStructuredDataCleanup: z.boolean().optional(),
|
|
56
|
+
})
|
|
57
|
+
.nullish();
|
|
58
|
+
// 409 payload when a structured plugin's uninstall needs confirmation —
|
|
59
|
+
// the snapshot has ALREADY been taken (S87's safe-to-retry design).
|
|
60
|
+
export const UninstallConfirmationRequiredSchema = z.object({
|
|
61
|
+
requiresConfirmation: z.literal(true),
|
|
62
|
+
snapshotGroupId: z.string(),
|
|
63
|
+
message: z.string(),
|
|
64
|
+
});
|
|
65
|
+
// S152: the BUNDLE uninstall's aggregated 409 — one snapshot group per
|
|
66
|
+
// structured plugin in the removal set (owned members, and the bundle
|
|
67
|
+
// itself if structured). A separate schema rather than widening
|
|
68
|
+
// UninstallConfirmationRequiredSchema: the single-plugin contract
|
|
69
|
+
// (snapshotGroupId, required) stays byte-identical for existing clients.
|
|
70
|
+
// Every snapshot is ALREADY taken when this is sent (S87's safe-to-retry
|
|
71
|
+
// property, kept cross-plugin).
|
|
72
|
+
export const BundleUninstallConfirmationRequiredSchema = z.object({
|
|
73
|
+
requiresConfirmation: z.literal(true),
|
|
74
|
+
memberSnapshots: z.array(z.object({
|
|
75
|
+
pluginId: z.string(),
|
|
76
|
+
snapshotGroupId: z.string(),
|
|
77
|
+
})),
|
|
78
|
+
message: z.string(),
|
|
79
|
+
});
|
|
80
|
+
// Task 6: the 200 success body for a single-plugin DELETE — the CONFIRMED
|
|
81
|
+
// pass's freshly-minted snapshotGroupId (the gate site already took it;
|
|
82
|
+
// this just stops discarding it), null for a simple-storage plugin (never
|
|
83
|
+
// snapshotted) or for the earlier PluginRegistry.uninstall() callers that
|
|
84
|
+
// route around the HTTP layer entirely.
|
|
85
|
+
export const UninstallSucceededSchema = z.object({
|
|
86
|
+
snapshotGroupId: z.string().nullable(),
|
|
87
|
+
});
|
|
88
|
+
// Task 6: the 200 success body for a BUNDLE DELETE — one entry per
|
|
89
|
+
// structured plugin in the cascade (owned members, and the bundle itself
|
|
90
|
+
// if structured) that got a fresh snapshot on this confirmed pass. Simple-
|
|
91
|
+
// storage members never appear here, same as the 409 aggregate above.
|
|
92
|
+
export const BundleUninstallSucceededSchema = z.object({
|
|
93
|
+
memberSnapshots: z.array(z.object({
|
|
94
|
+
pluginId: z.string(),
|
|
95
|
+
snapshotGroupId: z.string(),
|
|
96
|
+
})),
|
|
97
|
+
});
|
|
98
|
+
// The manual re-check route's response (S139): mirrors revalidateLicense's
|
|
99
|
+
// RevalidationOutcome, flattened for the wire. `checked: false` covers
|
|
100
|
+
// every fail-open case that still has a license row to report on
|
|
101
|
+
// (unreachable license server, no VELORA_SITE_DOMAIN, no marketplace
|
|
102
|
+
// configured) — `status` and `lastValidatedAt` stay null in that shape
|
|
103
|
+
// since nothing was verified. A plugin with no license row at all gets a
|
|
104
|
+
// 404 instead of this body (ApiErrorSchema) — there's nothing to recheck.
|
|
105
|
+
export const LicenseRecheckResponseSchema = z.object({
|
|
106
|
+
pluginId: z.string(),
|
|
107
|
+
checked: z.boolean(),
|
|
108
|
+
status: z.string().nullable(),
|
|
109
|
+
reason: z.string().nullable(),
|
|
110
|
+
lastValidatedAt: z.string().nullable(),
|
|
111
|
+
});
|
|
112
|
+
// S154 Task 4: a plugin's structured-data snapshot GROUPS, derived from
|
|
113
|
+
// PluginStructuredSnapshot (GROUP BY snapshotGroupId) rather than tracked
|
|
114
|
+
// by their own table — see apps/server/src/plugins/snapshot-groups.ts for
|
|
115
|
+
// the derivation. takenAt is the group's earliest row's createdAt (every
|
|
116
|
+
// row in a group is written in one snapshotPluginTables() call, so in
|
|
117
|
+
// practice they're all within the same transaction-ish burst — min is a
|
|
118
|
+
// defensive, not load-bearing, choice). trigger rides along from Task 3's
|
|
119
|
+
// column ("uninstall", "restore", or null for pre-Task-3 rows). status
|
|
120
|
+
// compares the group's own tableNames against totalTableCount — the
|
|
121
|
+
// UNION of distinct tableNames across ALL of the plugin's snapshot rows,
|
|
122
|
+
// the only denominator that survives an uninstall (which deletes the
|
|
123
|
+
// PluginStructuredTable tracking rows, never the snapshots themselves).
|
|
124
|
+
export const SnapshotGroupSchema = z.object({
|
|
125
|
+
snapshotGroupId: z.string(),
|
|
126
|
+
takenAt: z.string(),
|
|
127
|
+
trigger: z.string().nullable(),
|
|
128
|
+
tableNames: z.array(z.string()),
|
|
129
|
+
totalTableCount: z.number().int(),
|
|
130
|
+
status: z.enum(["complete", "partial"]),
|
|
131
|
+
});
|
|
132
|
+
export const SnapshotGroupListQuerySchema = z.object({
|
|
133
|
+
cursor: z.string().uuid().optional(),
|
|
134
|
+
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
135
|
+
});
|
|
136
|
+
export const SnapshotGroupListResponseSchema = z.object({
|
|
137
|
+
pluginId: z.string(),
|
|
138
|
+
items: z.array(SnapshotGroupSchema), // newest first
|
|
139
|
+
nextCursor: z.string().nullable(),
|
|
140
|
+
});
|
|
141
|
+
// S154 Task 5: the UNION restore plan — the newest available snapshot copy
|
|
142
|
+
// of each DISTINCT table this plugin has ever snapshotted, chosen
|
|
143
|
+
// independently per table across every group (not "pick one group and use
|
|
144
|
+
// only its tables"). This is what makes restore recover from the S87
|
|
145
|
+
// retry wedge: no single group need be complete for a full restore to be
|
|
146
|
+
// possible, as long as every table appears in SOME group.
|
|
147
|
+
export const RestorePlanEntrySchema = z.object({
|
|
148
|
+
tableName: z.string(),
|
|
149
|
+
snapshotGroupId: z.string(),
|
|
150
|
+
groupTakenAt: z.string(),
|
|
151
|
+
});
|
|
152
|
+
// 409 payload for an unconfirmed restore — nothing has been touched yet,
|
|
153
|
+
// the plan is offered for the admin to review before confirming. planHash
|
|
154
|
+
// (S161, S154 rider) is a stable digest of this exact plan: the confirm
|
|
155
|
+
// request must echo it back, and the handler refuses to proceed if a fresh
|
|
156
|
+
// re-plan hashes differently (a snapshot landed between the operator
|
|
157
|
+
// seeing this plan and confirming it) — closing the requestRestorePlan ->
|
|
158
|
+
// confirmRestore TOCTOU. A mismatch response reuses this same schema, with
|
|
159
|
+
// a fresh plan/planHash and a message explaining the plan changed.
|
|
160
|
+
export const RestoreConfirmationRequiredSchema = z.object({
|
|
161
|
+
requiresConfirmation: z.literal(true),
|
|
162
|
+
plan: z.array(RestorePlanEntrySchema),
|
|
163
|
+
planHash: z.string(),
|
|
164
|
+
message: z.string(),
|
|
165
|
+
});
|
|
166
|
+
export const RestoreSucceededSchema = z.object({
|
|
167
|
+
// The pre-restore safety snapshot's group id — null only when the
|
|
168
|
+
// plugin had no live tracked tables to protect (restoring onto empty).
|
|
169
|
+
preRestoreSnapshotGroupId: z.string().nullable(),
|
|
170
|
+
restoredTables: z.array(z.string()),
|
|
171
|
+
});
|
|
172
|
+
// Same DELETE-body-null convention as UninstallPluginBodySchema above: an
|
|
173
|
+
// absent POST body lands as `null` (not `undefined`) once Fastify's
|
|
174
|
+
// validator substitutes for a genuinely missing payload, so `.nullish()`
|
|
175
|
+
// (not `.optional()`) is required for an absent body to validate at all.
|
|
176
|
+
// planHash (S161, S154 rider) is optional at the schema level only
|
|
177
|
+
// because the SAME body shape covers the unconfirmed call (`{}`, no plan
|
|
178
|
+
// to hash yet) — the route handler enforces it as effectively required
|
|
179
|
+
// whenever confirmRestore is true: a confirm with a missing or stale
|
|
180
|
+
// planHash is refused exactly the same way (409, fresh plan reissued).
|
|
181
|
+
export const RestoreBodySchema = z
|
|
182
|
+
.object({
|
|
183
|
+
confirmRestore: z.boolean().optional(),
|
|
184
|
+
planHash: z.string().optional(),
|
|
185
|
+
})
|
|
186
|
+
.nullish();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const PluginSchema: z.ZodObject<{
|
|
3
|
+
pluginId: z.ZodString;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
type: z.ZodString;
|
|
6
|
+
version: z.ZodString;
|
|
7
|
+
trustTier: z.ZodString;
|
|
8
|
+
storageType: z.ZodString;
|
|
9
|
+
enabled: z.ZodBoolean;
|
|
10
|
+
remoteUrl: z.ZodNullable<z.ZodString>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
export type Plugin = z.infer<typeof PluginSchema>;
|
|
13
|
+
export declare const PluginListQuerySchema: z.ZodObject<{
|
|
14
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
15
|
+
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type PluginListQuery = z.infer<typeof PluginListQuerySchema>;
|
|
18
|
+
export declare const PluginListResponseSchema: z.ZodObject<{
|
|
19
|
+
items: z.ZodArray<z.ZodObject<{
|
|
20
|
+
pluginId: z.ZodString;
|
|
21
|
+
name: z.ZodString;
|
|
22
|
+
type: z.ZodString;
|
|
23
|
+
version: z.ZodString;
|
|
24
|
+
trustTier: z.ZodString;
|
|
25
|
+
storageType: z.ZodString;
|
|
26
|
+
enabled: z.ZodBoolean;
|
|
27
|
+
remoteUrl: z.ZodNullable<z.ZodString>;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
export type PluginListResponse = z.infer<typeof PluginListResponseSchema>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Read-side shape of a plugin_registry row — the ONLY consumer today is
|
|
3
|
+
// the admin's boot-time remote loader (velora-dev, Session 79), but this
|
|
4
|
+
// is real, permanent infrastructure: any dynamically-installed plugin
|
|
5
|
+
// needs a way for the admin to discover it at boot, sandbox or not.
|
|
6
|
+
export const PluginSchema = z.object({
|
|
7
|
+
pluginId: z.string(),
|
|
8
|
+
name: z.string(),
|
|
9
|
+
type: z.string(),
|
|
10
|
+
version: z.string(),
|
|
11
|
+
trustTier: z.string(),
|
|
12
|
+
storageType: z.string(),
|
|
13
|
+
enabled: z.boolean(),
|
|
14
|
+
remoteUrl: z.string().nullable(),
|
|
15
|
+
});
|
|
16
|
+
// Cursor-paginated per the non-negotiable list-endpoint rule, mirroring
|
|
17
|
+
// DataTypeListResponseSchema's exact shape (data-type-api.schema.ts).
|
|
18
|
+
export const PluginListQuerySchema = z.object({
|
|
19
|
+
cursor: z.string().uuid().optional(),
|
|
20
|
+
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
21
|
+
});
|
|
22
|
+
export const PluginListResponseSchema = z.object({
|
|
23
|
+
items: z.array(PluginSchema),
|
|
24
|
+
nextCursor: z.string().uuid().nullable(),
|
|
25
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const PluginStorageParamsSchema: z.ZodObject<{
|
|
3
|
+
pluginId: z.ZodString;
|
|
4
|
+
contentId: z.ZodString;
|
|
5
|
+
fieldId: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
export type PluginStorageParams = z.infer<typeof PluginStorageParamsSchema>;
|
|
8
|
+
export declare const SetPluginFieldValueRequestSchema: z.ZodObject<{
|
|
9
|
+
value: z.ZodUnknown;
|
|
10
|
+
}, z.core.$strict>;
|
|
11
|
+
export type SetPluginFieldValueRequest = z.infer<typeof SetPluginFieldValueRequestSchema>;
|
|
12
|
+
export declare const PluginFieldValueResponseSchema: z.ZodObject<{
|
|
13
|
+
value: z.ZodUnknown;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
export type PluginFieldValueResponse = z.infer<typeof PluginFieldValueResponseSchema>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// SimpleStorageAPI's HTTP surface (Session 68) — mirrors PROJECT_CONTEXT.md's
|
|
3
|
+
// SimpleStorageAPI interface (get(contentId, fieldId) / set(contentId,
|
|
4
|
+
// fieldId, value)) with pluginId made explicit as a required 3rd param:
|
|
5
|
+
// this is the lower-level adapter/HTTP surface, not the plugin-facing SDK
|
|
6
|
+
// ergonomics (usePluginValue(), Session 70, resolves pluginId from React
|
|
7
|
+
// context and never asks a plugin author to pass it by hand).
|
|
8
|
+
// Matches FieldDefinition.id's shape (document-type.schema.ts) — same
|
|
9
|
+
// stable key, just scoped to one plugin's stored value for that field.
|
|
10
|
+
const FieldIdSchema = z.string().regex(/^[a-zA-Z][a-zA-Z0-9_]*$/);
|
|
11
|
+
// Deliberately NOT plugin-sdk's stricter reverse-DNS pluginIdSchema:
|
|
12
|
+
// plugin-sdk depends on api-schemas, not the reverse, so it can't be
|
|
13
|
+
// imported here without a cycle.
|
|
14
|
+
const PluginIdSchema = z.string().min(1);
|
|
15
|
+
export const PluginStorageParamsSchema = z.object({
|
|
16
|
+
pluginId: PluginIdSchema,
|
|
17
|
+
contentId: z.string().uuid(),
|
|
18
|
+
fieldId: FieldIdSchema,
|
|
19
|
+
});
|
|
20
|
+
// `value` is z.unknown(), not a record — PROJECT_CONTEXT.md types
|
|
21
|
+
// SimpleStorageAPI's value as `any`; a plugin can store a string, number,
|
|
22
|
+
// array, or object, not only key-value maps.
|
|
23
|
+
export const SetPluginFieldValueRequestSchema = z.object({ value: z.unknown() }).strict();
|
|
24
|
+
export const PluginFieldValueResponseSchema = z.object({ value: z.unknown() });
|