@njdamstra/appwrite-utils-cli 1.10.0 → 1.11.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.
@@ -0,0 +1,195 @@
1
+ import { z } from "zod";
2
+ export declare const MigrationTargetType: z.ZodEnum<{
3
+ varchar: "varchar";
4
+ text: "text";
5
+ mediumtext: "mediumtext";
6
+ longtext: "longtext";
7
+ }>;
8
+ export type MigrationTargetType = z.infer<typeof MigrationTargetType>;
9
+ export declare const MigrationAction: z.ZodEnum<{
10
+ skip: "skip";
11
+ migrate: "migrate";
12
+ }>;
13
+ export type MigrationAction = z.infer<typeof MigrationAction>;
14
+ export declare const MigrationPlanEntrySchema: z.ZodObject<{
15
+ databaseId: z.ZodString;
16
+ databaseName: z.ZodString;
17
+ collectionId: z.ZodString;
18
+ collectionName: z.ZodString;
19
+ attributeKey: z.ZodString;
20
+ currentType: z.ZodDefault<z.ZodString>;
21
+ currentSize: z.ZodNumber;
22
+ isRequired: z.ZodDefault<z.ZodBoolean>;
23
+ isArray: z.ZodDefault<z.ZodBoolean>;
24
+ isEncrypted: z.ZodDefault<z.ZodBoolean>;
25
+ hasDefault: z.ZodDefault<z.ZodBoolean>;
26
+ defaultValue: z.ZodOptional<z.ZodAny>;
27
+ suggestedType: z.ZodEnum<{
28
+ varchar: "varchar";
29
+ text: "text";
30
+ mediumtext: "mediumtext";
31
+ longtext: "longtext";
32
+ }>;
33
+ targetType: z.ZodEnum<{
34
+ varchar: "varchar";
35
+ text: "text";
36
+ mediumtext: "mediumtext";
37
+ longtext: "longtext";
38
+ }>;
39
+ targetSize: z.ZodOptional<z.ZodNumber>;
40
+ action: z.ZodEnum<{
41
+ skip: "skip";
42
+ migrate: "migrate";
43
+ }>;
44
+ skipReason: z.ZodOptional<z.ZodString>;
45
+ indexesAffected: z.ZodDefault<z.ZodArray<z.ZodString>>;
46
+ }, z.core.$strip>;
47
+ export type MigrationPlanEntry = z.infer<typeof MigrationPlanEntrySchema>;
48
+ export declare const MigrationPlanSchema: z.ZodObject<{
49
+ version: z.ZodDefault<z.ZodNumber>;
50
+ generatedAt: z.ZodString;
51
+ appwriteEndpoint: z.ZodOptional<z.ZodString>;
52
+ appwriteProject: z.ZodOptional<z.ZodString>;
53
+ summary: z.ZodObject<{
54
+ totalStringAttributes: z.ZodNumber;
55
+ toMigrate: z.ZodNumber;
56
+ toSkip: z.ZodNumber;
57
+ databaseCount: z.ZodNumber;
58
+ collectionCount: z.ZodNumber;
59
+ }, z.core.$strip>;
60
+ entries: z.ZodArray<z.ZodObject<{
61
+ databaseId: z.ZodString;
62
+ databaseName: z.ZodString;
63
+ collectionId: z.ZodString;
64
+ collectionName: z.ZodString;
65
+ attributeKey: z.ZodString;
66
+ currentType: z.ZodDefault<z.ZodString>;
67
+ currentSize: z.ZodNumber;
68
+ isRequired: z.ZodDefault<z.ZodBoolean>;
69
+ isArray: z.ZodDefault<z.ZodBoolean>;
70
+ isEncrypted: z.ZodDefault<z.ZodBoolean>;
71
+ hasDefault: z.ZodDefault<z.ZodBoolean>;
72
+ defaultValue: z.ZodOptional<z.ZodAny>;
73
+ suggestedType: z.ZodEnum<{
74
+ varchar: "varchar";
75
+ text: "text";
76
+ mediumtext: "mediumtext";
77
+ longtext: "longtext";
78
+ }>;
79
+ targetType: z.ZodEnum<{
80
+ varchar: "varchar";
81
+ text: "text";
82
+ mediumtext: "mediumtext";
83
+ longtext: "longtext";
84
+ }>;
85
+ targetSize: z.ZodOptional<z.ZodNumber>;
86
+ action: z.ZodEnum<{
87
+ skip: "skip";
88
+ migrate: "migrate";
89
+ }>;
90
+ skipReason: z.ZodOptional<z.ZodString>;
91
+ indexesAffected: z.ZodDefault<z.ZodArray<z.ZodString>>;
92
+ }, z.core.$strip>>;
93
+ }, z.core.$strip>;
94
+ export type MigrationPlan = z.infer<typeof MigrationPlanSchema>;
95
+ export declare const CheckpointPhase: z.ZodEnum<{
96
+ pending: "pending";
97
+ completed: "completed";
98
+ failed: "failed";
99
+ backup_created: "backup_created";
100
+ data_copied_to_backup: "data_copied_to_backup";
101
+ data_verified_backup: "data_verified_backup";
102
+ original_deleted: "original_deleted";
103
+ new_attr_created: "new_attr_created";
104
+ data_copied_back: "data_copied_back";
105
+ data_verified_final: "data_verified_final";
106
+ backup_deleted: "backup_deleted";
107
+ }>;
108
+ export type CheckpointPhase = z.infer<typeof CheckpointPhase>;
109
+ export declare const CheckpointEntrySchema: z.ZodObject<{
110
+ databaseId: z.ZodString;
111
+ collectionId: z.ZodString;
112
+ attributeKey: z.ZodString;
113
+ backupKey: z.ZodString;
114
+ phase: z.ZodEnum<{
115
+ pending: "pending";
116
+ completed: "completed";
117
+ failed: "failed";
118
+ backup_created: "backup_created";
119
+ data_copied_to_backup: "data_copied_to_backup";
120
+ data_verified_backup: "data_verified_backup";
121
+ original_deleted: "original_deleted";
122
+ new_attr_created: "new_attr_created";
123
+ data_copied_back: "data_copied_back";
124
+ data_verified_final: "data_verified_final";
125
+ backup_deleted: "backup_deleted";
126
+ }>;
127
+ targetType: z.ZodEnum<{
128
+ varchar: "varchar";
129
+ text: "text";
130
+ mediumtext: "mediumtext";
131
+ longtext: "longtext";
132
+ }>;
133
+ targetSize: z.ZodOptional<z.ZodNumber>;
134
+ error: z.ZodOptional<z.ZodString>;
135
+ storedIndexes: z.ZodDefault<z.ZodArray<z.ZodObject<{
136
+ key: z.ZodString;
137
+ type: z.ZodString;
138
+ attributes: z.ZodArray<z.ZodString>;
139
+ orders: z.ZodOptional<z.ZodArray<z.ZodString>>;
140
+ }, z.core.$strip>>>;
141
+ }, z.core.$strip>;
142
+ export type CheckpointEntry = z.infer<typeof CheckpointEntrySchema>;
143
+ export declare const MigrationCheckpointSchema: z.ZodObject<{
144
+ planFile: z.ZodString;
145
+ startedAt: z.ZodString;
146
+ lastUpdatedAt: z.ZodString;
147
+ entries: z.ZodArray<z.ZodObject<{
148
+ databaseId: z.ZodString;
149
+ collectionId: z.ZodString;
150
+ attributeKey: z.ZodString;
151
+ backupKey: z.ZodString;
152
+ phase: z.ZodEnum<{
153
+ pending: "pending";
154
+ completed: "completed";
155
+ failed: "failed";
156
+ backup_created: "backup_created";
157
+ data_copied_to_backup: "data_copied_to_backup";
158
+ data_verified_backup: "data_verified_backup";
159
+ original_deleted: "original_deleted";
160
+ new_attr_created: "new_attr_created";
161
+ data_copied_back: "data_copied_back";
162
+ data_verified_final: "data_verified_final";
163
+ backup_deleted: "backup_deleted";
164
+ }>;
165
+ targetType: z.ZodEnum<{
166
+ varchar: "varchar";
167
+ text: "text";
168
+ mediumtext: "mediumtext";
169
+ longtext: "longtext";
170
+ }>;
171
+ targetSize: z.ZodOptional<z.ZodNumber>;
172
+ error: z.ZodOptional<z.ZodString>;
173
+ storedIndexes: z.ZodDefault<z.ZodArray<z.ZodObject<{
174
+ key: z.ZodString;
175
+ type: z.ZodString;
176
+ attributes: z.ZodArray<z.ZodString>;
177
+ orders: z.ZodOptional<z.ZodArray<z.ZodString>>;
178
+ }, z.core.$strip>>>;
179
+ }, z.core.$strip>>;
180
+ }, z.core.$strip>;
181
+ export type MigrationCheckpoint = z.infer<typeof MigrationCheckpointSchema>;
182
+ export interface AnalyzeOptions {
183
+ outputPath?: string;
184
+ verbose?: boolean;
185
+ }
186
+ export interface ExecuteOptions {
187
+ planPath: string;
188
+ keepBackups?: boolean;
189
+ dryRun?: boolean;
190
+ batchSize?: number;
191
+ batchDelayMs?: number;
192
+ checkpointPath?: string;
193
+ }
194
+ export declare function suggestTargetType(size: number, hasIndex: boolean): MigrationTargetType;
195
+ export declare function generateBackupKey(originalKey: string): string;
@@ -0,0 +1,117 @@
1
+ import { z } from "zod";
2
+ // ── Target types for string attribute migration ──
3
+ export const MigrationTargetType = z.enum([
4
+ "varchar",
5
+ "text",
6
+ "mediumtext",
7
+ "longtext",
8
+ ]);
9
+ export const MigrationAction = z.enum(["migrate", "skip"]);
10
+ // ── Plan entry: one per attribute to migrate ──
11
+ export const MigrationPlanEntrySchema = z.object({
12
+ databaseId: z.string(),
13
+ databaseName: z.string(),
14
+ collectionId: z.string(),
15
+ collectionName: z.string(),
16
+ attributeKey: z.string(),
17
+ currentType: z.string().default("string"),
18
+ currentSize: z.number(),
19
+ isRequired: z.boolean().default(false),
20
+ isArray: z.boolean().default(false),
21
+ isEncrypted: z.boolean().default(false),
22
+ hasDefault: z.boolean().default(false),
23
+ defaultValue: z.any().optional(),
24
+ suggestedType: MigrationTargetType,
25
+ targetType: MigrationTargetType,
26
+ targetSize: z.number().optional(), // varchar only
27
+ action: MigrationAction,
28
+ skipReason: z.string().optional(),
29
+ indexesAffected: z.array(z.string()).default([]),
30
+ });
31
+ // ── Plan: full migration plan (user-editable YAML) ──
32
+ export const MigrationPlanSchema = z.object({
33
+ version: z.number().default(1),
34
+ generatedAt: z.string(),
35
+ appwriteEndpoint: z.string().optional(),
36
+ appwriteProject: z.string().optional(),
37
+ summary: z.object({
38
+ totalStringAttributes: z.number(),
39
+ toMigrate: z.number(),
40
+ toSkip: z.number(),
41
+ databaseCount: z.number(),
42
+ collectionCount: z.number(),
43
+ }),
44
+ entries: z.array(MigrationPlanEntrySchema),
45
+ });
46
+ // ── Checkpoint: tracks progress during execution ──
47
+ export const CheckpointPhase = z.enum([
48
+ "pending",
49
+ "backup_created",
50
+ "data_copied_to_backup",
51
+ "data_verified_backup",
52
+ "original_deleted",
53
+ "new_attr_created",
54
+ "data_copied_back",
55
+ "data_verified_final",
56
+ "backup_deleted",
57
+ "completed",
58
+ "failed",
59
+ ]);
60
+ export const CheckpointEntrySchema = z.object({
61
+ databaseId: z.string(),
62
+ collectionId: z.string(),
63
+ attributeKey: z.string(),
64
+ backupKey: z.string(),
65
+ phase: CheckpointPhase,
66
+ targetType: MigrationTargetType,
67
+ targetSize: z.number().optional(),
68
+ error: z.string().optional(),
69
+ // Store index definitions for recreation after attribute delete
70
+ storedIndexes: z
71
+ .array(z.object({
72
+ key: z.string(),
73
+ type: z.string(),
74
+ attributes: z.array(z.string()),
75
+ orders: z.array(z.string()).optional(),
76
+ }))
77
+ .default([]),
78
+ });
79
+ export const MigrationCheckpointSchema = z.object({
80
+ planFile: z.string(),
81
+ startedAt: z.string(),
82
+ lastUpdatedAt: z.string(),
83
+ entries: z.array(CheckpointEntrySchema),
84
+ });
85
+ // ── Helper: suggest target type from size + index presence ──
86
+ export function suggestTargetType(size, hasIndex) {
87
+ // varchar supports up to 16,383 bytes and allows full indexing
88
+ if (size <= 768)
89
+ return "varchar";
90
+ if (hasIndex)
91
+ return "varchar"; // indexes require varchar
92
+ if (size <= 16_383)
93
+ return "text";
94
+ if (size <= 4_000_000)
95
+ return "mediumtext";
96
+ return "longtext";
97
+ }
98
+ // ── Helper: generate backup key with length limits ──
99
+ const MAX_KEY_LENGTH = 36;
100
+ const BACKUP_PREFIX = "_mig_";
101
+ export function generateBackupKey(originalKey) {
102
+ const candidate = `${BACKUP_PREFIX}${originalKey}`;
103
+ if (candidate.length <= MAX_KEY_LENGTH) {
104
+ return candidate;
105
+ }
106
+ // Truncate + 4-char hash for uniqueness
107
+ const hash = simpleHash(originalKey);
108
+ const maxOrigLen = MAX_KEY_LENGTH - BACKUP_PREFIX.length - 1 - 4; // _mig_ + _ + hash4
109
+ return `_m_${originalKey.slice(0, maxOrigLen)}_${hash}`;
110
+ }
111
+ function simpleHash(str) {
112
+ let h = 0;
113
+ for (let i = 0; i < str.length; i++) {
114
+ h = ((h << 5) - h + str.charCodeAt(i)) | 0;
115
+ }
116
+ return Math.abs(h).toString(36).slice(0, 4).padStart(4, "0");
117
+ }