appwrite-cli 13.1.0-rc.3 → 13.1.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/dist/cli.cjs CHANGED
@@ -93392,7 +93392,7 @@ var package_default = {
93392
93392
  type: "module",
93393
93393
  homepage: "https://appwrite.io/support",
93394
93394
  description: "Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API",
93395
- version: "13.1.0-rc.3",
93395
+ version: "13.1.0",
93396
93396
  license: "BSD-3-Clause",
93397
93397
  main: "dist/index.js",
93398
93398
  types: "dist/index.d.ts",
@@ -93431,7 +93431,6 @@ var package_default = {
93431
93431
  dotenv: "^16.4.5",
93432
93432
  ejs: "^3.1.9",
93433
93433
  handlebars: "^4.7.7",
93434
- "form-data": "^4.0.0",
93435
93434
  ignore: "^7.0.5",
93436
93435
  inquirer: "^8.2.4",
93437
93436
  "inquirer-search-list": "^1.2.6",
@@ -107643,7 +107642,7 @@ var import_undici = __toESM(require_undici(), 1);
107643
107642
  // lib/constants.ts
107644
107643
  var SDK_TITLE = "Appwrite";
107645
107644
  var SDK_TITLE_LOWER = "appwrite";
107646
- var SDK_VERSION = "13.1.0-rc.3";
107645
+ var SDK_VERSION = "13.1.0";
107647
107646
  var SDK_NAME = "Command Line";
107648
107647
  var SDK_PLATFORM = "console";
107649
107648
  var SDK_LANGUAGE = "cli";
@@ -133102,6 +133101,7 @@ var commandDescriptions = {
133102
133101
  push: `The push command provides a convenient wrapper for pushing your functions, collections, buckets, teams, and messaging-topics.`,
133103
133102
  run: `The run command allows you to run the project locally to allow easy development and quick debugging.`,
133104
133103
  functions: `The functions command allows you to view, create, and manage your Cloud Functions.`,
133104
+ generate: `The generate command allows you to generate a type-safe SDK from your ${SDK_TITLE} project configuration.`,
133105
133105
  health: `The health command allows you to both validate and monitor your ${SDK_TITLE} server's health.`,
133106
133106
  pull: `The pull command helps you pull your ${SDK_TITLE} project, functions, collections, buckets, teams, and messaging-topics`,
133107
133107
  locale: `The locale command allows you to customize your app based on your users' location.`,
@@ -136219,23 +136219,19 @@ var initSite = async () => {
136219
136219
  let selected = {
136220
136220
  template: templateDetails.frameworks[0].providerRootDirectory
136221
136221
  };
136222
- let gitCloneCommands = "";
136222
+ let dirSetupCommands = "";
136223
136223
  const sparse = selected.template.startsWith("./") ? selected.template.substring(2) : selected.template;
136224
136224
  log("Fetching site code ...");
136225
136225
  if (selected.template === "./") {
136226
- gitCloneCommands = `
136227
- mkdir -p .
136228
- cd .
136226
+ dirSetupCommands = `
136227
+ cd ${templatesDir}
136229
136228
  git init
136230
136229
  git remote add origin ${repo}
136231
- git config --global init.defaultBranch main
136232
- git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}')
136233
- git checkout FETCH_HEAD
136230
+ git config --global init.defaultBranch main
136234
136231
  `.trim();
136235
136232
  } else {
136236
- gitCloneCommands = `
136237
- mkdir -p .
136238
- cd .
136233
+ dirSetupCommands = `
136234
+ cd ${templatesDir}
136239
136235
  git init
136240
136236
  git remote add origin ${repo}
136241
136237
  git config --global init.defaultBranch main
@@ -136243,17 +136239,29 @@ var initSite = async () => {
136243
136239
  echo "${sparse}" >> .git/info/sparse-checkout
136244
136240
  git config --add remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
136245
136241
  git config remote.origin.tagopt --no-tags
136246
- git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}')
136247
- git checkout FETCH_HEAD
136248
136242
  `.trim();
136249
136243
  }
136244
+ let windowsGitCloneCommands = `
136245
+ $tag = (git ls-remote --tags origin "${templateDetails.providerVersion}" | Select-Object -Last 1) -replace '.*refs/tags/', ''
136246
+ git fetch --depth=1 origin "refs/tags/$tag"
136247
+ git checkout FETCH_HEAD
136248
+ `.trim();
136249
+ let unixGitCloneCommands = `
136250
+ git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}')
136251
+ git checkout FETCH_HEAD
136252
+ `.trim();
136253
+ let usedShell = null;
136250
136254
  if (process.platform === "win32") {
136251
- gitCloneCommands = 'cmd /c "' + gitCloneCommands + '"';
136255
+ dirSetupCommands = dirSetupCommands + "\n" + windowsGitCloneCommands;
136256
+ usedShell = "powershell.exe";
136257
+ } else {
136258
+ dirSetupCommands = dirSetupCommands + "\n" + unixGitCloneCommands;
136252
136259
  }
136253
136260
  try {
136254
- import_child_process2.default.execSync(gitCloneCommands, {
136261
+ import_child_process2.default.execSync(dirSetupCommands, {
136255
136262
  stdio: "pipe",
136256
- cwd: templatesDir
136263
+ cwd: templatesDir,
136264
+ shell: usedShell
136257
136265
  });
136258
136266
  } catch (err) {
136259
136267
  if (err.message.includes("error: unknown option")) {
@@ -136274,28 +136282,11 @@ Suggestion: It appears that git is not installed, try installing git then trying
136274
136282
  throw err;
136275
136283
  }
136276
136284
  }
136277
- import_fs5.default.rmSync(import_path5.default.join(templatesDir, ".git"), { recursive: true });
136278
- const copyRecursiveSync = (src, dest) => {
136279
- let exists = import_fs5.default.existsSync(src);
136280
- let stats = exists && import_fs5.default.statSync(src);
136281
- let isDirectory = exists && stats && stats.isDirectory();
136282
- if (isDirectory) {
136283
- if (!import_fs5.default.existsSync(dest)) {
136284
- import_fs5.default.mkdirSync(dest);
136285
- }
136286
- import_fs5.default.readdirSync(src).forEach(function(childItemName) {
136287
- copyRecursiveSync(
136288
- import_path5.default.join(src, childItemName),
136289
- import_path5.default.join(dest, childItemName)
136290
- );
136291
- });
136292
- } else {
136293
- import_fs5.default.copyFileSync(src, dest);
136294
- }
136295
- };
136296
- copyRecursiveSync(
136285
+ import_fs5.default.rmSync(import_path5.default.join(templatesDir, ".git"), { recursive: true, force: true });
136286
+ import_fs5.default.cpSync(
136297
136287
  selected.template === "./" ? templatesDir : import_path5.default.join(templatesDir, selected.template),
136298
- siteDir
136288
+ siteDir,
136289
+ { recursive: true, force: true }
136299
136290
  );
136300
136291
  import_fs5.default.rmSync(templatesDir, { recursive: true, force: true });
136301
136292
  const readmePath = import_path5.default.join(process.cwd(), "sites", siteName, "README.md");
@@ -136606,7 +136597,7 @@ class <%- toPascalCase(collection.name) %> {
136606
136597
  // lib/shared/typescript-type-utils.ts
136607
136598
  var fs7 = __toESM(require("fs"), 1);
136608
136599
  var path6 = __toESM(require("path"), 1);
136609
- function getTypeScriptType(attribute, entities, entityName) {
136600
+ function getTypeScriptType(attribute, entities, entityName, forCreate = false) {
136610
136601
  let type = "";
136611
136602
  switch (attribute.type) {
136612
136603
  case "string":
@@ -136631,7 +136622,8 @@ function getTypeScriptType(attribute, entities, entityName) {
136631
136622
  if (!relatedEntity) {
136632
136623
  throw new Error(`Related entity with ID '${relatedId}' not found.`);
136633
136624
  }
136634
- type = LanguageMeta.toPascalCase(relatedEntity.name);
136625
+ const baseName = LanguageMeta.toPascalCase(relatedEntity.name);
136626
+ type = forCreate ? `((${baseName}Create & { $id?: string; $permissions?: string[] }) | string)` : baseName;
136635
136627
  if (attribute.relationType === "oneToMany" && attribute.side === "parent" || attribute.relationType === "manyToOne" && attribute.side === "child" || attribute.relationType === "manyToMany") {
136636
136628
  type = `${type}[]`;
136637
136629
  }
@@ -142161,6 +142153,9 @@ var BaseDatabasesGenerator = class {
142161
142153
  if (!fs15.existsSync(fileDir)) {
142162
142154
  fs15.mkdirSync(fileDir, { recursive: true });
142163
142155
  }
142156
+ if (relativePath === "constants.ts" && fs15.existsSync(filePath)) {
142157
+ continue;
142158
+ }
142164
142159
  fs15.writeFileSync(filePath, content, "utf-8");
142165
142160
  }
142166
142161
  }
@@ -142172,10 +142167,10 @@ var BaseDatabasesGenerator = class {
142172
142167
  };
142173
142168
 
142174
142169
  // lib/commands/generators/typescript/templates/types.ts.hbs
142175
- var types_ts_default = "import { type Models, Permission } from '{{appwriteDep}}';\n\n{{{ENUMS}}}{{{TYPES}}}\nexport type QueryValue = string | number | boolean;\n\nexport type ExtractQueryValue<T> = T extends (infer U)[]\n ? U extends QueryValue ? U : never\n : T extends QueryValue | null ? NonNullable<T> : never;\n\nexport type QueryableKeys<T> = {\n [K in keyof T]: ExtractQueryValue<T[K]> extends never ? never : K;\n}[keyof T];\n\nexport type QueryBuilder<T> = {\n equal: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n notEqual: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n lessThan: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n lessThanEqual: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n greaterThan: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n greaterThanEqual: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n contains: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n search: <K extends QueryableKeys<T>>(field: K, value: string) => string;\n isNull: <K extends QueryableKeys<T>>(field: K) => string;\n isNotNull: <K extends QueryableKeys<T>>(field: K) => string;\n startsWith: <K extends QueryableKeys<T>>(field: K, value: string) => string;\n endsWith: <K extends QueryableKeys<T>>(field: K, value: string) => string;\n between: <K extends QueryableKeys<T>>(field: K, start: ExtractQueryValue<T[K]>, end: ExtractQueryValue<T[K]>) => string;\n select: <K extends keyof T>(fields: K[]) => string;\n orderAsc: <K extends keyof T>(field: K) => string;\n orderDesc: <K extends keyof T>(field: K) => string;\n limit: (value: number) => string;\n offset: (value: number) => string;\n cursorAfter: (documentId: string) => string;\n cursorBefore: (documentId: string) => string;\n or: (...queries: string[]) => string;\n and: (...queries: string[]) => string;\n}\n\nexport type DatabaseId = {{{databaseIdType}}};\n\n{{{DATABASE_TABLES_TYPE}}}\n";
142170
+ var types_ts_default = "import { type Models } from '{{appwriteDep}}';\n\n{{{ENUMS}}}{{{TYPES}}}\ndeclare const __roleStringBrand: unique symbol;\nexport type RoleString = string & { readonly [__roleStringBrand]: never };\n\nexport type RoleBuilder = {\n any: () => RoleString;\n user: (userId: string, status?: string) => RoleString;\n users: (status?: string) => RoleString;\n guests: () => RoleString;\n team: (teamId: string, role?: string) => RoleString;\n member: (memberId: string) => RoleString;\n label: (label: string) => RoleString;\n}\n\nexport type PermissionBuilder = {\n read: (role: RoleString) => string;\n write: (role: RoleString) => string;\n create: (role: RoleString) => string;\n update: (role: RoleString) => string;\n delete: (role: RoleString) => string;\n}\n\nexport type PermissionCallback = (permission: PermissionBuilder, role: RoleBuilder) => string[];\n\nexport type QueryValue = string | number | boolean;\n\nexport type ExtractQueryValue<T> = T extends (infer U)[]\n ? U extends QueryValue ? U : never\n : T extends QueryValue | null ? NonNullable<T> : never;\n\nexport type QueryableKeys<T> = {\n [K in keyof T]: ExtractQueryValue<T[K]> extends never ? never : K;\n}[keyof T];\n\nexport type QueryBuilder<T> = {\n equal: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n notEqual: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n lessThan: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n lessThanEqual: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n greaterThan: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n greaterThanEqual: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n contains: <K extends QueryableKeys<T>>(field: K, value: ExtractQueryValue<T[K]>) => string;\n search: <K extends QueryableKeys<T>>(field: K, value: string) => string;\n isNull: <K extends QueryableKeys<T>>(field: K) => string;\n isNotNull: <K extends QueryableKeys<T>>(field: K) => string;\n startsWith: <K extends QueryableKeys<T>>(field: K, value: string) => string;\n endsWith: <K extends QueryableKeys<T>>(field: K, value: string) => string;\n between: <K extends QueryableKeys<T>>(field: K, start: ExtractQueryValue<T[K]>, end: ExtractQueryValue<T[K]>) => string;\n select: <K extends keyof T>(fields: K[]) => string;\n orderAsc: <K extends keyof T>(field: K) => string;\n orderDesc: <K extends keyof T>(field: K) => string;\n limit: (value: number) => string;\n offset: (value: number) => string;\n cursorAfter: (documentId: string) => string;\n cursorBefore: (documentId: string) => string;\n or: (...queries: string[]) => string;\n and: (...queries: string[]) => string;\n}\n\nexport type DatabaseId = {{{databaseIdType}}};\n\n{{{DATABASE_TABLES_TYPE}}}\n";
142176
142171
 
142177
142172
  // lib/commands/generators/typescript/templates/databases.ts.hbs
142178
- var databases_ts_default = 'import { Client, TablesDB, ID, Query, type Models, Permission } from \'{{appwriteDep}}\';\nimport type { DatabaseHandle, DatabaseId, DatabaseTableMap, DatabaseTables, QueryBuilder } from \'./types.js\';\n{{#if supportsServerSide}}\nimport { PROJECT_ID, ENDPOINT, API_KEY } from \'./constants.js\';\n{{else}}\nimport { PROJECT_ID, ENDPOINT } from \'./constants.js\';\n{{/if}}\n\nconst createQueryBuilder = <T>(): QueryBuilder<T> => ({\n equal: (field, value) => Query.equal(String(field), value as any),\n notEqual: (field, value) => Query.notEqual(String(field), value as any),\n lessThan: (field, value) => Query.lessThan(String(field), value as any),\n lessThanEqual: (field, value) => Query.lessThanEqual(String(field), value as any),\n greaterThan: (field, value) => Query.greaterThan(String(field), value as any),\n greaterThanEqual: (field, value) => Query.greaterThanEqual(String(field), value as any),\n contains: (field, value) => Query.contains(String(field), value as any),\n search: (field, value) => Query.search(String(field), value),\n isNull: (field) => Query.isNull(String(field)),\n isNotNull: (field) => Query.isNotNull(String(field)),\n startsWith: (field, value) => Query.startsWith(String(field), value),\n endsWith: (field, value) => Query.endsWith(String(field), value),\n between: (field, start, end) => Query.between(String(field), start as any, end as any),\n select: (fields) => Query.select(fields.map(String)),\n orderAsc: (field) => Query.orderAsc(String(field)),\n orderDesc: (field) => Query.orderDesc(String(field)),\n limit: (value) => Query.limit(value),\n offset: (value) => Query.offset(value),\n cursorAfter: (documentId) => Query.cursorAfter(documentId),\n cursorBefore: (documentId) => Query.cursorBefore(documentId),\n or: (...queries) => Query.or(queries),\n and: (...queries) => Query.and(queries),\n});\n\n{{{TABLE_ID_MAP}}}\n\n{{{TABLES_WITH_RELATIONSHIPS}}}\n\nconst serializePermissions = (permissions?: Permission[]): string[] | undefined =>\n permissions?.map((permission) => permission.toString());\n\nfunction createTableApi<T extends Models.Row>(\n tablesDB: TablesDB,\n databaseId: string,\n tableId: string,\n) {\n return {\n create: (data: any, options?: { rowId?: string; permissions?: Permission[]; transactionId?: string }) =>\n tablesDB.createRow<T>({\n databaseId,\n tableId,\n rowId: options?.rowId ?? ID.unique(),\n data,\n permissions: serializePermissions(options?.permissions),\n transactionId: options?.transactionId,\n }),\n get: (id: string) =>\n tablesDB.getRow<T>({\n databaseId,\n tableId,\n rowId: id,\n }),\n update: (id: string, data: any, options?: { permissions?: Permission[]; transactionId?: string }) =>\n tablesDB.updateRow<T>({\n databaseId,\n tableId,\n rowId: id,\n data,\n ...(options?.permissions ? { permissions: serializePermissions(options.permissions) } : {}),\n transactionId: options?.transactionId,\n }),\n delete: async (id: string, options?: { transactionId?: string }) => {\n await tablesDB.deleteRow({\n databaseId,\n tableId,\n rowId: id,\n transactionId: options?.transactionId,\n });\n },\n list: (options?: { queries?: (q: any) => string[] }) =>\n tablesDB.listRows<T>({\n databaseId,\n tableId,\n queries: options?.queries?.(createQueryBuilder<T>()),\n }),{{{BULK_METHODS}}}\n };\n}\n\n{{{BULK_CHECK}}}\nconst hasOwn = (obj: unknown, key: string): boolean =>\n obj != null && Object.prototype.hasOwnProperty.call(obj, key);\n\nfunction createDatabaseHandle<D extends DatabaseId>(\n tablesDB: TablesDB,\n databaseId: D,\n): DatabaseHandle<D> {\n const tableApiCache = new Map<string, unknown>();\n const dbMap = tableIdMap[databaseId];\n\n return {\n use: <T extends keyof DatabaseTableMap[D] & string>(tableName: T): DatabaseTableMap[D][T] => {\n if (!hasOwn(dbMap, tableName)) {\n throw new Error(`Unknown table "${tableName}" in database "${databaseId}"`);\n }\n\n if (!tableApiCache.has(tableName)) {\n const tableId = dbMap[tableName];\n const api = createTableApi(tablesDB, databaseId, tableId);\n {{{BULK_REMOVAL}}}\n tableApiCache.set(tableName, api);\n }\n return tableApiCache.get(tableName) as DatabaseTableMap[D][T];\n },\n{{#if supportsServerSide}}\n create: (tableId: string, name: string, options?: { permissions?: Permission[]; rowSecurity?: boolean; enabled?: boolean; columns?: any[]; indexes?: any[] }) =>\n tablesDB.createTable({\n databaseId,\n tableId,\n name,\n permissions: serializePermissions(options?.permissions),\n rowSecurity: options?.rowSecurity,\n enabled: options?.enabled,\n columns: options?.columns,\n indexes: options?.indexes,\n }),\n update: (tableName: string, name: string, options?: { permissions?: Permission[]; rowSecurity?: boolean; enabled?: boolean }) => {\n if (!hasOwn(dbMap, tableName)) {\n throw new Error(`Unknown table "${tableName}" in database "${databaseId}"`);\n }\n const tableId = dbMap[tableName];\n return tablesDB.updateTable({\n databaseId,\n tableId,\n name,\n permissions: serializePermissions(options?.permissions),\n rowSecurity: options?.rowSecurity,\n enabled: options?.enabled,\n });\n },\n delete: async (tableName: string) => {\n if (!hasOwn(dbMap, tableName)) {\n throw new Error(`Unknown table "${tableName}" in database "${databaseId}"`);\n }\n const tableId = dbMap[tableName];\n await tablesDB.deleteTable({\n databaseId,\n tableId,\n });\n },\n{{/if}}\n };\n}\n\nfunction createDatabasesApi(tablesDB: TablesDB): DatabaseTables {\n const dbCache = new Map<DatabaseId, ReturnType<typeof createDatabaseHandle>>();\n\n return {\n use: (databaseId: DatabaseId) => {\n if (!hasOwn(tableIdMap, databaseId)) {\n throw new Error(`Unknown database "${databaseId}"`);\n }\n\n if (!dbCache.has(databaseId)) {\n dbCache.set(databaseId, createDatabaseHandle(tablesDB, databaseId));\n }\n return dbCache.get(databaseId);\n },\n{{#if supportsServerSide}}\n create: (databaseId: string, name: string, options?: { enabled?: boolean }) =>\n tablesDB.create({\n databaseId,\n name,\n enabled: options?.enabled,\n }),\n update: (databaseId: DatabaseId, name: string, options?: { enabled?: boolean }) =>\n tablesDB.update({\n databaseId,\n name,\n enabled: options?.enabled,\n }),\n delete: async (databaseId: DatabaseId) => {\n await tablesDB.delete({\n databaseId,\n });\n },\n{{/if}}\n } as DatabaseTables;\n}\n\n// Initialize client\nconst client = new Client()\n .setEndpoint(ENDPOINT)\n .setProject(PROJECT_ID){{#if supportsServerSide}}\n .setKey(API_KEY){{/if}};\n\nconst tablesDB = new TablesDB(client);\n\nexport const databases: DatabaseTables = createDatabasesApi(tablesDB);\n';
142173
+ var databases_ts_default = 'import { Client, TablesDB, ID, Query, type Models, Permission, Role } from \'{{appwriteDep}}\';\nimport type { DatabaseHandle, DatabaseId, DatabaseTableMap, DatabaseTables, QueryBuilder, PermissionBuilder, RoleBuilder, RoleString } from \'./types.js\';\n{{#if supportsServerSide}}\nimport { PROJECT_ID, ENDPOINT, API_KEY } from \'./constants.js\';\n{{else}}\nimport { PROJECT_ID, ENDPOINT } from \'./constants.js\';\n{{/if}}\n\nconst createQueryBuilder = <T>(): QueryBuilder<T> => ({\n equal: (field, value) => Query.equal(String(field), value as any),\n notEqual: (field, value) => Query.notEqual(String(field), value as any),\n lessThan: (field, value) => Query.lessThan(String(field), value as any),\n lessThanEqual: (field, value) => Query.lessThanEqual(String(field), value as any),\n greaterThan: (field, value) => Query.greaterThan(String(field), value as any),\n greaterThanEqual: (field, value) => Query.greaterThanEqual(String(field), value as any),\n contains: (field, value) => Query.contains(String(field), value as any),\n search: (field, value) => Query.search(String(field), value),\n isNull: (field) => Query.isNull(String(field)),\n isNotNull: (field) => Query.isNotNull(String(field)),\n startsWith: (field, value) => Query.startsWith(String(field), value),\n endsWith: (field, value) => Query.endsWith(String(field), value),\n between: (field, start, end) => Query.between(String(field), start as any, end as any),\n select: (fields) => Query.select(fields.map(String)),\n orderAsc: (field) => Query.orderAsc(String(field)),\n orderDesc: (field) => Query.orderDesc(String(field)),\n limit: (value) => Query.limit(value),\n offset: (value) => Query.offset(value),\n cursorAfter: (documentId) => Query.cursorAfter(documentId),\n cursorBefore: (documentId) => Query.cursorBefore(documentId),\n or: (...queries) => Query.or(queries),\n and: (...queries) => Query.and(queries),\n});\n\n{{{TABLE_ID_MAP}}}\n\n{{{TABLES_WITH_RELATIONSHIPS}}}\n\nconst roleBuilder: RoleBuilder = {\n any: () => Role.any() as RoleString,\n user: (userId, status?) => Role.user(userId, status) as RoleString,\n users: (status?) => Role.users(status) as RoleString,\n guests: () => Role.guests() as RoleString,\n team: (teamId, role?) => Role.team(teamId, role) as RoleString,\n member: (memberId) => Role.member(memberId) as RoleString,\n label: (label) => Role.label(label) as RoleString,\n};\n\nconst permissionBuilder: PermissionBuilder = {\n read: (role) => Permission.read(role),\n write: (role) => Permission.write(role),\n create: (role) => Permission.create(role),\n update: (role) => Permission.update(role),\n delete: (role) => Permission.delete(role),\n};\n\nconst resolvePermissions = (callback?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]): string[] | undefined =>\n callback?.(permissionBuilder, roleBuilder);\n\nfunction createTableApi<T extends Models.Row>(\n tablesDB: TablesDB,\n databaseId: string,\n tableId: string,\n) {\n return {\n create: (data: any, options?: { rowId?: string; permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; transactionId?: string }) =>\n tablesDB.createRow<T>({\n databaseId,\n tableId,\n rowId: options?.rowId ?? ID.unique(),\n data,\n permissions: resolvePermissions(options?.permissions),\n transactionId: options?.transactionId,\n }),\n get: (id: string) =>\n tablesDB.getRow<T>({\n databaseId,\n tableId,\n rowId: id,\n }),\n update: (id: string, data: any, options?: { permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; transactionId?: string }) =>\n tablesDB.updateRow<T>({\n databaseId,\n tableId,\n rowId: id,\n data,\n ...(options?.permissions ? { permissions: resolvePermissions(options.permissions) } : {}),\n transactionId: options?.transactionId,\n }),\n delete: async (id: string, options?: { transactionId?: string }) => {\n await tablesDB.deleteRow({\n databaseId,\n tableId,\n rowId: id,\n transactionId: options?.transactionId,\n });\n },\n list: (options?: { queries?: (q: any) => string[] }) =>\n tablesDB.listRows<T>({\n databaseId,\n tableId,\n queries: options?.queries?.(createQueryBuilder<T>()),\n }),{{{BULK_METHODS}}}\n };\n}\n\n{{{BULK_CHECK}}}\nconst hasOwn = (obj: unknown, key: string): boolean =>\n obj != null && Object.prototype.hasOwnProperty.call(obj, key);\n\nfunction createDatabaseHandle<D extends DatabaseId>(\n tablesDB: TablesDB,\n databaseId: D,\n): DatabaseHandle<D> {\n const tableApiCache = new Map<string, unknown>();\n const dbMap = tableIdMap[databaseId];\n\n return {\n use: <T extends keyof DatabaseTableMap[D] & string>(tableId: T): DatabaseTableMap[D][T] => {\n if (!hasOwn(dbMap, tableId)) {\n throw new Error(`Unknown table "${tableId}" in database "${databaseId}"`);\n }\n\n if (!tableApiCache.has(tableId)) {\n const resolvedTableId = dbMap[tableId];\n const api = createTableApi(tablesDB, databaseId, resolvedTableId);\n {{{BULK_REMOVAL}}}\n tableApiCache.set(tableId, api);\n }\n return tableApiCache.get(tableId) as DatabaseTableMap[D][T];\n },\n{{#if supportsServerSide}}\n create: (tableId: string, name: string, options?: { permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; rowSecurity?: boolean; enabled?: boolean; columns?: any[]; indexes?: any[] }) =>\n tablesDB.createTable({\n databaseId,\n tableId,\n name,\n permissions: resolvePermissions(options?.permissions),\n rowSecurity: options?.rowSecurity,\n enabled: options?.enabled,\n columns: options?.columns,\n indexes: options?.indexes,\n }),\n update: (tableId: string, options?: { name?: string; permissions?: (permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]; rowSecurity?: boolean; enabled?: boolean }) => {\n if (!hasOwn(dbMap, tableId)) {\n throw new Error(`Unknown table "${tableId}" in database "${databaseId}"`);\n }\n const resolvedTableId = dbMap[tableId];\n return tablesDB.updateTable({\n databaseId,\n tableId: resolvedTableId,\n name: options?.name ?? tableId, // TODO: remove this fallback once fixed in other SDKs\n permissions: resolvePermissions(options?.permissions),\n rowSecurity: options?.rowSecurity,\n enabled: options?.enabled,\n });\n },\n delete: async (tableId: string) => {\n if (!hasOwn(dbMap, tableId)) {\n throw new Error(`Unknown table "${tableId}" in database "${databaseId}"`);\n }\n const resolvedTableId = dbMap[tableId];\n await tablesDB.deleteTable({\n databaseId,\n tableId: resolvedTableId,\n });\n },\n{{/if}}\n };\n}\n\nfunction createDatabasesApi(tablesDB: TablesDB): DatabaseTables {\n const dbCache = new Map<DatabaseId, ReturnType<typeof createDatabaseHandle>>();\n\n return {\n use: (databaseId: DatabaseId) => {\n if (!hasOwn(tableIdMap, databaseId)) {\n throw new Error(`Unknown database "${databaseId}"`);\n }\n\n if (!dbCache.has(databaseId)) {\n dbCache.set(databaseId, createDatabaseHandle(tablesDB, databaseId));\n }\n return dbCache.get(databaseId);\n },\n{{#if supportsServerSide}}\n create: (databaseId: string, name: string, options?: { enabled?: boolean }) =>\n tablesDB.create({\n databaseId,\n name,\n enabled: options?.enabled,\n }),\n update: (databaseId: DatabaseId, options?: { name?: string; enabled?: boolean }) => {\n return tablesDB.update({\n databaseId,\n name: options?.name ?? databaseId,\n enabled: options?.enabled,\n });\n },\n delete: async (databaseId: DatabaseId) => {\n await tablesDB.delete({\n databaseId,\n });\n },\n{{/if}}\n } as DatabaseTables;\n}\n\n// Initialize client\nconst client = new Client()\n .setEndpoint(ENDPOINT)\n .setProject(PROJECT_ID){{#if supportsServerSide}}\n .setKey(API_KEY){{/if}};\n\nconst tablesDB = new TablesDB(client);\n\nexport const databases: DatabaseTables = createDatabasesApi(tablesDB);\n';
142179
142174
 
142180
142175
  // lib/commands/generators/typescript/templates/index.ts.hbs
142181
142176
  var index_ts_default = '/**\n * {{sdkTitle}} Generated SDK\n *\n * This file is auto-generated. Do not edit manually.\n * Re-run `{{executableName}} generate` to regenerate.\n */\n\nexport { databases } from "./databases.js";\nexport * from "./types.js";\n';
@@ -142188,6 +142183,8 @@ var typesTemplate = import_handlebars.default.compile(String(types_ts_default));
142188
142183
  var databasesTemplate = import_handlebars.default.compile(String(databases_ts_default));
142189
142184
  var indexTemplate = import_handlebars.default.compile(String(index_ts_default));
142190
142185
  var constantsTemplate = import_handlebars.default.compile(String(constants_ts_default));
142186
+ var PERMISSION_CALLBACK_INLINE = `(permission: { read: (role: RoleString) => string; write: (role: RoleString) => string; create: (role: RoleString) => string; update: (role: RoleString) => string; delete: (role: RoleString) => string }, role: { any: () => RoleString; user: (userId: string, status?: string) => RoleString; users: (status?: string) => RoleString; guests: () => RoleString; team: (teamId: string, role?: string) => RoleString; member: (memberId: string) => RoleString; label: (label: string) => RoleString }) => string[]`;
142187
+ var getQueryCallbackInline = (typeName) => `(q: { equal: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; notEqual: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; lessThan: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; lessThanEqual: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; greaterThan: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; greaterThanEqual: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; contains: <K extends QueryableKeys<${typeName}>>(field: K, value: ExtractQueryValue<${typeName}[K]>) => string; search: <K extends QueryableKeys<${typeName}>>(field: K, value: string) => string; isNull: <K extends QueryableKeys<${typeName}>>(field: K) => string; isNotNull: <K extends QueryableKeys<${typeName}>>(field: K) => string; startsWith: <K extends QueryableKeys<${typeName}>>(field: K, value: string) => string; endsWith: <K extends QueryableKeys<${typeName}>>(field: K, value: string) => string; between: <K extends QueryableKeys<${typeName}>>(field: K, start: ExtractQueryValue<${typeName}[K]>, end: ExtractQueryValue<${typeName}[K]>) => string; select: <K extends keyof ${typeName}>(fields: K[]) => string; orderAsc: <K extends keyof ${typeName}>(field: K) => string; orderDesc: <K extends keyof ${typeName}>(field: K) => string; limit: (value: number) => string; offset: (value: number) => string; cursorAfter: (documentId: string) => string; cursorBefore: (documentId: string) => string; or: (...queries: string[]) => string; and: (...queries: string[]) => string }) => string[]`;
142191
142188
  var TypeScriptDatabasesGenerator = class extends BaseDatabasesGenerator {
142192
142189
  language = "typescript";
142193
142190
  fileExtension = "ts";
@@ -142216,16 +142213,19 @@ var TypeScriptDatabasesGenerator = class extends BaseDatabasesGenerator {
142216
142213
  $id: e.$id,
142217
142214
  name: e.name
142218
142215
  }));
142219
- const attributes = this.buildAttributes(entity, typeEntities, " ");
142220
- const createType = attributes.trim().length === 0 ? `export type ${typeName}Create = Record<string, never>` : `export type ${typeName}Create = {
142221
- ${attributes}
142216
+ const createAttributes = this.buildAttributes(entity, typeEntities, " ", true);
142217
+ const rowAttributes = this.buildAttributes(entity, typeEntities, " ", false);
142218
+ const createType = createAttributes.trim().length === 0 ? `export type ${typeName}Create = Record<string, never>` : `export type ${typeName}Create = {
142219
+ ${createAttributes}
142220
+ }`;
142221
+ const rowType = rowAttributes.trim().length === 0 ? `export type ${typeName} = Models.Row` : `export type ${typeName} = Models.Row & {
142222
+ ${rowAttributes}
142222
142223
  }`;
142223
- const rowType = `export type ${typeName} = Models.Row & ${typeName}Create`;
142224
142224
  return `${createType}
142225
142225
 
142226
142226
  ${rowType}`;
142227
142227
  }
142228
- buildAttributes(entity, typeEntities, indent) {
142228
+ buildAttributes(entity, typeEntities, indent, forCreate = false) {
142229
142229
  const fields = this.getFields(entity);
142230
142230
  if (!fields) return "";
142231
142231
  return fields.map((attr) => {
@@ -142242,7 +142242,7 @@ ${rowType}`;
142242
142242
  relationType: attr.relationType,
142243
142243
  side: attr.side
142244
142244
  };
142245
- return `${indent}${JSON.stringify(attr.key)}${attr.required ? "" : "?"}: ${getTypeScriptType(typeAttr, typeEntities, entity.name)};`;
142245
+ return `${indent}${JSON.stringify(attr.key)}${attr.required ? "" : "?"}: ${getTypeScriptType(typeAttr, typeEntities, entity.name, forCreate)};`;
142246
142246
  }).join("\n");
142247
142247
  }
142248
142248
  generateEnums(entities) {
@@ -142295,21 +142295,24 @@ ${enumValues}
142295
142295
  const createFields = this.buildAttributes(
142296
142296
  entity,
142297
142297
  typeEntities,
142298
- " "
142298
+ " ",
142299
+ true
142300
+ // forCreate - relationships use Create suffix
142299
142301
  );
142300
142302
  const createInline = createFields.trim().length === 0 ? "Record<string, never>" : `{
142301
142303
  ${createFields}
142302
142304
  }`;
142303
- const baseMethods = ` create: (data: ${createInline}, options?: { rowId?: string; permissions?: Permission[]; transactionId?: string }) => Promise<${typeName}>;
142305
+ const queryCallback = getQueryCallbackInline(typeName);
142306
+ const baseMethods = ` create: (data: ${createInline}, options?: { rowId?: string; permissions?: ${PERMISSION_CALLBACK_INLINE}; transactionId?: string }) => Promise<${typeName}>;
142304
142307
  get: (id: string) => Promise<${typeName}>;
142305
- update: (id: string, data: Partial<${createInline}>, options?: { permissions?: Permission[]; transactionId?: string }) => Promise<${typeName}>;
142308
+ update: (id: string, data: Partial<${createInline}>, options?: { permissions?: ${PERMISSION_CALLBACK_INLINE}; transactionId?: string }) => Promise<${typeName}>;
142306
142309
  delete: (id: string, options?: { transactionId?: string }) => Promise<void>;
142307
- list: (options?: { queries?: (q: QueryBuilder<${typeName}>) => string[] }) => Promise<{ total: number; rows: ${typeName}[] }>;`;
142310
+ list: (options?: { queries?: ${queryCallback} }) => Promise<{ total: number; rows: ${typeName}[] }>;`;
142308
142311
  const canUseBulkMethods = supportsServerSide && !this.hasRelationshipColumns(entity);
142309
142312
  const bulkMethods = canUseBulkMethods ? `
142310
142313
  createMany: (rows: Array<${createInline} & { $id?: string; $permissions?: string[] }>, options?: { transactionId?: string }) => Promise<{ total: number; rows: ${typeName}[] }>;
142311
- updateMany: (data: Partial<${createInline}>, options?: { queries?: (q: QueryBuilder<${typeName}>) => string[]; transactionId?: string }) => Promise<{ total: number; rows: ${typeName}[] }>;
142312
- deleteMany: (options?: { queries?: (q: QueryBuilder<${typeName}>) => string[]; transactionId?: string }) => Promise<{ total: number; rows: ${typeName}[] }>;` : "";
142314
+ updateMany: (data: Partial<${createInline}>, options?: { queries?: ${queryCallback}; transactionId?: string }) => Promise<{ total: number; rows: ${typeName}[] }>;
142315
+ deleteMany: (options?: { queries?: ${queryCallback}; transactionId?: string }) => Promise<{ total: number; rows: ${typeName}[] }>;` : "";
142313
142316
  return ` ${JSON.stringify(entity.name)}: {
142314
142317
  ${baseMethods}${bulkMethods}
142315
142318
  }`;
@@ -142322,40 +142325,18 @@ ${tableTypes}
142322
142325
  ${dbReturnTypes}
142323
142326
  };
142324
142327
 
142325
- export type DatabaseCreateOptions = {
142326
- enabled?: boolean;
142327
- };
142328
-
142329
- export type DatabaseUpdateOptions = {
142330
- enabled?: boolean;
142331
- };
142332
-
142333
- export type TableCreateOptions = {
142334
- permissions?: Permission[];
142335
- rowSecurity?: boolean;
142336
- enabled?: boolean;
142337
- columns?: any[];
142338
- indexes?: any[];
142339
- };
142340
-
142341
- export type TableUpdateOptions = {
142342
- permissions?: Permission[];
142343
- rowSecurity?: boolean;
142344
- enabled?: boolean;
142345
- };
142346
-
142347
142328
  export type DatabaseHandle<D extends DatabaseId> = {
142348
- use: <T extends keyof DatabaseTableMap[D] & string>(tableName: T) => DatabaseTableMap[D][T];
142349
- ${supportsServerSide ? ` create: (tableId: string, name: string, options?: TableCreateOptions) => Promise<Models.Table>;
142350
- update: <T extends keyof DatabaseTableMap[D] & string>(tableName: T, name: string, options?: TableUpdateOptions) => Promise<Models.Table>;
142351
- delete: <T extends keyof DatabaseTableMap[D] & string>(tableName: T) => Promise<void>;` : ""}
142329
+ use: <T extends keyof DatabaseTableMap[D] & string>(tableId: T) => DatabaseTableMap[D][T];
142330
+ ${supportsServerSide ? ` create: (tableId: string, name: string, options?: { permissions?: ${PERMISSION_CALLBACK_INLINE}; rowSecurity?: boolean; enabled?: boolean; columns?: any[]; indexes?: any[] }) => Promise<Models.Table>;
142331
+ update: <T extends keyof DatabaseTableMap[D] & string>(tableId: T, options?: { name?: string; permissions?: ${PERMISSION_CALLBACK_INLINE}; rowSecurity?: boolean; enabled?: boolean }) => Promise<Models.Table>;
142332
+ delete: <T extends keyof DatabaseTableMap[D] & string>(tableId: T) => Promise<void>;` : ""}
142352
142333
  };
142353
142334
 
142354
142335
  export type DatabaseTables = {
142355
142336
  use: <D extends DatabaseId>(databaseId: D) => DatabaseHandle<D>;
142356
- ${supportsServerSide ? ` create: (databaseId: string, name: string, options?: DatabaseCreateOptions) => Promise<Models.Database>;
142357
- update: (databaseId: DatabaseId, name: string, options?: DatabaseUpdateOptions) => Promise<Models.Database>;
142358
- delete: (databaseId: DatabaseId) => Promise<void>;` : ""}
142337
+ ${supportsServerSide ? ` create: (databaseId: string, name: string, options?: { enabled?: boolean }) => Promise<Models.Database>;
142338
+ update: <D extends DatabaseId>(databaseId: D, options?: { name?: string; enabled?: boolean }) => Promise<Models.Database>;
142339
+ delete: <D extends DatabaseId>(databaseId: D) => Promise<void>;` : ""}
142359
142340
  };`;
142360
142341
  }
142361
142342
  generateTypesFile(config2) {
@@ -142438,14 +142419,14 @@ ${supportsServerSide ? ` create: (databaseId: string, name: string, options?: D
142438
142419
  }
142439
142420
  generateBulkCheck(supportsBulk) {
142440
142421
  if (!supportsBulk) return "";
142441
- return `const hasBulkMethods = (dbId: string, tableName: string) => !tablesWithRelationships.has(\`\${dbId}:\${tableName}\`);
142422
+ return `const hasBulkMethods = (dbId: string, tableId: string) => !tablesWithRelationships.has(\`\${dbId}:\${tableId}\`);
142442
142423
  `;
142443
142424
  }
142444
142425
  generateBulkRemoval(supportsBulk) {
142445
142426
  if (!supportsBulk) return "";
142446
142427
  return `
142447
142428
  // Remove bulk methods for tables with relationships
142448
- if (!hasBulkMethods(databaseId, tableName)) {
142429
+ if (!hasBulkMethods(databaseId, tableId)) {
142449
142430
  delete (api as any).createMany;
142450
142431
  delete (api as any).updateMany;
142451
142432
  delete (api as any).deleteMany;
@@ -142569,7 +142550,7 @@ var generateAction = async (options) => {
142569
142550
  let detectedLanguage;
142570
142551
  const serverSideOverride = options.server ?? "auto";
142571
142552
  if (!["auto", "true", "false"].includes(serverSideOverride)) {
142572
- error48(`Invalid --server-side value: ${serverSideOverride}`);
142553
+ error48(`Invalid --server value: ${serverSideOverride}`);
142573
142554
  process.exit(1);
142574
142555
  }
142575
142556
  if (options.language) {
@@ -142634,9 +142615,6 @@ Use --language to specify the target language. Supported: ${supported}`
142634
142615
  const firstEntity = entities?.[0];
142635
142616
  const dbId = firstEntity?.databaseId ?? "databaseId";
142636
142617
  const tableName = firstEntity?.name ?? "tableName";
142637
- const formatAccessor = (value) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value) ? `.${value}` : `[${JSON.stringify(value)}]`;
142638
- const dbAccessor = formatAccessor(dbId);
142639
- const tableAccessor = formatAccessor(tableName);
142640
142618
  console.log("");
142641
142619
  log(`Import the generated SDK in your project:`);
142642
142620
  console.log(
@@ -142663,7 +142641,7 @@ var generate = new Command("generate").description(
142663
142641
  `Generate a type-safe SDK from your ${SDK_TITLE} project configuration`
142664
142642
  ).option(
142665
142643
  "-o, --output <directory>",
142666
- "Output directory for generated files (default: generated)",
142644
+ "Output directory for generated files",
142667
142645
  "generated"
142668
142646
  ).option(
142669
142647
  "-l, --language <language>",
@@ -142672,6 +142650,19 @@ var generate = new Command("generate").description(
142672
142650
  "--server <mode>",
142673
142651
  "Override server-side generation (auto|true|false)",
142674
142652
  "auto"
142653
+ ).addHelpText(
142654
+ "after",
142655
+ `
142656
+ Example:
142657
+ Import the generated SDK in your project:
142658
+ import { databases } from "./generated/${SDK_TITLE_LOWER}/index.js";
142659
+
142660
+ Configure your SDK constants:
142661
+ set values in ./generated/${SDK_TITLE_LOWER}/constants.ts
142662
+
142663
+ Usage:
142664
+ const mydb = databases.use("databaseId");
142665
+ await mydb.use("tableName").create({ ... });`
142675
142666
  ).action(actionRunner(generateAction));
142676
142667
 
142677
142668
  // lib/commands/services/account.ts