create-devoplus-one-app 0.1.0-next.186 → 0.1.0-next.190

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{mkdir,readdir,stat,writeFile}from"node:fs/promises";import{basename,dirname,join as join2,resolve}from"node:path";import{readFileSync,readdirSync,statSync}from"node:fs";var MONTHS=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];var DAYS=["sun","mon","tue","wed","thu","fri","sat"];var FIELDS=[{label:"dakika",min:0,max:59},{label:"saat",min:0,max:23},{label:"ayın günü",min:1,max:31},{label:"ay",min:1,max:12,names:MONTHS,nameBase:1},{label:"haftanın günü",min:0,max:7,names:DAYS,nameBase:0}];function value(raw,spec){if(/^\d{1,2}$/.test(raw)){const n=Number(raw);return n>=spec.min&&n<=spec.max?n:null}if(spec.names){const i=spec.names.indexOf(raw.toLowerCase());if(i>=0)return i+(spec.nameBase??0)}return null}function field(raw,spec){const values=new Set;const star=raw.startsWith("*");for(const part of raw.split(",")){const m=/^(\*|[A-Za-z0-9]+(?:-[A-Za-z0-9]+)?)(?:\/(\d{1,2}))?$/.exec(part);if(!m)return`${spec.label} alanında tanınmayan öğe: "${part}"`;const[,range,stepRaw]=m;const step=stepRaw===void 0?1:Number(stepRaw);if(step<1)return`${spec.label} alanında adım en az 1 olmalı: "${part}"`;let from;let to;if(range==="*"){from=spec.min;to=spec.max}else if(range.includes("-")){const[a,b]=range.split("-");const va=value(a,spec);const vb=value(b,spec);if(va===null||vb===null)return`${spec.label} alanında geçersiz aralık: "${part}" (${spec.min}-${spec.max})`;if(va>vb)return`${spec.label} alanında aralık ters: "${part}"`;from=va;to=vb}else{const v=value(range,spec);if(v===null)return`${spec.label} alanında geçersiz değer: "${part}" (${spec.min}-${spec.max})`;from=v;to=stepRaw===void 0?v:spec.max}for(let n=from;n<=to;n+=step)values.add(n)}return{values,star}}function parseCron(expression){if(typeof expression!=="string")return{ok:false,error:"cron ifadesi metin olmalı"};const parts=expression.trim().split(/\s+/);if(parts.length!==5||parts[0]==="")return{ok:false,error:"cron ifadesi tam 5 alan olmalı (dakika saat ayın-günü ay haftanın-günü)"};const parsed=[];for(let i=0;i<5;i++){const r=field(parts[i],FIELDS[i]);if(typeof r==="string")return{ok:false,error:r};parsed.push(r)}const[minute,hour,dom,month,dow]=parsed;const dayOfWeek=new Set([...dow.values].map(d=>d===7?0:d));return{ok:true,schedule:{minute:minute.values,hour:hour.values,dayOfMonth:dom.values,month:month.values,dayOfWeek,dayOfMonthStar:dom.star,dayOfWeekStar:dow.star}}}var TIME_ZONE_RE=/^[A-Za-z][A-Za-z0-9_+-]*(?:\/[A-Za-z0-9_+-]+){0,2}$/;function canonicalTimeZone(timeZone){if(typeof timeZone!=="string"||!TIME_ZONE_RE.test(timeZone))return null;try{return new Intl.DateTimeFormat("en-US",{timeZone}).resolvedOptions().timeZone}catch{return null}}import{z}from"zod";var SLUG_RE=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;var SLUG_MAX=24;function isValidSlug(slug2){return slug2.length<=SLUG_MAX&&SLUG_RE.test(slug2)}var JOB_NAME_RE=/^[a-z][a-z0-9-]{1,39}$/;var JOBS_MAX_SCHEDULES=10;var JOBS_MAX_QUEUES=10;var JOBS_DEFAULT_TIME_ZONE="Europe/Istanbul";var JOB_MAX_RETRIES_DEFAULT=3;var JOB_MAX_RETRIES_MAX=10;var JOB_BODY_MAX_BYTES=64*1024;var JOB_IDENTITY_MAX_AGE_MS=48*60*60*1e3;var JOB_SERVICE_SCOPES=["mail.execute","sms.execute","push.execute","dexa.read","ai.use"];var jobName=z.string().regex(JOB_NAME_RE,"ad küçük harfle başlar; yalnız küçük harf, rakam ve tire; 2-40 karakter");var description=z.string().trim().min(1).max(200).optional();var scheduleSchema=z.object({name:jobName,cron:z.string().superRefine((value2,ctx)=>{const r=parseCron(value2);if(!r.ok)ctx.addIssue({code:"custom",message:r.error})}),timeZone:z.string().default(JOBS_DEFAULT_TIME_ZONE).transform((value2,ctx)=>{const canonical=canonicalTimeZone(value2);if(!canonical){ctx.addIssue({code:"custom",message:`"${value2}" tanınan bir saat dilimi değil (ör. Europe/Istanbul, UTC)`});return z.NEVER}return canonical}),description}).strict();var queueSchema=z.object({name:jobName,maxRetries:z.number().int().min(0).max(JOB_MAX_RETRIES_MAX).default(JOB_MAX_RETRIES_DEFAULT),description}).strict();function uniqueNames(items,ctx){const seen=new Set;items.forEach((item,i)=>{if(seen.has(item.name))ctx.addIssue({code:"custom",path:[i,"name"],message:`"${item.name}" adı birden çok kez yazılmış`});seen.add(item.name)})}var jobsSchema=z.object({schedules:z.array(scheduleSchema).max(JOBS_MAX_SCHEDULES,`en çok ${JOBS_MAX_SCHEDULES} zamanlama beyan edilebilir`).superRefine(uniqueNames).default([]),queues:z.array(queueSchema).max(JOBS_MAX_QUEUES,`en çok ${JOBS_MAX_QUEUES} kuyruk beyan edilebilir`).superRefine(uniqueNames).default([]),services:z.array(z.string().refine(s=>JOB_SERVICE_SCOPES.includes(s),{message:`arka plan işi servisleri yalnız şunlar olabilir: ${JOB_SERVICE_SCOPES.join(", ")} (DEXA'ya yazma bu yolla açılmaz)`})).max(JOB_SERVICE_SCOPES.length).superRefine((items,ctx)=>{const seen=new Set;items.forEach((s,i)=>{if(seen.has(s))ctx.addIssue({code:"custom",path:[i],message:`"${s}" birden çok kez yazılmış`});seen.add(s)})}).optional()}).strict().refine(jobs=>jobs.schedules.length+jobs.queues.length>0,{message:"jobs en az bir zamanlama (schedules) ya da kuyruk (queues) taşımalıdır; hiç yoksa alanı yazmayın"});import{z as z3}from"zod";import{z as z2}from"zod";var AGENT_TOOL_NAME_RE=/^[a-z][a-z0-9-]{1,39}$/;var AGENT_TOOLS_MAX=20;var AGENT_INPUT_SCHEMA_MAX_BYTES=8*1024;var AGENT_INPUT_SCHEMA_MAX_DEPTH=8;var AGENT_INPUT_SCHEMA_MAX_PROPERTIES=50;var AGENT_INPUT_SCHEMA_MAX_ENUM=100;var AGENT_INPUT_SCHEMA_DESCRIPTION_MAX=500;var AGENT_INPUT_PROPERTY_RE=/^[A-Za-z_][A-Za-z0-9_]{0,63}$/;var AGENT_INPUT_KEYWORDS=["type","properties","required","enum","minimum","maximum","minLength","maxLength","items","description"];var AGENT_INPUT_TYPES=["object","string","number","integer","boolean","array"];var KEYWORDS=new Set(AGENT_INPUT_KEYWORDS);var TYPES=new Set(AGENT_INPUT_TYPES);function isPlainObject(value2){return value2!==null&&typeof value2==="object"&&!Array.isArray(value2)}function utf8Length(text){let n=0;for(const ch of text){const c=ch.codePointAt(0)??0;n+=c<128?1:c<2048?2:c<65536?3:4}return n}function join(path,key){return path?`${path}.${key}`:String(key)}function agentInputSchemaProblems(schema){const problems=[];let serialized;try{serialized=JSON.stringify(schema)??""}catch{return[{path:"",message:"şema JSON'a çevrilemiyor"}]}const bytes=utf8Length(serialized);if(bytes>AGENT_INPUT_SCHEMA_MAX_BYTES)problems.push({path:"",message:`şema en çok ${AGENT_INPUT_SCHEMA_MAX_BYTES} bayt olabilir (${bytes})`});if(!isPlainObject(schema))return[...problems,{path:"",message:"şema bir nesne olmalıdır"}];if(schema.type!=="object")problems.push({path:"type",message:'araç girdisinin kökü "type": "object" olmalıdır'});node(schema,"",1,problems);return problems}function node(schema,path,depth,out){if(!isPlainObject(schema)){out.push({path,message:"şema düğümü bir nesne olmalıdır"});return}if(depth>AGENT_INPUT_SCHEMA_MAX_DEPTH){out.push({path,message:`şema en çok ${AGENT_INPUT_SCHEMA_MAX_DEPTH} düzey iç içe olabilir`});return}for(const key of Object.keys(schema))if(!KEYWORDS.has(key))out.push({path:join(path,key),message:`"${key}" desteklenmiyor; izinli anahtarlar: ${AGENT_INPUT_KEYWORDS.join(", ")}`});const type=schema.type;if(typeof type!=="string"||!TYPES.has(type)){out.push({path:join(path,"type"),message:`"type" zorunludur ve şunlardan biri olmalıdır: ${AGENT_INPUT_TYPES.join(", ")}`});return}const only=(key,allowed)=>{if(key in schema&&!allowed.includes(type))out.push({path:join(path,key),message:`"${key}" yalnız ${allowed.join("/")} tipinde kullanılabilir`})};only("properties",["object"]);only("required",["object"]);only("items",["array"]);only("minimum",["number","integer"]);only("maximum",["number","integer"]);only("minLength",["string"]);only("maxLength",["string"]);if("description"in schema){const d=schema.description;if(typeof d!=="string"||d.trim().length===0||d.length>AGENT_INPUT_SCHEMA_DESCRIPTION_MAX)out.push({path:join(path,"description"),message:`"description" 1-${AGENT_INPUT_SCHEMA_DESCRIPTION_MAX} karakterlik metin olmalıdır`})}for(const key of["minimum","maximum"]){if(key in schema&&(typeof schema[key]!=="number"||!Number.isFinite(schema[key])))out.push({path:join(path,key),message:`"${key}" sonlu bir sayı olmalıdır`})}if(typeof schema.minimum==="number"&&typeof schema.maximum==="number"&&schema.minimum>schema.maximum)out.push({path:join(path,"minimum"),message:'"minimum" "maximum"dan büyük olamaz'});for(const key of["minLength","maxLength"]){const v=schema[key];if(key in schema&&(typeof v!=="number"||!Number.isSafeInteger(v)||v<0))out.push({path:join(path,key),message:`"${key}" negatif olmayan bir tam sayı olmalıdır`})}if(typeof schema.minLength==="number"&&typeof schema.maxLength==="number"&&schema.minLength>schema.maxLength)out.push({path:join(path,"minLength"),message:'"minLength" "maxLength"ten büyük olamaz'});if("enum"in schema){const values=schema.enum;if(!Array.isArray(values)||values.length===0||values.length>AGENT_INPUT_SCHEMA_MAX_ENUM){out.push({path:join(path,"enum"),message:`"enum" 1-${AGENT_INPUT_SCHEMA_MAX_ENUM} öğeli bir dizi olmalıdır`})}else{const seen=new Set;values.forEach((v,i)=>{const ok=type==="string"&&typeof v==="string"||type==="boolean"&&typeof v==="boolean"||type==="number"&&typeof v==="number"&&Number.isFinite(v)||type==="integer"&&typeof v==="number"&&Number.isSafeInteger(v);if(!ok)out.push({path:join(join(path,"enum"),i),message:`"enum" öğesi "${type}" tipinde olmalıdır`});const k=JSON.stringify(v);if(seen.has(k))out.push({path:join(join(path,"enum"),i),message:'"enum" öğesi birden çok kez yazılmış'});seen.add(k)})}}if(type==="object"){const props=schema.properties??{};if(!isPlainObject(props)){out.push({path:join(path,"properties"),message:'"properties" bir nesne olmalıdır'})}else{const names=Object.keys(props);if(names.length>AGENT_INPUT_SCHEMA_MAX_PROPERTIES)out.push({path:join(path,"properties"),message:`bir nesnede en çok ${AGENT_INPUT_SCHEMA_MAX_PROPERTIES} alan olabilir`});for(const name of names){if(!AGENT_INPUT_PROPERTY_RE.test(name))out.push({path:join(join(path,"properties"),name),message:'alan adı harf ya da "_" ile başlar, yalnız harf/rakam/"_" içerir, en çok 64 karakter'});node(props[name],join(join(path,"properties"),name),depth+1,out)}if("required"in schema){const req=schema.required;if(!Array.isArray(req)||req.some(r=>typeof r!=="string")){out.push({path:join(path,"required"),message:'"required" metin dizisi olmalıdır'})}else{const seen=new Set;req.forEach((r,i)=>{if(!(r in props))out.push({path:join(join(path,"required"),i),message:`"${r}" "properties" içinde tanımlı değil`});if(seen.has(r))out.push({path:join(join(path,"required"),i),message:`"${r}" birden çok kez yazılmış`});seen.add(r)})}}}}if(type==="array"){if(!("items"in schema))out.push({path:join(path,"items"),message:'dizi tipinde "items" zorunludur'});else node(schema.items,join(path,"items"),depth+1,out)}}var localized=z2.object({tr:z2.string().trim().min(1).max(200),en:z2.string().trim().min(1).max(200).optional()});var localizedLong=z2.object({tr:z2.string().trim().min(1).max(1e3),en:z2.string().trim().min(1).max(1e3).optional()});var agentToolSchema=z2.object({name:z2.string().regex(AGENT_TOOL_NAME_RE,'araç adı küçük harfle başlar, yalnız küçük harf/rakam/"-" içerir, 2-40 karakter'),title:localized,description:localizedLong,readOnly:z2.boolean(),permission:z2.string().optional(),input:z2.unknown().superRefine((schema,ctx)=>{for(const p of agentInputSchemaProblems(schema))ctx.addIssue({code:"custom",path:p.path?p.path.split("."):[],message:p.message})})}).strict();var agentSectionSchema=z2.object({summary:localizedLong,tools:z2.array(agentToolSchema).max(AGENT_TOOLS_MAX,`en çok ${AGENT_TOOLS_MAX} araç beyan edilebilir`).superRefine((tools,ctx)=>{const seen=new Set;tools.forEach((t,i)=>{if(seen.has(t.name))ctx.addIssue({code:"custom",path:[i,"name"],message:`"${t.name}" aracı birden çok kez yazılmış`});seen.add(t.name)})}).default([])}).strict();var localizedText=z3.object({tr:z3.string().trim().min(1).max(120),en:z3.string().trim().min(1).max(120).optional()});var SCOPE_RE=/^(?:[a-z][a-z0-9]*\.(?:read|write|manage|execute)|ai\.use)$/;var DEXA_QUERY_KEY_RE=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;var DEXA_QUERY_KEYS_MAX=64;function renamed(next){return z3.never({error:`bu alan kaldırıldı; yerine "services.${next}" yazın`}).optional()}var DEXA_READ_SCOPE="dexa.read";var DEXA_COMMAND_KEYS_MAX=32;var DEXA_WRITE_SCOPE="dexa.write";function dexaKeyList(kind,max){return z3.array(z3.string().regex(DEXA_QUERY_KEY_RE,"DEXA anahtarı harf ya da rakamla başlamalı, yalnız harf/rakam/./_/- içermeli ve en çok 128 karakter olmalıdır")).min(1,`en az bir DEXA ${kind} anahtarı beyan edilmelidir`).max(max,`en çok ${max} DEXA ${kind} anahtarı beyan edilebilir`).superRefine((keys,ctx)=>{const seen=new Set;keys.forEach((key,i)=>{if(seen.has(key))ctx.addIssue({code:"custom",path:[i],message:`"${key}" anahtarı birden çok kez yazılmış`});seen.add(key)})})}var NAVIGATION_MAX_ITEMS=12;var NAVIGATION_PATH_RE=/^\/(?:[A-Za-z0-9_-][A-Za-z0-9._-]*(?:\/[A-Za-z0-9_-][A-Za-z0-9._-]*)*)?$/;var NAVIGATION_PATH_MAX_LENGTH=200;var ACTING_SESSION_MODES=["read","write"];var DEVICE_PERMISSIONS=["camera","microphone","geolocation"];var semver=z3.string().regex(/^\d+\.\d+\.\d+$/,"semver biçimi x.y.z olmalı");var PERMISSION_CODE_RE=/^One\.[A-Z][A-Za-z0-9]*\.[A-Z][A-Za-z0-9]*$/;var permissionCode=z3.string().regex(PERMISSION_CODE_RE);var EXTRA_PERMISSIONS_MAX=16;function permissionNamespace(code){return code.slice(0,code.lastIndexOf(".")+1)}var manifestSchema=z3.object({schemaVersion:z3.literal(1),app:z3.object({slug:z3.string().max(SLUG_MAX).regex(SLUG_RE,"slug küçük harf/rakam ve tek tire içerebilir; harfle başlar"),name:localizedText,version:semver,description:localizedText.optional(),owner:z3.object({email:z3.string().email()})}),entry:z3.string().regex(/^[\w./-]+\.(ts|js|mjs)$/),scopes:z3.array(z3.string().regex(SCOPE_RE)).max(32).default([]),services:z3.object({database:z3.boolean().default(true),files:z3.boolean().default(false),cache:z3.boolean().default(false),d1:renamed("database"),r2:renamed("files"),kv:renamed("cache"),email:z3.boolean().default(false),sms:z3.boolean().default(false),push:z3.boolean().default(false),orgSchema:z3.boolean().default(false),dexa:z3.object({queryKeys:dexaKeyList("sorgu",DEXA_QUERY_KEYS_MAX).optional(),commandKeys:dexaKeyList("işlem",DEXA_COMMAND_KEYS_MAX).optional()}).refine(dexa=>dexa.queryKeys!==void 0||dexa.commandKeys!==void 0,{message:"services.dexa en az bir anahtar listesi taşımalıdır: queryKeys (okuma sorguları) ya da commandKeys (ERP işlemleri)"}).optional()}).strict().transform(({d1:_d1,r2:_r2,kv:_kv,...services})=>services).prefault({}),menu:z3.object({title:localizedText,icon:z3.string().max(64).optional(),group:z3.string().max(64).optional()}),permission:z3.object({code:permissionCode,name:localizedText}),permissions:z3.array(z3.object({code:permissionCode,name:localizedText}).strict()).max(EXTRA_PERMISSIONS_MAX,`en çok ${EXTRA_PERMISSIONS_MAX} ek izin beyan edilebilir`).default([]),navigation:z3.array(z3.object({path:z3.string().max(NAVIGATION_PATH_MAX_LENGTH,`yol en çok ${NAVIGATION_PATH_MAX_LENGTH} karakter olabilir`).regex(NAVIGATION_PATH_RE,"yol '/' ile başlar ve yalnız harf, rakam, '-', '_', '.' içeren parçalardan oluşur (sorgu, '#', '..' yok)"),label:localizedText,permission:z3.string().optional()}).strict()).max(NAVIGATION_MAX_ITEMS,`en çok ${NAVIGATION_MAX_ITEMS} menü öğesi beyan edilebilir`).superRefine((items,ctx)=>{const seen=new Set;items.forEach((item,i)=>{if(seen.has(item.path))ctx.addIssue({code:"custom",path:[i,"path"],message:`"${item.path}" yolu birden çok kez yazılmış`});seen.add(item.path)})}).default([]),actingSessions:z3.enum(ACTING_SESSION_MODES).default("read"),devicePermissions:z3.array(z3.enum(DEVICE_PERMISSIONS)).superRefine((items,ctx)=>{const seen=new Set;items.forEach((item,i)=>{if(seen.has(item))ctx.addIssue({code:"custom",path:[i],message:`"${item}" birden çok kez yazılmış`});seen.add(item)})}).default([]),agent:agentSectionSchema.optional(),limits:z3.object({cpuMs:z3.number().int().min(1).max(1e3).optional(),subRequests:z3.number().int().min(1).max(200).optional()}).optional(),observability:z3.object({headSamplingRate:z3.number().gt(0,"örnekleme oranı 0'dan büyük olmalıdır").max(1,"örnekleme oranı en çok 1 olabilir").optional()}).strict().optional(),jobs:jobsSchema.optional()}).strict().superRefine((manifest,ctx)=>{const ns=permissionNamespace(manifest.permission.code);const seen=new Set([manifest.permission.code]);manifest.permissions.forEach((p,i)=>{if(!p.code.startsWith(ns))ctx.addIssue({code:"custom",path:["permissions",i,"code"],message:`ek izin "${p.code}" ana iznin ad alanında olmalı (${ns}…)`});else if(seen.has(p.code))ctx.addIssue({code:"custom",path:["permissions",i,"code"],message:`"${p.code}" izni birden çok kez yazılmış`});seen.add(p.code)});const declared=new Set([manifest.permission.code,...manifest.permissions.map(p=>p.code)]);manifest.agent?.tools.forEach((tool,i)=>{if(tool.permission===void 0)return;if(!PERMISSION_CODE_RE.test(tool.permission)||!tool.permission.startsWith(ns))ctx.addIssue({code:"custom",path:["agent","tools",i,"permission"],message:`araç izni "${tool.permission}" uygulamanın ad alanında olmalı (${ns}…)`});else if(!declared.has(tool.permission))ctx.addIssue({code:"custom",path:["agent","tools",i,"permission"],message:`araç izni "${tool.permission}" manifest'te beyan edilmemiş — "permission.code" ya da "permissions" içinde olmalı`})});manifest.navigation.forEach((item,i)=>{if(item.permission===void 0)return;if(!PERMISSION_CODE_RE.test(item.permission)||!item.permission.startsWith(ns))ctx.addIssue({code:"custom",path:["navigation",i,"permission"],message:`sekme izni "${item.permission}" uygulamanın ad alanında olmalı (${ns}…)`});else if(!declared.has(item.permission))ctx.addIssue({code:"custom",path:["navigation",i,"permission"],message:`sekme izni "${item.permission}" manifest'te beyan edilmemiş — "permission.code" ya da "permissions" içinde olmalı`})});manifest.jobs?.services?.forEach((service,i)=>{if(!manifest.scopes.includes(service))ctx.addIssue({code:"custom",path:["jobs","services",i],message:`jobs.services içindeki "${service}" scopes içinde de beyan edilmelidir`})});const dexa=manifest.services.dexa;const pairs=[{scope:DEXA_READ_SCOPE,keys:dexa?.queryKeys,field:"queryKeys",what:"sorgu",verb:"DEXA sorguları"},{scope:DEXA_WRITE_SCOPE,keys:dexa?.commandKeys,field:"commandKeys",what:"işlem",verb:"DEXA işlemleri (ERP yazma)"}];for(const pair of pairs){const hasScope=manifest.scopes.includes(pair.scope);const hasKeys=pair.keys!==void 0;if(hasKeys&&!hasScope)ctx.addIssue({code:"custom",path:["scopes"],message:`services.dexa.${pair.field} beyan edildi; scopes içinde "${pair.scope}" de olmalıdır (${pair.verb} bu scope olmadan çalışmaz)`});if(hasScope&&!hasKeys)ctx.addIssue({code:"custom",path:["services","dexa"],message:`scopes içinde "${pair.scope}" var; services.dexa.${pair.field} ile çalıştırılacak ${pair.what} anahtarları da beyan edilmelidir`})}});function validateManifest(input){const r=manifestSchema.safeParse(input);if(r.success)return{ok:true,manifest:r.data};return{ok:false,errors:r.error.issues.map(i=>({path:i.path.join(".")||"(kök)",message:i.message}))}}var BLOCK_RE=/\{\{([#^])([A-Za-z0-9_]+)\}\}\n?([\s\S]*?)\{\{\/\2\}\}\n?/g;var VAR_RE=/\{\{([A-Za-z0-9_]+)\}\}/g;var MAX_NESTING=8;function lookup(vars,name){if(!Object.hasOwn(vars,name))throw new Error(`şablon değişkeni tanımsız: ${name}`);return vars[name]}function isTruthy(value2){return value2===true||typeof value2==="string"&&value2.length>0}function renderTemplate(source,vars){let out=source;for(let round=0;round<MAX_NESTING;round++){let changed=false;out=out.replace(BLOCK_RE,(_match,kind,name,body)=>{changed=true;return kind==="#"===isTruthy(lookup(vars,name))?body:""});if(!changed)break}if(/\{\{[#^/]/.test(out))throw new Error("şablon bloğu kapanmamış ya da çok derin");return out.replace(VAR_RE,(_match,name)=>{const value2=lookup(vars,name);if(typeof value2!=="string")throw new Error(`şablon değişkeni metin değil: ${name}`);return value2})}var TEMPLATE_NAMES=["blank","envanter","bakim-takvimi","saha-denetimi","egitim-sertifika","ziyaretci-kaydi","uygunsuzluk-dof","musteri-ziyaret","hedef-takibi"];var DEFAULT_TEMPLATE="blank";var TEMPLATES=[{name:"blank",title:{tr:"Boş iskelet",en:"Blank scaffold"},summary:{tr:"Kişisel notlar örneğiyle en küçük başlangıç; hiçbir şablon uymuyorsa",en:"Smallest start with a personal-notes sample; when no template fits"}},{name:"envanter",title:{tr:"Envanter",en:"Inventory"},summary:{tr:"Stok kalemleri, adet ve konum, giriş/çıkış hareketleri, düşük stok uyarısı ve günlük kontrol",en:"Stock items, quantity and location, in/out movements, low-stock alert and daily check"}},{name:"bakim-takvimi",title:{tr:"Bakım takvimi",en:"Maintenance schedule"},summary:{tr:"Cihaz ve ekipmanların periyodik bakımı; sıradaki bakım tarihi sunucuda hesaplanır, yaklaşan ve geciken bakım sorumluya hatırlatılır",en:"Periodic maintenance of devices and equipment; the next due date is computed on the server, upcoming and overdue work is reminded"}},{name:"saha-denetimi",title:{tr:"Saha denetimi",en:"Field audit"},summary:{tr:"Mağaza ve şube denetimi için kontrol listesi; madde başına sonuç, fotoğraf, sunucuda hesaplanan puan ve yazdırılabilir rapor",en:"Checklist for store and branch audits; per-item result, photo, server-computed score and printable report"}},{name:"egitim-sertifika",title:{tr:"Eğitim ve sertifika takibi",en:"Training and certificate tracking"},summary:{tr:"Çalışanların eğitim ve sertifikaları; süresi dolmak üzere olanlar kişiye ve yöneticisine hatırlatılır, yönetici ekibini görür",en:"Employee trainings and certificates; expiring ones are reminded to the person and their manager, managers see their team"}},{name:"ziyaretci-kaydi",title:{tr:"Ziyaretçi kaydı",en:"Visitor log"},summary:{tr:"Resepsiyonda ziyaretçi girişi ve çıkışı; ziyaret edilen çalışana bildirim, kişisel veriler belirli bir süre sonra kendiliğinden silinir",en:"Visitor check-in and check-out at reception; the host is notified, personal data is deleted automatically after a set period"}},{name:"uygunsuzluk-dof",title:{tr:"Uygunsuzluk ve düzeltici faaliyet",en:"Nonconformity and corrective action"},summary:{tr:"Kalite ve iş güvenliği uygunsuzlukları; kök neden, sorumlu ve terminli düzeltici faaliyetler, geciken faaliyet hatırlatması",en:"Quality and safety nonconformities; root cause, corrective actions with owner and due date, overdue reminders"}},{name:"musteri-ziyaret",title:{tr:"Müşteri ziyaret raporu",en:"Customer visit report"},summary:{tr:"Saha ekibinin müşteri ziyaretleri; müşteri listesi ERP'ye bağlanabilir, ziyaret notu ve sonraki adım kaydedilir, yönetici ekibini görür",en:"Field team customer visits; the customer list can be connected to the ERP, visit notes and next steps are recorded, managers see their team"}},{name:"hedef-takibi",title:{tr:"Hedef ve aksiyon takibi",en:"Goal and action tracking"},summary:{tr:"Ekip hedefleri, ölçülebilir sonuçlar ve aksiyonlar; ilerleme sunucuda hesaplanır, dönem panosu ve Excel",en:"Team goals, measurable results and actions; progress is computed on the server, period board and Excel"}}];function isTemplateName(value2){return TEMPLATE_NAMES.includes(value2)}var FOLD_COLUMN_SUFFIX="_fold";var FOLD_PAIRS=[["Ç","c"],["ç","c"],["Ğ","g"],["ğ","g"],["İ","i"],["ı","i"],["Ö","o"],["ö","o"],["Ş","s"],["ş","s"],["Ü","u"],["ü","u"],["Â","a"],["â","a"],["Î","i"],["î","i"],["Û","u"],["û","u"]];var FOLD_MAP=new Map(FOLD_PAIRS);var FOLD_RE=new RegExp(`[${FOLD_PAIRS.map(([from])=>from).join("")}]`,"g");function foldColumnName(column){return`${column}${FOLD_COLUMN_SUFFIX}`}var SQL_FOLD_PAIRS=[...FOLD_PAIRS.map(([from,to])=>[from.normalize("NFD"),to]).filter(([from],i)=>from!==FOLD_PAIRS[i][0]),...FOLD_PAIRS];var DATA_FIELD_TYPES=["text","longText","number","money","date","datetime","boolean","choice","person","file"];var DATA_NAME_RE=/^[a-z][a-z0-9_]{0,39}$/;var DATA_CHOICE_VALUE_RE=/^[a-z0-9][a-z0-9_-]{0,39}$/;var DATA_MAX_ENTITIES=30;var DATA_MAX_FIELDS=60;var DATA_MAX_CHOICES=100;var DATA_TITLE_MAX_LENGTH=120;var TEXT_DEFAULT_MAX_LENGTH=200;var TEXT_MAX_LENGTH=1e3;var LONG_TEXT_DEFAULT_MAX_LENGTH=1e4;var LONG_TEXT_MAX_LENGTH=5e4;var DATA_MAX_COLUMNS=100;var SYSTEM_COLUMNS=["id","created_at","created_by","updated_at","updated_by","deleted_at"];var SQL_KEYWORDS=new Set("abort action add after all alter always analyze and as asc attach autoincrement before begin between by cascade case cast check collate column commit conflict constraint create cross current current_date current_time current_timestamp database default deferrable deferred delete desc detach distinct do drop each else end escape except exclude exclusive exists explain fail filter first following for foreign from full generated glob group groups having if ignore immediate in index indexed initially inner insert instead intersect into is isnull join key last left like limit match materialized natural no not nothing notnull null nulls of offset on or order others outer over partition plan pragma preceding primary query raise range recursive references regexp reindex release rename replace restrict returning right rollback row rows savepoint select set table temp temporary then ties to transaction trigger unbounded union unique update using vacuum values view virtual when where window with without rowid oid _rowid_".split(" "));var RESERVED_TABLE_PREFIXES=["sqlite_","d1_","cf_","one_"];var DataModelError=class extends Error{issues;constructor(issues){super(issues.length===1?issues[0]:`Veri modelinde ${issues.length} sorun var:
2
+ import{mkdir,readdir,stat,writeFile}from"node:fs/promises";import{basename,dirname,join as join2,resolve}from"node:path";import{readFileSync,readdirSync,statSync}from"node:fs";var MONTHS=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];var DAYS=["sun","mon","tue","wed","thu","fri","sat"];var FIELDS=[{label:"dakika",min:0,max:59},{label:"saat",min:0,max:23},{label:"ayın günü",min:1,max:31},{label:"ay",min:1,max:12,names:MONTHS,nameBase:1},{label:"haftanın günü",min:0,max:7,names:DAYS,nameBase:0}];function value(raw,spec){if(/^\d{1,2}$/.test(raw)){const n=Number(raw);return n>=spec.min&&n<=spec.max?n:null}if(spec.names){const i=spec.names.indexOf(raw.toLowerCase());if(i>=0)return i+(spec.nameBase??0)}return null}function field(raw,spec){const values=new Set;const star=raw.startsWith("*");for(const part of raw.split(",")){const m=/^(\*|[A-Za-z0-9]+(?:-[A-Za-z0-9]+)?)(?:\/(\d{1,2}))?$/.exec(part);if(!m)return`${spec.label} alanında tanınmayan öğe: "${part}"`;const[,range,stepRaw]=m;const step=stepRaw===void 0?1:Number(stepRaw);if(step<1)return`${spec.label} alanında adım en az 1 olmalı: "${part}"`;let from;let to;if(range==="*"){from=spec.min;to=spec.max}else if(range.includes("-")){const[a,b]=range.split("-");const va=value(a,spec);const vb=value(b,spec);if(va===null||vb===null)return`${spec.label} alanında geçersiz aralık: "${part}" (${spec.min}-${spec.max})`;if(va>vb)return`${spec.label} alanında aralık ters: "${part}"`;from=va;to=vb}else{const v=value(range,spec);if(v===null)return`${spec.label} alanında geçersiz değer: "${part}" (${spec.min}-${spec.max})`;from=v;to=stepRaw===void 0?v:spec.max}for(let n=from;n<=to;n+=step)values.add(n)}return{values,star}}function parseCron(expression){if(typeof expression!=="string")return{ok:false,error:"cron ifadesi metin olmalı"};const parts=expression.trim().split(/\s+/);if(parts.length!==5||parts[0]==="")return{ok:false,error:"cron ifadesi tam 5 alan olmalı (dakika saat ayın-günü ay haftanın-günü)"};const parsed=[];for(let i=0;i<5;i++){const r=field(parts[i],FIELDS[i]);if(typeof r==="string")return{ok:false,error:r};parsed.push(r)}const[minute,hour,dom,month,dow]=parsed;const dayOfWeek=new Set([...dow.values].map(d=>d===7?0:d));return{ok:true,schedule:{minute:minute.values,hour:hour.values,dayOfMonth:dom.values,month:month.values,dayOfWeek,dayOfMonthStar:dom.star,dayOfWeekStar:dow.star}}}var TIME_ZONE_RE=/^[A-Za-z][A-Za-z0-9_+-]*(?:\/[A-Za-z0-9_+-]+){0,2}$/;function canonicalTimeZone(timeZone){if(typeof timeZone!=="string"||!TIME_ZONE_RE.test(timeZone))return null;try{return new Intl.DateTimeFormat("en-US",{timeZone}).resolvedOptions().timeZone}catch{return null}}import{z}from"zod";var SLUG_RE=/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;var SLUG_MAX=24;function isValidSlug(slug2){return slug2.length<=SLUG_MAX&&SLUG_RE.test(slug2)}var JOB_NAME_RE=/^[a-z][a-z0-9-]{1,39}$/;var JOBS_MAX_SCHEDULES=10;var JOBS_MAX_QUEUES=10;var JOBS_DEFAULT_TIME_ZONE="Europe/Istanbul";var JOB_MAX_RETRIES_DEFAULT=3;var JOB_MAX_RETRIES_MAX=10;var JOB_BODY_MAX_BYTES=64*1024;var JOB_IDENTITY_MAX_AGE_MS=48*60*60*1e3;var JOB_SERVICE_SCOPES=["mail.execute","sms.execute","push.execute","dexa.read","ai.use"];var jobName=z.string().regex(JOB_NAME_RE,"ad küçük harfle başlar; yalnız küçük harf, rakam ve tire; 2-40 karakter");var description=z.string().trim().min(1).max(200).optional();var scheduleSchema=z.object({name:jobName,cron:z.string().superRefine((value2,ctx)=>{const r=parseCron(value2);if(!r.ok)ctx.addIssue({code:"custom",message:r.error})}),timeZone:z.string().default(JOBS_DEFAULT_TIME_ZONE).transform((value2,ctx)=>{const canonical=canonicalTimeZone(value2);if(!canonical){ctx.addIssue({code:"custom",message:`"${value2}" tanınan bir saat dilimi değil (ör. Europe/Istanbul, UTC)`});return z.NEVER}return canonical}),description}).strict();var queueSchema=z.object({name:jobName,maxRetries:z.number().int().min(0).max(JOB_MAX_RETRIES_MAX).default(JOB_MAX_RETRIES_DEFAULT),description}).strict();function uniqueNames(items,ctx){const seen=new Set;items.forEach((item,i)=>{if(seen.has(item.name))ctx.addIssue({code:"custom",path:[i,"name"],message:`"${item.name}" adı birden çok kez yazılmış`});seen.add(item.name)})}var jobsSchema=z.object({schedules:z.array(scheduleSchema).max(JOBS_MAX_SCHEDULES,`en çok ${JOBS_MAX_SCHEDULES} zamanlama beyan edilebilir`).superRefine(uniqueNames).default([]),queues:z.array(queueSchema).max(JOBS_MAX_QUEUES,`en çok ${JOBS_MAX_QUEUES} kuyruk beyan edilebilir`).superRefine(uniqueNames).default([]),services:z.array(z.string().refine(s=>JOB_SERVICE_SCOPES.includes(s),{message:`arka plan işi servisleri yalnız şunlar olabilir: ${JOB_SERVICE_SCOPES.join(", ")} (DEXA'ya yazma bu yolla açılmaz)`})).max(JOB_SERVICE_SCOPES.length).superRefine((items,ctx)=>{const seen=new Set;items.forEach((s,i)=>{if(seen.has(s))ctx.addIssue({code:"custom",path:[i],message:`"${s}" birden çok kez yazılmış`});seen.add(s)})}).optional()}).strict().refine(jobs=>jobs.schedules.length+jobs.queues.length>0,{message:"jobs en az bir zamanlama (schedules) ya da kuyruk (queues) taşımalıdır; hiç yoksa alanı yazmayın"});import{z as z3}from"zod";import{z as z2}from"zod";var AGENT_TOOL_NAME_RE=/^[a-z][a-z0-9-]{1,39}$/;var AGENT_TOOLS_MAX=20;var AGENT_INPUT_SCHEMA_MAX_BYTES=8*1024;var AGENT_INPUT_SCHEMA_MAX_DEPTH=8;var AGENT_INPUT_SCHEMA_MAX_PROPERTIES=50;var AGENT_INPUT_SCHEMA_MAX_ENUM=100;var AGENT_INPUT_SCHEMA_DESCRIPTION_MAX=500;var AGENT_INPUT_PROPERTY_RE=/^[A-Za-z_][A-Za-z0-9_]{0,63}$/;var AGENT_INPUT_KEYWORDS=["type","properties","required","enum","minimum","maximum","minLength","maxLength","items","description"];var AGENT_INPUT_TYPES=["object","string","number","integer","boolean","array"];var KEYWORDS=new Set(AGENT_INPUT_KEYWORDS);var TYPES=new Set(AGENT_INPUT_TYPES);function isPlainObject(value2){return value2!==null&&typeof value2==="object"&&!Array.isArray(value2)}function utf8Length(text){let n=0;for(const ch of text){const c=ch.codePointAt(0)??0;n+=c<128?1:c<2048?2:c<65536?3:4}return n}function join(path,key){return path?`${path}.${key}`:String(key)}function agentInputSchemaProblems(schema){const problems=[];let serialized;try{serialized=JSON.stringify(schema)??""}catch{return[{path:"",message:"şema JSON'a çevrilemiyor"}]}const bytes=utf8Length(serialized);if(bytes>AGENT_INPUT_SCHEMA_MAX_BYTES)problems.push({path:"",message:`şema en çok ${AGENT_INPUT_SCHEMA_MAX_BYTES} bayt olabilir (${bytes})`});if(!isPlainObject(schema))return[...problems,{path:"",message:"şema bir nesne olmalıdır"}];if(schema.type!=="object")problems.push({path:"type",message:'araç girdisinin kökü "type": "object" olmalıdır'});node(schema,"",1,problems);return problems}function node(schema,path,depth,out){if(!isPlainObject(schema)){out.push({path,message:"şema düğümü bir nesne olmalıdır"});return}if(depth>AGENT_INPUT_SCHEMA_MAX_DEPTH){out.push({path,message:`şema en çok ${AGENT_INPUT_SCHEMA_MAX_DEPTH} düzey iç içe olabilir`});return}for(const key of Object.keys(schema))if(!KEYWORDS.has(key))out.push({path:join(path,key),message:`"${key}" desteklenmiyor; izinli anahtarlar: ${AGENT_INPUT_KEYWORDS.join(", ")}`});const type=schema.type;if(typeof type!=="string"||!TYPES.has(type)){out.push({path:join(path,"type"),message:`"type" zorunludur ve şunlardan biri olmalıdır: ${AGENT_INPUT_TYPES.join(", ")}`});return}const only=(key,allowed)=>{if(key in schema&&!allowed.includes(type))out.push({path:join(path,key),message:`"${key}" yalnız ${allowed.join("/")} tipinde kullanılabilir`})};only("properties",["object"]);only("required",["object"]);only("items",["array"]);only("minimum",["number","integer"]);only("maximum",["number","integer"]);only("minLength",["string"]);only("maxLength",["string"]);if("description"in schema){const d=schema.description;if(typeof d!=="string"||d.trim().length===0||d.length>AGENT_INPUT_SCHEMA_DESCRIPTION_MAX)out.push({path:join(path,"description"),message:`"description" 1-${AGENT_INPUT_SCHEMA_DESCRIPTION_MAX} karakterlik metin olmalıdır`})}for(const key of["minimum","maximum"]){if(key in schema&&(typeof schema[key]!=="number"||!Number.isFinite(schema[key])))out.push({path:join(path,key),message:`"${key}" sonlu bir sayı olmalıdır`})}if(typeof schema.minimum==="number"&&typeof schema.maximum==="number"&&schema.minimum>schema.maximum)out.push({path:join(path,"minimum"),message:'"minimum" "maximum"dan büyük olamaz'});for(const key of["minLength","maxLength"]){const v=schema[key];if(key in schema&&(typeof v!=="number"||!Number.isSafeInteger(v)||v<0))out.push({path:join(path,key),message:`"${key}" negatif olmayan bir tam sayı olmalıdır`})}if(typeof schema.minLength==="number"&&typeof schema.maxLength==="number"&&schema.minLength>schema.maxLength)out.push({path:join(path,"minLength"),message:'"minLength" "maxLength"ten büyük olamaz'});if("enum"in schema){const values=schema.enum;if(!Array.isArray(values)||values.length===0||values.length>AGENT_INPUT_SCHEMA_MAX_ENUM){out.push({path:join(path,"enum"),message:`"enum" 1-${AGENT_INPUT_SCHEMA_MAX_ENUM} öğeli bir dizi olmalıdır`})}else{const seen=new Set;values.forEach((v,i)=>{const ok=type==="string"&&typeof v==="string"||type==="boolean"&&typeof v==="boolean"||type==="number"&&typeof v==="number"&&Number.isFinite(v)||type==="integer"&&typeof v==="number"&&Number.isSafeInteger(v);if(!ok)out.push({path:join(join(path,"enum"),i),message:`"enum" öğesi "${type}" tipinde olmalıdır`});const k=JSON.stringify(v);if(seen.has(k))out.push({path:join(join(path,"enum"),i),message:'"enum" öğesi birden çok kez yazılmış'});seen.add(k)})}}if(type==="object"){const props=schema.properties??{};if(!isPlainObject(props)){out.push({path:join(path,"properties"),message:'"properties" bir nesne olmalıdır'})}else{const names=Object.keys(props);if(names.length>AGENT_INPUT_SCHEMA_MAX_PROPERTIES)out.push({path:join(path,"properties"),message:`bir nesnede en çok ${AGENT_INPUT_SCHEMA_MAX_PROPERTIES} alan olabilir`});for(const name of names){if(!AGENT_INPUT_PROPERTY_RE.test(name))out.push({path:join(join(path,"properties"),name),message:'alan adı harf ya da "_" ile başlar, yalnız harf/rakam/"_" içerir, en çok 64 karakter'});node(props[name],join(join(path,"properties"),name),depth+1,out)}if("required"in schema){const req=schema.required;if(!Array.isArray(req)||req.some(r=>typeof r!=="string")){out.push({path:join(path,"required"),message:'"required" metin dizisi olmalıdır'})}else{const seen=new Set;req.forEach((r,i)=>{if(!(r in props))out.push({path:join(join(path,"required"),i),message:`"${r}" "properties" içinde tanımlı değil`});if(seen.has(r))out.push({path:join(join(path,"required"),i),message:`"${r}" birden çok kez yazılmış`});seen.add(r)})}}}}if(type==="array"){if(!("items"in schema))out.push({path:join(path,"items"),message:'dizi tipinde "items" zorunludur'});else node(schema.items,join(path,"items"),depth+1,out)}}var localized=z2.object({tr:z2.string().trim().min(1).max(200),en:z2.string().trim().min(1).max(200).optional()});var localizedLong=z2.object({tr:z2.string().trim().min(1).max(1e3),en:z2.string().trim().min(1).max(1e3).optional()});var agentToolSchema=z2.object({name:z2.string().regex(AGENT_TOOL_NAME_RE,'araç adı küçük harfle başlar, yalnız küçük harf/rakam/"-" içerir, 2-40 karakter'),title:localized,description:localizedLong,readOnly:z2.boolean(),permission:z2.string().optional(),input:z2.unknown().superRefine((schema,ctx)=>{for(const p of agentInputSchemaProblems(schema))ctx.addIssue({code:"custom",path:p.path?p.path.split("."):[],message:p.message})})}).strict();var agentSectionSchema=z2.object({summary:localizedLong,tools:z2.array(agentToolSchema).max(AGENT_TOOLS_MAX,`en çok ${AGENT_TOOLS_MAX} araç beyan edilebilir`).superRefine((tools,ctx)=>{const seen=new Set;tools.forEach((t,i)=>{if(seen.has(t.name))ctx.addIssue({code:"custom",path:[i,"name"],message:`"${t.name}" aracı birden çok kez yazılmış`});seen.add(t.name)})}).default([])}).strict();var localizedText=z3.object({tr:z3.string().trim().min(1).max(120),en:z3.string().trim().min(1).max(120).optional()});var SCOPE_RE=/^(?:[a-z][a-z0-9]*\.(?:read|write|manage|execute)|ai\.use)$/;var DEXA_QUERY_KEY_RE=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;var DEXA_QUERY_KEYS_MAX=64;function renamed(next){return z3.never({error:`bu alan kaldırıldı; yerine "services.${next}" yazın`}).optional()}var DEXA_READ_SCOPE="dexa.read";var DEXA_COMMAND_KEYS_MAX=32;var DEXA_WRITE_SCOPE="dexa.write";function dexaKeyList(kind,max){return z3.array(z3.string().regex(DEXA_QUERY_KEY_RE,"DEXA anahtarı harf ya da rakamla başlamalı, yalnız harf/rakam/./_/- içermeli ve en çok 128 karakter olmalıdır")).min(1,`en az bir DEXA ${kind} anahtarı beyan edilmelidir`).max(max,`en çok ${max} DEXA ${kind} anahtarı beyan edilebilir`).superRefine((keys,ctx)=>{const seen=new Set;keys.forEach((key,i)=>{if(seen.has(key))ctx.addIssue({code:"custom",path:[i],message:`"${key}" anahtarı birden çok kez yazılmış`});seen.add(key)})})}var NAVIGATION_MAX_ITEMS=12;var NAVIGATION_PATH_RE=/^\/(?:[A-Za-z0-9_-][A-Za-z0-9._-]*(?:\/[A-Za-z0-9_-][A-Za-z0-9._-]*)*)?$/;var NAVIGATION_PATH_MAX_LENGTH=200;var ACTING_SESSION_MODES=["read","write"];var DEVICE_PERMISSIONS=["camera","microphone","geolocation"];var semver=z3.string().regex(/^\d+\.\d+\.\d+$/,"semver biçimi x.y.z olmalı");var PERMISSION_CODE_RE=/^One\.[A-Z][A-Za-z0-9]*\.[A-Z][A-Za-z0-9]*$/;var permissionCode=z3.string().regex(PERMISSION_CODE_RE);var EXTRA_PERMISSIONS_MAX=16;function permissionNamespace(code){return code.slice(0,code.lastIndexOf(".")+1)}var manifestSchema=z3.object({schemaVersion:z3.literal(1),app:z3.object({slug:z3.string().max(SLUG_MAX).regex(SLUG_RE,"slug küçük harf/rakam ve tek tire içerebilir; harfle başlar"),name:localizedText,version:semver,description:localizedText.optional(),owner:z3.object({email:z3.string().email()})}),entry:z3.string().regex(/^[\w./-]+\.(ts|js|mjs)$/),scopes:z3.array(z3.string().regex(SCOPE_RE)).max(32).default([]),services:z3.object({database:z3.boolean().default(true),files:z3.boolean().default(false),cache:z3.boolean().default(false),d1:renamed("database"),r2:renamed("files"),kv:renamed("cache"),email:z3.boolean().default(false),sms:z3.boolean().default(false),push:z3.boolean().default(false),orgSchema:z3.boolean().default(false),dexa:z3.object({queryKeys:dexaKeyList("sorgu",DEXA_QUERY_KEYS_MAX).optional(),commandKeys:dexaKeyList("işlem",DEXA_COMMAND_KEYS_MAX).optional()}).refine(dexa=>dexa.queryKeys!==void 0||dexa.commandKeys!==void 0,{message:"services.dexa en az bir anahtar listesi taşımalıdır: queryKeys (okuma sorguları) ya da commandKeys (ERP işlemleri)"}).optional()}).strict().transform(({d1:_d1,r2:_r2,kv:_kv,...services})=>services).prefault({}),menu:z3.object({title:localizedText,icon:z3.string().max(64).optional(),group:z3.string().max(64).optional()}),permission:z3.object({code:permissionCode,name:localizedText}),permissions:z3.array(z3.object({code:permissionCode,name:localizedText}).strict()).max(EXTRA_PERMISSIONS_MAX,`en çok ${EXTRA_PERMISSIONS_MAX} ek izin beyan edilebilir`).default([]),navigation:z3.array(z3.object({path:z3.string().max(NAVIGATION_PATH_MAX_LENGTH,`yol en çok ${NAVIGATION_PATH_MAX_LENGTH} karakter olabilir`).regex(NAVIGATION_PATH_RE,"yol '/' ile başlar ve yalnız harf, rakam, '-', '_', '.' içeren parçalardan oluşur (sorgu, '#', '..' yok)"),label:localizedText,permission:z3.string().optional()}).strict()).max(NAVIGATION_MAX_ITEMS,`en çok ${NAVIGATION_MAX_ITEMS} menü öğesi beyan edilebilir`).superRefine((items,ctx)=>{const seen=new Set;items.forEach((item,i)=>{if(seen.has(item.path))ctx.addIssue({code:"custom",path:[i,"path"],message:`"${item.path}" yolu birden çok kez yazılmış`});seen.add(item.path)})}).default([]),actingSessions:z3.enum(ACTING_SESSION_MODES).default("read"),devicePermissions:z3.array(z3.enum(DEVICE_PERMISSIONS)).superRefine((items,ctx)=>{const seen=new Set;items.forEach((item,i)=>{if(seen.has(item))ctx.addIssue({code:"custom",path:[i],message:`"${item}" birden çok kez yazılmış`});seen.add(item)})}).default([]),agent:agentSectionSchema.optional(),limits:z3.object({cpuMs:z3.number().int().min(1).max(1e3).optional(),subRequests:z3.number().int().min(1).max(200).optional()}).optional(),observability:z3.object({headSamplingRate:z3.number().gt(0,"örnekleme oranı 0'dan büyük olmalıdır").max(1,"örnekleme oranı en çok 1 olabilir").optional()}).strict().optional(),jobs:jobsSchema.optional()}).strict().superRefine((manifest,ctx)=>{const ns=permissionNamespace(manifest.permission.code);const seen=new Set([manifest.permission.code]);manifest.permissions.forEach((p,i)=>{if(!p.code.startsWith(ns))ctx.addIssue({code:"custom",path:["permissions",i,"code"],message:`ek izin "${p.code}" ana iznin ad alanında olmalı (${ns}…)`});else if(seen.has(p.code))ctx.addIssue({code:"custom",path:["permissions",i,"code"],message:`"${p.code}" izni birden çok kez yazılmış`});seen.add(p.code)});const declared=new Set([manifest.permission.code,...manifest.permissions.map(p=>p.code)]);manifest.agent?.tools.forEach((tool,i)=>{if(tool.permission===void 0)return;if(!PERMISSION_CODE_RE.test(tool.permission)||!tool.permission.startsWith(ns))ctx.addIssue({code:"custom",path:["agent","tools",i,"permission"],message:`araç izni "${tool.permission}" uygulamanın ad alanında olmalı (${ns}…)`});else if(!declared.has(tool.permission))ctx.addIssue({code:"custom",path:["agent","tools",i,"permission"],message:`araç izni "${tool.permission}" manifest'te beyan edilmemiş — "permission.code" ya da "permissions" içinde olmalı`})});manifest.navigation.forEach((item,i)=>{if(item.permission===void 0)return;if(!PERMISSION_CODE_RE.test(item.permission)||!item.permission.startsWith(ns))ctx.addIssue({code:"custom",path:["navigation",i,"permission"],message:`sekme izni "${item.permission}" uygulamanın ad alanında olmalı (${ns}…)`});else if(!declared.has(item.permission))ctx.addIssue({code:"custom",path:["navigation",i,"permission"],message:`sekme izni "${item.permission}" manifest'te beyan edilmemiş — "permission.code" ya da "permissions" içinde olmalı`})});manifest.jobs?.services?.forEach((service,i)=>{if(!manifest.scopes.includes(service))ctx.addIssue({code:"custom",path:["jobs","services",i],message:`jobs.services içindeki "${service}" scopes içinde de beyan edilmelidir`})});const dexa=manifest.services.dexa;const pairs=[{scope:DEXA_READ_SCOPE,keys:dexa?.queryKeys,field:"queryKeys",what:"sorgu",verb:"DEXA sorguları"},{scope:DEXA_WRITE_SCOPE,keys:dexa?.commandKeys,field:"commandKeys",what:"işlem",verb:"DEXA işlemleri (ERP yazma)"}];for(const pair of pairs){const hasScope=manifest.scopes.includes(pair.scope);const hasKeys=pair.keys!==void 0;if(hasKeys&&!hasScope)ctx.addIssue({code:"custom",path:["scopes"],message:`services.dexa.${pair.field} beyan edildi; scopes içinde "${pair.scope}" de olmalıdır (${pair.verb} bu scope olmadan çalışmaz)`});if(hasScope&&!hasKeys)ctx.addIssue({code:"custom",path:["services","dexa"],message:`scopes içinde "${pair.scope}" var; services.dexa.${pair.field} ile çalıştırılacak ${pair.what} anahtarları da beyan edilmelidir`})}});function validateManifest(input){const r=manifestSchema.safeParse(input);if(r.success)return{ok:true,manifest:r.data};return{ok:false,errors:r.error.issues.map(i=>({path:i.path.join(".")||"(kök)",message:i.message}))}}var MENU_ICON_NAMES=["address-book","align-center","align-justify","align-left","align-right","amazon","android","angle-double-down","angle-double-left","angle-double-right","angle-double-up","angle-down","angle-left","angle-right","angle-up","apple","arrow-circle-down","arrow-circle-left","arrow-circle-right","arrow-circle-up","arrow-down","arrow-down-left","arrow-down-left-and-arrow-up-right-to-center","arrow-down-right","arrow-left","arrow-right","arrow-right-arrow-left","arrow-up","arrow-up-left","arrow-up-right","arrow-up-right-and-arrow-down-left-from-center","arrows-alt","arrows-h","arrows-v","asterisk","at","backward","ban","barcode","bars","bell","bell-slash","bitcoin","bolt","book","bookmark","bookmark-fill","box","briefcase","building","building-columns","bullseye","calculator","calendar","calendar-clock","calendar-minus","calendar-plus","calendar-times","camera","car","caret-down","caret-left","caret-right","caret-up","cart-arrow-down","cart-minus","cart-plus","chart-bar","chart-line","chart-pie","chart-scatter","check","check-circle","check-square","chevron-circle-down","chevron-circle-left","chevron-circle-right","chevron-circle-up","chevron-down","chevron-left","chevron-right","chevron-up","circle","circle-fill","circle-off","circle-on","clipboard","clock","clone","cloud","cloud-download","cloud-upload","code","cog","comment","comments","compass","copy","credit-card","crown","database","delete-left","desktop","directions","directions-alt","discord","dollar","download","eject","ellipsis-h","ellipsis-v","envelope","equals","eraser","ethereum","euro","exclamation-circle","exclamation-triangle","expand","external-link","eye","eye-slash","face-smile","facebook","fast-backward","fast-forward","file","file-arrow-up","file-check","file-edit","file-excel","file-export","file-import","file-o","file-pdf","file-plus","file-word","filter","filter-fill","filter-slash","flag","flag-fill","folder","folder-open","folder-plus","forward","gauge","gift","github","globe","google","graduation-cap","hammer","hashtag","headphones","heart","heart-fill","history","home","hourglass","id-card","image","images","inbox","indian-rupee","info","info-circle","instagram","key","language","lightbulb","link","linkedin","list","list-check","lock","lock-open","map","map-marker","mars","megaphone","microchip","microchip-ai","microphone","microsoft","minus","minus-circle","mobile","money-bill","moon","objects-column","palette","paperclip","pause","pause-circle","paypal","pen-to-square","pencil","percentage","phone","pinterest","play","play-circle","plus","plus-circle","pound","power-off","prime","print","qrcode","question","question-circle","receipt","reddit","refresh","replay","reply","save","search","search-minus","search-plus","send","server","share-alt","shield","shop","shopping-bag","shopping-cart","sign-in","sign-out","sitemap","slack","sliders-h","sliders-v","sort","sort-alpha-down","sort-alpha-down-alt","sort-alpha-up","sort-alpha-up-alt","sort-alt","sort-alt-slash","sort-amount-down","sort-amount-down-alt","sort-amount-up","sort-amount-up-alt","sort-down","sort-down-fill","sort-numeric-down","sort-numeric-down-alt","sort-numeric-up","sort-numeric-up-alt","sort-up","sort-up-fill","sparkles","spinner","spinner-dotted","star","star-fill","star-half","star-half-fill","step-backward","step-backward-alt","step-forward","step-forward-alt","stop","stop-circle","stopwatch","sun","sync","table","tablet","tag","tags","telegram","th-large","thumbs-down","thumbs-down-fill","thumbs-up","thumbs-up-fill","thumbtack","ticket","tiktok","times","times-circle","trash","trophy","truck","turkish-lira","twitch","twitter","undo","unlock","upload","user","user-edit","user-minus","user-plus","users","venus","verified","video","vimeo","volume-down","volume-off","volume-up","wallet","warehouse","wave-pulse","whatsapp","wifi","window-maximize","window-minimize","wrench","youtube"];var KNOWN=new Set(MENU_ICON_NAMES);var BLOCK_RE=/\{\{([#^])([A-Za-z0-9_]+)\}\}\n?([\s\S]*?)\{\{\/\2\}\}\n?/g;var VAR_RE=/\{\{([A-Za-z0-9_]+)\}\}/g;var MAX_NESTING=8;function lookup(vars,name){if(!Object.hasOwn(vars,name))throw new Error(`şablon değişkeni tanımsız: ${name}`);return vars[name]}function isTruthy(value2){return value2===true||typeof value2==="string"&&value2.length>0}function renderTemplate(source,vars){let out=source;for(let round=0;round<MAX_NESTING;round++){let changed=false;out=out.replace(BLOCK_RE,(_match,kind,name,body)=>{changed=true;return kind==="#"===isTruthy(lookup(vars,name))?body:""});if(!changed)break}if(/\{\{[#^/]/.test(out))throw new Error("şablon bloğu kapanmamış ya da çok derin");return out.replace(VAR_RE,(_match,name)=>{const value2=lookup(vars,name);if(typeof value2!=="string")throw new Error(`şablon değişkeni metin değil: ${name}`);return value2})}var TEMPLATE_NAMES=["blank","envanter","bakim-takvimi","saha-denetimi","egitim-sertifika","ziyaretci-kaydi","uygunsuzluk-dof","musteri-ziyaret","hedef-takibi"];var DEFAULT_TEMPLATE="blank";var TEMPLATES=[{name:"blank",title:{tr:"Boş iskelet",en:"Blank scaffold"},summary:{tr:"Kişisel notlar örneğiyle en küçük başlangıç; hiçbir şablon uymuyorsa",en:"Smallest start with a personal-notes sample; when no template fits"}},{name:"envanter",title:{tr:"Envanter",en:"Inventory"},summary:{tr:"Stok kalemleri, adet ve konum, giriş/çıkış hareketleri, düşük stok uyarısı ve günlük kontrol",en:"Stock items, quantity and location, in/out movements, low-stock alert and daily check"}},{name:"bakim-takvimi",title:{tr:"Bakım takvimi",en:"Maintenance schedule"},summary:{tr:"Cihaz ve ekipmanların periyodik bakımı; sıradaki bakım tarihi sunucuda hesaplanır, yaklaşan ve geciken bakım sorumluya hatırlatılır",en:"Periodic maintenance of devices and equipment; the next due date is computed on the server, upcoming and overdue work is reminded"}},{name:"saha-denetimi",title:{tr:"Saha denetimi",en:"Field audit"},summary:{tr:"Mağaza ve şube denetimi için kontrol listesi; madde başına sonuç, fotoğraf, sunucuda hesaplanan puan ve yazdırılabilir rapor",en:"Checklist for store and branch audits; per-item result, photo, server-computed score and printable report"}},{name:"egitim-sertifika",title:{tr:"Eğitim ve sertifika takibi",en:"Training and certificate tracking"},summary:{tr:"Çalışanların eğitim ve sertifikaları; süresi dolmak üzere olanlar kişiye ve yöneticisine hatırlatılır, yönetici ekibini görür",en:"Employee trainings and certificates; expiring ones are reminded to the person and their manager, managers see their team"}},{name:"ziyaretci-kaydi",title:{tr:"Ziyaretçi kaydı",en:"Visitor log"},summary:{tr:"Resepsiyonda ziyaretçi girişi ve çıkışı; ziyaret edilen çalışana bildirim, kişisel veriler belirli bir süre sonra kendiliğinden silinir",en:"Visitor check-in and check-out at reception; the host is notified, personal data is deleted automatically after a set period"}},{name:"uygunsuzluk-dof",title:{tr:"Uygunsuzluk ve düzeltici faaliyet",en:"Nonconformity and corrective action"},summary:{tr:"Kalite ve iş güvenliği uygunsuzlukları; kök neden, sorumlu ve terminli düzeltici faaliyetler, geciken faaliyet hatırlatması",en:"Quality and safety nonconformities; root cause, corrective actions with owner and due date, overdue reminders"}},{name:"musteri-ziyaret",title:{tr:"Müşteri ziyaret raporu",en:"Customer visit report"},summary:{tr:"Saha ekibinin müşteri ziyaretleri; müşteri listesi ERP'ye bağlanabilir, ziyaret notu ve sonraki adım kaydedilir, yönetici ekibini görür",en:"Field team customer visits; the customer list can be connected to the ERP, visit notes and next steps are recorded, managers see their team"}},{name:"hedef-takibi",title:{tr:"Hedef ve aksiyon takibi",en:"Goal and action tracking"},summary:{tr:"Ekip hedefleri, ölçülebilir sonuçlar ve aksiyonlar; ilerleme sunucuda hesaplanır, dönem panosu ve Excel",en:"Team goals, measurable results and actions; progress is computed on the server, period board and Excel"}}];function isTemplateName(value2){return TEMPLATE_NAMES.includes(value2)}var FOLD_COLUMN_SUFFIX="_fold";var FOLD_PAIRS=[["Ç","c"],["ç","c"],["Ğ","g"],["ğ","g"],["İ","i"],["ı","i"],["Ö","o"],["ö","o"],["Ş","s"],["ş","s"],["Ü","u"],["ü","u"],["Â","a"],["â","a"],["Î","i"],["î","i"],["Û","u"],["û","u"]];var FOLD_MAP=new Map(FOLD_PAIRS);var FOLD_RE=new RegExp(`[${FOLD_PAIRS.map(([from])=>from).join("")}]`,"g");function foldColumnName(column){return`${column}${FOLD_COLUMN_SUFFIX}`}var SQL_FOLD_PAIRS=[...FOLD_PAIRS.map(([from,to])=>[from.normalize("NFD"),to]).filter(([from],i)=>from!==FOLD_PAIRS[i][0]),...FOLD_PAIRS];var DATA_FIELD_TYPES=["text","longText","number","money","date","datetime","boolean","choice","person","file"];var DATA_NAME_RE=/^[a-z][a-z0-9_]{0,39}$/;var DATA_CHOICE_VALUE_RE=/^[a-z0-9][a-z0-9_-]{0,39}$/;var DATA_MAX_ENTITIES=30;var DATA_MAX_FIELDS=60;var DATA_MAX_CHOICES=100;var DATA_TITLE_MAX_LENGTH=120;var TEXT_DEFAULT_MAX_LENGTH=200;var TEXT_MAX_LENGTH=1e3;var LONG_TEXT_DEFAULT_MAX_LENGTH=1e4;var LONG_TEXT_MAX_LENGTH=5e4;var DATA_MAX_COLUMNS=100;var SYSTEM_COLUMNS=["id","created_at","created_by","updated_at","updated_by","deleted_at"];var SQL_KEYWORDS=new Set("abort action add after all alter always analyze and as asc attach autoincrement before begin between by cascade case cast check collate column commit conflict constraint create cross current current_date current_time current_timestamp database default deferrable deferred delete desc detach distinct do drop each else end escape except exclude exclusive exists explain fail filter first following for foreign from full generated glob group groups having if ignore immediate in index indexed initially inner insert instead intersect into is isnull join key last left like limit match materialized natural no not nothing notnull null nulls of offset on or order others outer over partition plan pragma preceding primary query raise range recursive references regexp reindex release rename replace restrict returning right rollback row rows savepoint select set table temp temporary then ties to transaction trigger unbounded union unique update using vacuum values view virtual when where window with without rowid oid _rowid_".split(" "));var RESERVED_TABLE_PREFIXES=["sqlite_","d1_","cf_","one_"];var DataModelError=class extends Error{issues;constructor(issues){super(issues.length===1?issues[0]:`Veri modelinde ${issues.length} sorun var:
3
3
  - ${issues.join("\n- ")}`);this.name="DataModelError";this.issues=issues}};var isRecord=v=>typeof v==="object"&&v!==null&&!Array.isArray(v);function nameIssue(name,kind){if(!DATA_NAME_RE.test(name))return`${kind} adı "${name}" geçersiz: küçük harfle başlamalı, yalnız küçük harf (a-z), rakam ve alt çizgi içermeli, en çok 40 karakter olmalı.`;if(name.includes("__")||name.endsWith("_"))return`${kind} adı "${name}" çift alt çizgi içeremez ve alt çizgiyle bitemez.`;if(SQL_KEYWORDS.has(name))return`${kind} adı "${name}" veritabanı dilinde ayrılmış bir sözcüktür; başka bir ad seçin (ör. "${name}_value").`;return null}function titleIssue(raw,where){if(!isRecord(raw))return`${where}: "title" { "tr": "…", "en": "…" } biçiminde olmalı.`;for(const lang of["tr","en"]){const v=raw[lang];if(typeof v!=="string"||v.trim()==="")return`${where}: "title.${lang}" boş olamaz (Türkçe ve İngilizce ad zorunlu).`;if(v.length>DATA_TITLE_MAX_LENGTH)return`${where}: "title.${lang}" en çok ${DATA_TITLE_MAX_LENGTH} karakter olabilir.`}for(const k of Object.keys(raw))if(k!=="tr"&&k!=="en")return`${where}: "title" içinde bilinmeyen dil "${k}" (yalnız "tr" ve "en").`;return null}var FIELD_KEYS=new Set(["type","title","required","unique","index","default","choices","maxLength","min","max"]);var ENTITY_KEYS=new Set(["title","fields","softDelete"]);var NOT_UNIQUE=new Set(["longText","boolean"]);var NOT_INDEXED=new Set(["longText"]);var NO_DEFAULT=new Set(["person","file"]);function moneyToMinor(raw){let text;if(typeof raw==="number"){if(!Number.isFinite(raw))return null;text=String(raw);if(/e/i.test(text))return null}else text=raw.trim();const m=/^(-)?(\d{1,16})(?:[.,](\d{1,2}))?$/.exec(text);if(!m)return null;const minor=Number(m[2])*100+Number((m[3]??"").padEnd(2,"0")||"0");if(!Number.isSafeInteger(minor))return null;return m[1]&&minor!==0?-minor:minor}function minorToMoney(minor){const abs=Math.abs(minor);const major=Math.floor(abs/100);const cents=String(abs%100).padStart(2,"0");return`${minor<0?"-":""}${major}.${cents}`}var DATE_RE=/^(\d{4})-(\d{2})-(\d{2})$/;var DATETIME_RE=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?(?:Z|[+-]\d{2}:\d{2})$/;function isCalendarDate(text){const m=DATE_RE.exec(text);if(!m)return false;const[y,mo,d]=[Number(m[1]),Number(m[2]),Number(m[3])];const date=new Date(Date.UTC(y,mo-1,d));return y>=1&&date.getUTCFullYear()===y&&date.getUTCMonth()===mo-1&&date.getUTCDate()===d}function normalizeDateTime(text){if(!DATETIME_RE.test(text)||!isCalendarDate(text.slice(0,10)))return null;const t=Date.parse(text);if(!Number.isFinite(t))return null;return new Date(t).toISOString()}function defaultIssue(field2,value2,where){const bad=expected=>`${where}: "default" ${expected} olmalı.`;switch(field2.type){case"text":case"longText":return typeof value2==="string"?null:bad("metin");case"number":return typeof value2==="number"&&Number.isFinite(value2)?null:bad("sayı");case"money":return(typeof value2==="number"||typeof value2==="string")&&moneyToMinor(value2)!==null?null:bad("en çok iki ondalık basamaklı tutar (ör. 12.50)");case"boolean":return typeof value2==="boolean"?null:bad("true ya da false");case"date":return typeof value2==="string"&&isCalendarDate(value2)?null:bad("YYYY-AA-GG biçiminde tarih");case"datetime":return typeof value2==="string"&&normalizeDateTime(value2)!==null?null:bad("bölgeli ISO tarih-saat (ör. 2026-01-31T09:00:00Z)");case"choice":return typeof value2==="string"&&field2.choices.some(c=>c.value===value2)?null:bad('seçeneklerden birinin "value" değeri');default:return`${where}: bu alan türünde varsayılan verilemez.`}}function parseDataModel(raw){const issues=[];if(!isRecord(raw))throw new DataModelError(['one.data.json bir JSON nesnesi olmalı: { "version": 1, "entities": { … } }.']);if(raw.version!==1)issues.push('"version" 1 olmalı.');for(const k of Object.keys(raw))if(k!=="version"&&k!=="entities"&&k!=="$schema")issues.push(`Bilinmeyen üst alan "${k}" (yalnız "version" ve "entities").`);if(!isRecord(raw.entities)){issues.push('"entities" bir nesne olmalı: { "<varlık adı>": { "title": …, "fields": { … } } }.');throw new DataModelError(issues)}const entityNames=Object.keys(raw.entities);if(entityNames.length>DATA_MAX_ENTITIES)issues.push(`En çok ${DATA_MAX_ENTITIES} varlık tanımlanabilir (${entityNames.length}).`);const entities=[];for(const entityName of entityNames){const where=`"${entityName}"`;const ni=nameIssue(entityName,"varlık");if(ni)issues.push(ni);else if(RESERVED_TABLE_PREFIXES.some(p=>entityName.startsWith(p)))issues.push(`varlık adı "${entityName}" platform için ayrılmış bir önekle başlıyor (${RESERVED_TABLE_PREFIXES.join(", ")}).`);const e=raw.entities[entityName];if(!isRecord(e)){issues.push(`${where}: varlık bir nesne olmalı.`);continue}for(const k of Object.keys(e))if(!ENTITY_KEYS.has(k))issues.push(`${where}: bilinmeyen alan "${k}" (title · fields · softDelete).`);const ti=titleIssue(e.title,where);if(ti)issues.push(ti);if(e.softDelete!==void 0&&typeof e.softDelete!=="boolean")issues.push(`${where}: "softDelete" true ya da false olmalı.`);if(!isRecord(e.fields)){issues.push(`${where}: "fields" bir nesne olmalı.`);continue}const fieldNames=Object.keys(e.fields);if(fieldNames.length===0)issues.push(`${where}: en az bir alan tanımlanmalı.`);if(fieldNames.length>DATA_MAX_FIELDS)issues.push(`${where}: bir varlıkta en çok ${DATA_MAX_FIELDS} alan olabilir (${fieldNames.length}).`);const fields=[];const columns=new Set(SYSTEM_COLUMNS);for(const fieldName of fieldNames){const fw=`${where}.${fieldName}`;const fni=nameIssue(fieldName,"alan");if(fni)issues.push(fni);else if(SYSTEM_COLUMNS.includes(fieldName))issues.push(`alan adı "${fieldName}" platformun otomatik kolonudur (${SYSTEM_COLUMNS.join(", ")}); başka bir ad seçin.`);else if(fieldName.endsWith("_minor"))issues.push(`alan adı "${fieldName}" "_minor" ile bitemez (para alanlarının kolon eki).`);else if(fieldName.endsWith(FOLD_COLUMN_SUFFIX))issues.push(`alan adı "${fieldName}" "${FOLD_COLUMN_SUFFIX}" ile bitemez (metin alanlarının arama kolonu eki).`);const f=e.fields[fieldName];if(!isRecord(f)){issues.push(`${fw}: alan bir nesne olmalı.`);continue}for(const k of Object.keys(f))if(!FIELD_KEYS.has(k))issues.push(`${fw}: bilinmeyen özellik "${k}".`);const type=f.type;if(typeof type!=="string"||!DATA_FIELD_TYPES.includes(type)){issues.push(`${fw}: "type" şunlardan biri olmalı: ${DATA_FIELD_TYPES.join(", ")}.`);continue}const t=type;const fti=titleIssue(f.title,fw);if(fti)issues.push(fti);for(const flag of["required","unique","index"])if(f[flag]!==void 0&&typeof f[flag]!=="boolean")issues.push(`${fw}: "${flag}" true ya da false olmalı.`);const unique=f.unique===true;if(unique&&NOT_UNIQUE.has(t))issues.push(`${fw}: "${t}" türündeki alan tekil (unique) olamaz.`);if(f.index===true&&NOT_INDEXED.has(t))issues.push(`${fw}: "${t}" türündeki alana dizin (index) eklenemez.`);let choices=[];if(t==="choice"){if(!Array.isArray(f.choices)||f.choices.length===0)issues.push(`${fw}: seçim alanında "choices" en az bir seçenek içermeli.`);else if(f.choices.length>DATA_MAX_CHOICES)issues.push(`${fw}: en çok ${DATA_MAX_CHOICES} seçenek olabilir.`);else{const seen=new Set;f.choices.forEach((c,i)=>{const cw=`${fw}.choices[${i}]`;if(!isRecord(c)||typeof c.value!=="string"||!DATA_CHOICE_VALUE_RE.test(c.value)){issues.push(`${cw}: "value" küçük harf, rakam, "_" ya da "-" içeren en çok 40 karakterlik bir kod olmalı (ör. "beklemede").`);return}if(seen.has(c.value))issues.push(`${cw}: "${c.value}" değeri tekrar ediyor.`);seen.add(c.value);const cti=titleIssue(c.title,cw);if(cti)issues.push(cti);for(const k of Object.keys(c))if(k!=="value"&&k!=="title")issues.push(`${cw}: bilinmeyen özellik "${k}".`);if(!cti)choices.push({value:c.value,title:{tr:c.title.tr,en:c.title.en}})})}}else if(f.choices!==void 0)issues.push(`${fw}: "choices" yalnız seçim (choice) alanında kullanılır.`);let maxLength;if(t==="text"||t==="longText"){const cap=t==="text"?TEXT_MAX_LENGTH:LONG_TEXT_MAX_LENGTH;if(f.maxLength===void 0)maxLength=t==="text"?TEXT_DEFAULT_MAX_LENGTH:LONG_TEXT_DEFAULT_MAX_LENGTH;else if(typeof f.maxLength!=="number"||!Number.isInteger(f.maxLength)||f.maxLength<1||f.maxLength>cap)issues.push(`${fw}: "maxLength" 1 ile ${cap} arasında bir tamsayı olmalı.`);else maxLength=f.maxLength}else if(f.maxLength!==void 0)issues.push(`${fw}: "maxLength" yalnız metin alanlarında kullanılır.`);let min;let max;for(const bound of["min","max"]){const v=f[bound];if(v===void 0)continue;if(t!=="number"&&t!=="money"){issues.push(`${fw}: "${bound}" yalnız sayı ve para alanlarında kullanılır.`);continue}if(typeof v!=="number"||!Number.isFinite(v)||t==="money"&&moneyToMinor(v)===null)issues.push(`${fw}: "${bound}" geçerli bir sayı olmalı${t==="money"?" (en çok iki ondalık basamak)":""}.`);else if(bound==="min")min=v;else max=v}if(min!==void 0&&max!==void 0&&min>max)issues.push(`${fw}: "min" "max"tan büyük olamaz.`);let def;if(f.default!==void 0){if(NO_DEFAULT.has(t))issues.push(`${fw}: "${t}" türündeki alanda varsayılan verilemez.`);else if(unique)issues.push(`${fw}: tekil (unique) alanda varsayılan verilemez (her kayıt aynı değeri alırdı).`);else{const di=defaultIssue({type:t,choices},f.default,fw);if(di)issues.push(di);else if(t==="money")def=minorToMoney(moneyToMinor(f.default));else if(t==="datetime")def=normalizeDateTime(f.default);else def=f.default;if(def!==void 0&&(t==="number"||t==="money")){const n=t==="money"?moneyToMinor(def)/100:def;if(min!==void 0&&n<min||max!==void 0&&n>max)issues.push(`${fw}: "default" min/max aralığının dışında.`)}if(def!==void 0&&maxLength!==void 0&&[...String(def)].length>maxLength)issues.push(`${fw}: "default" "maxLength" sınırını aşıyor.`)}}const column=t==="money"?`${fieldName}_minor`:fieldName;if(columns.has(column))issues.push(`${fw}: kolon adı "${column}" başka bir kolonla çakışıyor.`);columns.add(column);const foldColumn=t==="text"||t==="longText"?foldColumnName(column):void 0;if(foldColumn!==void 0){if(columns.has(foldColumn))issues.push(`${fw}: arama kolonu "${foldColumn}" başka bir kolonla çakışıyor.`);columns.add(foldColumn)}if(!fti)fields.push({name:fieldName,column,type:t,title:{tr:f.title.tr,en:f.title.en},required:f.required===true,unique,index:f.index===true,default:def,choices,maxLength,foldColumn,min,max})}if(columns.size>DATA_MAX_COLUMNS)issues.push(`${where}: tabloda en çok ${DATA_MAX_COLUMNS} kolon olabilir; bu varlık ${columns.size} kolon gerektiriyor (${SYSTEM_COLUMNS.length} otomatik + alanlar + her metin alanı için bir arama kolonu). Alanları iki varlığa bölün.`);if(!ti)entities.push({name:entityName,title:{tr:e.title.tr,en:e.title.en},softDelete:e.softDelete!==false,fields})}if(issues.length>0)throw new DataModelError(issues);return{version:1,entities}}function toModelInput(model){const entities={};for(const e of model.entities){const fields={};for(const f of e.fields){const out={type:f.type,title:{...f.title}};if(f.required)out.required=true;if(f.unique)out.unique=true;if(f.index)out.index=true;if(f.default!==void 0)out.default=f.default;if(f.choices.length>0)out.choices=f.choices.map(c=>({value:c.value,title:{...c.title}}));if(f.maxLength!==void 0)out.maxLength=f.maxLength;if(f.min!==void 0)out.min=f.min;if(f.max!==void 0)out.max=f.max;fields[f.name]=out}entities[e.name]={title:{...e.title},fields,softDelete:e.softDelete}}return{version:1,entities}}var DATA_SNAPSHOT_FILE=".one-data-snapshot.json";var DATA_MODEL_FILE="one.data.json";var DATA_TYPES_FILE="src/data/types.ts";var MIGRATION_NAME_RE=/^(\d{4})_[a-z0-9_]+\.sql$/;var q=name=>`"${name}"`;function sqlType(f){switch(f.type){case"number":return"REAL";case"money":case"boolean":return"INTEGER";default:return"TEXT"}}function literal(f,value2){if(f.type==="boolean")return value2===true?"1":"0";if(f.type==="money")return String(moneyToMinor(value2));if(f.type==="number")return String(value2);return`'${String(value2).replace(/'/g,"''")}'`}function checkClause(f){if(f.type==="boolean")return` CHECK (${q(f.column)} IN (0, 1))`;return""}function foldColumnDef(f){return f.foldColumn===void 0?null:`${q(f.foldColumn)} TEXT`}function columnDef(f,adding){let sql=`${q(f.column)} ${sqlType(f)}`;if(f.required){sql+=" NOT NULL";if(adding&&f.default!==void 0)sql+=` DEFAULT ${literal(f,f.default)}`}return sql+checkClause(f)}var indexName=(kind,entity,field2)=>`${kind}_${entity}__${field2}`;function indexSql(e,f){if(f.unique)return`CREATE UNIQUE INDEX ${q(indexName("ux",e.name,f.name))} ON ${q(e.name)} (${q(f.column)}) WHERE "deleted_at" IS NULL;`;if(f.index)return`CREATE INDEX ${q(indexName("ix",e.name,f.name))} ON ${q(e.name)} (${q(f.column)});`;return null}function createEntitySql(e){const cols=['"id" TEXT NOT NULL PRIMARY KEY','"created_at" TEXT NOT NULL','"created_by" TEXT NOT NULL','"updated_at" TEXT NOT NULL','"updated_by" TEXT NOT NULL','"deleted_at" TEXT',...e.fields.flatMap(f=>{const fold=foldColumnDef(f);return fold===null?[columnDef(f,false)]:[columnDef(f,false),fold]})];const out=[`CREATE TABLE ${q(e.name)} (
4
4
  ${cols.join(",\n ")}
5
5
  );`];out.push(`CREATE INDEX ${q(`ix_${e.name}__created_at`)} ON ${q(e.name)} ("created_at") WHERE "deleted_at" IS NULL;`);for(const f of e.fields){const ix=indexSql(e,f);if(ix)out.push(ix)}return out}var CURRENT={foldColumns:true,choiceChecks:new Set};function diffDataModels(prev,next,legacy=CURRENT){const statements=[];const changes=[];const errors=[];const prevEntities=new Map((prev?.entities??[]).map(e=>[e.name,e]));const nextNames=new Set(next.entities.map(e=>e.name));for(const old of prevEntities.values())if(!nextNames.has(old.name))errors.push(`"${old.name}" varlığı modelden kaldırılmış. Tablo ve verisi otomatik silinmez; varlığı one.data.json'a geri ekleyin (kullanmıyorsanız ekranlardan kaldırmanız yeterli).`);for(const e of next.entities){const old=prevEntities.get(e.name);if(!old){statements.push(`-- ${e.name}: ${e.title.tr}`,...createEntitySql(e));changes.push({kind:"create-table",entity:e.name});continue}const oldFields=new Map(old.fields.map(f=>[f.name,f]));const nextFieldNames=new Set(e.fields.map(f=>f.name));for(const of of old.fields)if(!nextFieldNames.has(of.name))errors.push(`"${e.name}.${of.name}" alanı kaldırılmış ya da adı değiştirilmiş. Kolon ve verisi otomatik silinmez/yeniden adlandırılmaz; alanı geri ekleyin (yeni bir ad gerekiyorsa yeni bir alan açın, eskisini kullanmayı bırakın).`);const added=[];for(const f of e.fields){const of=oldFields.get(f.name);const where=`"${e.name}.${f.name}"`;if(!of){if(f.required&&f.default===void 0)errors.push(`${where} zorunlu bir alan olarak eklenmiş ama varsayılanı yok: var olan kayıtlar bu alanı boş bırakamaz. Ya "default" verin ya da alanı isteğe bağlı ekleyin.`);if(f.unique&&f.default!==void 0)errors.push(`${where} tekil ve varsayılanlı eklenemez (var olan kayıtlar aynı değeri alırdı).`);if(f.unique&&f.required)errors.push(`${where} var olan bir tabloya tekil VE zorunlu eklenemez; isteğe bağlı tekil ekleyin.`);added.push(`ALTER TABLE ${q(e.name)} ADD COLUMN ${columnDef(f,true)};`);const fold=foldColumnDef(f);if(fold)added.push(`ALTER TABLE ${q(e.name)} ADD COLUMN ${fold};`);const ix=indexSql(e,f);if(ix)added.push(ix);changes.push({kind:"add-column",entity:e.name,field:f.name});continue}if(of.type!==f.type)errors.push(`${where} alanının türü "${of.type}" → "${f.type}" değiştirilmiş; tür değişikliği desteklenmez (yeni bir alan açın).`);if(of.required!==f.required)errors.push(`${where} alanı ${f.required?"zorunlu yapılmış":"isteğe bağlı yapılmış"}; var olan kolonun bu kuralı değiştirilemez (yeni bir alan açın ya da eski hâle döndürün).`);if(of.unique!==f.unique)errors.push(`${where} alanının tekillik (unique) kuralı değiştirilmiş; var olan kolonda desteklenmez.`);if(of.index&&!f.index)errors.push(`${where} alanının dizini (index) kaldırılmış; dizin silme desteklenmez, "index": true kalmalı.`);if(!of.index&&f.index&&!f.unique){added.push(indexSql(e,f));changes.push({kind:"add-index",entity:e.name,field:f.name})}if(of.type===f.type&&f.type==="choice"){const nextValues=new Set(f.choices.map(c=>c.value));const removed=of.choices.map(c=>c.value).filter(v=>!nextValues.has(v));const oldValues=new Set(of.choices.map(c=>c.value));const addedValues=f.choices.map(c=>c.value).filter(v=>!oldValues.has(v));if(removed.length>0)errors.push(`${where} seçim alanından değer kaldırılmış (${removed.join(", ")}). Var olan kayıtlar bu değeri taşıyabilir; değeri listede bırakın (artık kullanılmayacaksa ekranlardan gizleyin). Yalnız görünen adlar (title) ve sıra değişebilir.`);else if(addedValues.length>0&&legacy.choiceChecks.has(`${e.name}.${f.name}`))errors.push(`${where} seçim alanına değer eklenmiş (${addedValues.join(", ")}), ama bu alanın tablosu eski bir sürümle kurulmuş ve veritabanında değerleri bir kısıtla sabitlenmiş; kısıt ekleme yapan bir migration ile kaldırılamaz. Yeni değerler için yeni bir seçim alanı açın ya da platform ekibine danışın.`)}if(of.type===f.type&&f.foldColumn!==void 0&&!legacy.foldColumns){added.push(`ALTER TABLE ${q(e.name)} ADD COLUMN ${foldColumnDef(f)};`);changes.push({kind:"add-search-column",entity:e.name,field:f.name})}}if(added.length>0)statements.push(`-- ${e.name}: ${e.title.tr}`,...added)}return{statements,changes,errors}}var DATA_SNAPSHOT_VERSION=2;var isLegacyKey=v=>typeof v==="string"&&/^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/.test(v);function readSnapshot(raw){if(raw===null)return null;const broken=why=>new DataModelError([`migrations/${DATA_SNAPSHOT_FILE} ${why} — dosya elle düzenlenmez; git'teki son hâline döndürün.`]);let json;try{json=JSON.parse(raw)}catch{throw new DataModelError([`migrations/${DATA_SNAPSHOT_FILE} okunamadı (geçerli JSON değil). Bu dosya elle düzenlenmez; git'teki son hâline döndürün.`])}const doc2=json??{};let model;try{model=parseDataModel(doc2.model)}catch(e){if(e instanceof DataModelError)throw broken(`geçersiz: ${e.issues.join(" · ")}`);throw e}if(doc2.v===void 0||doc2.v===1){const checks=new Set;for(const e of model.entities)for(const f of e.fields)if(f.type==="choice")checks.add(`${e.name}.${f.name}`);return{model,legacy:{foldColumns:false,choiceChecks:checks}}}if(doc2.v!==DATA_SNAPSHOT_VERSION)throw broken(`bu SDK'nın tanımadığı bir sürümde (v: ${JSON.stringify(doc2.v)}); SDK'yı güncelleyin`);const raw2=doc2.choiceChecks??[];if(!Array.isArray(raw2)||!raw2.every(isLegacyKey))throw broken('geçersiz: "choiceChecks" "<varlık>.<alan>" listesi olmalı');return{model,legacy:{foldColumns:true,choiceChecks:new Set(raw2)}}}function renderSnapshot(model,legacy=CURRENT){const present=new Set(model.entities.flatMap(e=>e.fields.filter(f=>f.type==="choice").map(f=>`${e.name}.${f.name}`)));const choiceChecks=[...legacy.choiceChecks].filter(k=>present.has(k)).sort();return JSON.stringify({note:"one data generate tarafından yazılır; elle düzenlemeyin. Bir sonraki üretimin farkı bu modele göre alınır.",v:DATA_SNAPSHOT_VERSION,...choiceChecks.length>0?{choiceChecks}:{},model:toModelInput(model)},null,2)+"\n"}function nextMigrationName(existing2){let max=0;for(const name of existing2){const m=MIGRATION_NAME_RE.exec(name);if(m)max=Math.max(max,Number(m[1]))}if(max>=9999)throw new DataModelError(["migrations/ altında 9999 numarasına ulaşılmış; yeni numara verilemiyor."]);return`${String(max+1).padStart(4,"0")}_one_data.sql`}function tablesCreatedIn(sql){const text=sql.replace(/--[^\n]*/g," ").replace(/\/\*[\s\S]*?\*\//g," ");const out=new Set;const re=/\bcreate\s+(?:temp\s+|temporary\s+|virtual\s+)?table\s+(?:if\s+not\s+exists\s+)?(?:main\s*\.\s*)?["`[]?([A-Za-z0-9_]+)["`\]]?/gi;for(const m of text.matchAll(re))out.add(m[1].toLowerCase());return out}function planDataGeneration(input){const next=parseDataModel(input.model);const prev=readSnapshot(input.snapshot);const legacy=prev?.legacy??CURRENT;const diff=diffDataModels(prev?.model??null,next,legacy);const issues=[...diff.errors];const handwritten=new Set;for(const m of input.existing)for(const t of tablesCreatedIn(m.sql))handwritten.add(t);for(const c of diff.changes)if(c.kind==="create-table"&&handwritten.has(c.entity))issues.push(`"${c.entity}" adında bir tablo elle yazılmış bir migration'da zaten kuruluyor; varlığa başka bir ad verin.`);if(issues.length>0)throw new DataModelError(issues);const migration=diff.statements.length===0?null:{name:nextMigrationName(input.existing.map(m=>m.name)),sql:"-- one data generate tarafından one.data.json'dan üretildi.\n-- ⛔ Uygulandıktan sonra bu dosya DEĞİŞTİRİLMEZ: model değişince bir sonraki numarayla yeni dosya üretilir.\n-- Her kurulumun kendi veritabanı vardır; tablolarda portal kolonu yoktur. Kişi = kullanıcı kimliği (sub).\n"+diff.statements.join("\n")+"\n"};return{migration,types:renderTypes(next),snapshot:renderSnapshot(next,legacy),changes:diff.changes}}var pascal=name=>name.split("_").filter(Boolean).map(p=>p[0].toUpperCase()+p.slice(1)).join("");function tsValueType(f){switch(f.type){case"number":return"number";case"boolean":return"boolean";case"choice":return f.choices.map(c=>JSON.stringify(c.value)).join(" | ");default:return"string"}}function tsInputType(f){if(f.type==="money")return"string | number";if(f.type==="number")return"number | string";return tsValueType(f)}var doc=f=>{const unit=f.type==="money"?' — tutar, ondalıklı metin ("1234.50")':f.type==="date"?" — YYYY-AA-GG":f.type==="datetime"?" — ISO tarih-saat (UTC)":f.type==="person"?" — kişi (kullanıcı kimliği, sub)":f.type==="file"?" — dosya anahtarı":"";return` /** ${f.title.tr}${unit} */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-devoplus-one-app",
3
- "version": "0.1.0-next.186",
3
+ "version": "0.1.0-next.190",
4
4
  "description": "Yeni bir Devoplus One uygulaması iskeleti üretir: manifest, SDK'lı giriş noktası, Portal köprülü kabuk, veritabanı migration'ı ve AGENTS.md",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "type": "module",
@@ -125,6 +125,8 @@ metinle sorun ve şıkları numaralı yazın. Teknik soru sorulmaz.
125
125
  {{^hasScopes}}
126
126
  Bu uygulama henüz scope beyan etmiyor (yalnız kimlik + kendi veritabanı).
127
127
  {{/hasScopes}}
128
+ - Menü simgesi `one.manifest.json` dosyasındaki `menu.icon` alanıdır: PrimeIcons sınıfı (ör. `pi pi-box`, `pi pi-flag`). Listede
129
+ olmayan değer menüde varsayılan simgeyle çizilir ve doğrulama uyarı yazar; değişiklik bir sonraki yayında menüye geçer.
128
130
  - Portal menüsünde görünme izni `{{permissionCode}}` kodudur; kimin kullanacağını portal yöneticisi Yetki Yönetimi'nden
129
131
  atar; uygulama kendi içinde ikinci bir yetki modeli KURMAZ (kendi rol tablosu, e-posta listesiyle yetki vb. YAZILMAZ).
130
132
  - Uygulama içinde rol gerekiyorsa (ör. yalnız onaylayanlar onaylasın) **ek izin kodu** beyan edilir: