[{"data":1,"prerenderedAt":26087},["ShallowReactive",2],{"navigation":3,"/releases-archive":287,"/releases-archive-surround":26084},[4,24,64,112,148,180,263,267,271,275,279,283],{"title":5,"path":6,"stem":7,"children":8},"Getting Started","/getting-started","1.getting-started",[9,12,16,20],{"title":10,"path":6,"stem":11},"Introduction","1.getting-started/index",{"title":13,"path":14,"stem":15},"Installation","/getting-started/installation","1.getting-started/1.installation",{"title":17,"path":18,"stem":19},"Quickstart","/getting-started/quickstart","1.getting-started/2.quickstart",{"title":21,"path":22,"stem":23},"Build Your First API","/getting-started/first-api","1.getting-started/3.first-api",{"title":25,"path":26,"stem":27,"children":28},"Essentials","/essentials","2.essentials",[29,32,36,40,44,48,52,56,60],{"title":30,"path":26,"stem":31},"Core concepts","2.essentials/index",{"title":33,"path":34,"stem":35},"Routing","/essentials/routing","2.essentials/1.routing",{"title":37,"path":38,"stem":39},"Authentication","/essentials/authentication","2.essentials/2.authentication",{"title":41,"path":42,"stem":43},"Identity & User Store","/essentials/identity","2.essentials/3.identity",{"title":45,"path":46,"stem":47},"Requests & Responses","/essentials/requests-responses","2.essentials/4.requests-responses",{"title":49,"path":50,"stem":51},"Controllers","/essentials/controllers","2.essentials/5.controllers",{"title":53,"path":54,"stem":55},"Database","/essentials/database","2.essentials/6.database",{"title":57,"path":58,"stem":59},"Validation","/essentials/validation","2.essentials/7.validation",{"title":61,"path":62,"stem":63},"Migrations","/essentials/migrations","2.essentials/8.migrations",{"title":65,"path":66,"stem":67,"children":68},"Features","/features","3.features",[69,72,76,80,84,88,92,96,100,104,108],{"title":70,"path":66,"stem":71},"Built‑in Capabilities","3.features/index",{"title":73,"path":74,"stem":75},"Caching","/features/caching","3.features/caching",{"title":77,"path":78,"stem":79},"CORS & CSRF","/features/cors-csrf","3.features/cors-csrf",{"title":81,"path":82,"stem":83},"Distributed Locks","/features/distributed-locks","3.features/distributed-locks",{"title":85,"path":86,"stem":87},"Events & Listeners","/features/events","3.features/events",{"title":89,"path":90,"stem":91},"Field Selection","/features/field-selection","3.features/field-selection",{"title":93,"path":94,"stem":95},"File Uploads","/features/file-uploads","3.features/file-uploads",{"title":97,"path":98,"stem":99},"Notifications","/features/notifications","3.features/notifications",{"title":101,"path":102,"stem":103},"Queues & Jobs","/features/queues-jobs","3.features/queues-jobs",{"title":105,"path":106,"stem":107},"Rate Limiting","/features/rate-limiting","3.features/rate-limiting",{"title":109,"path":110,"stem":111},"Task Scheduling","/features/scheduling","3.features/scheduling",{"title":113,"path":114,"stem":115,"children":116},"Advanced","/advanced","4.advanced",[117,120,124,128,132,136,140,144],{"title":118,"path":114,"stem":119},"Techniques and Patterns","4.advanced/index",{"title":121,"path":122,"stem":123},"Configuration","/advanced/configuration","4.advanced/configuration",{"title":125,"path":126,"stem":127},"Dependency Injection","/advanced/dependency-injection","4.advanced/dependency-injection",{"title":129,"path":130,"stem":131},"Middleware","/advanced/middleware","4.advanced/middleware",{"title":133,"path":134,"stem":135},"Performance","/advanced/performance","4.advanced/performance",{"title":137,"path":138,"stem":139},"Repositories","/advanced/repositories","4.advanced/repositories",{"title":141,"path":142,"stem":143},"Service Providers","/advanced/service-providers","4.advanced/service-providers",{"title":145,"path":146,"stem":147},"Testing","/advanced/testing","4.advanced/testing",{"title":149,"path":150,"stem":151,"children":152},"Deployment","/deployment","5.deployment",[153,156,160,164,168,172,176],{"title":154,"path":150,"stem":155},"Options for Deployment","5.deployment/index",{"title":157,"path":158,"stem":159},"Docker Deployment","/deployment/docker","5.deployment/docker",{"title":161,"path":162,"stem":163},"Logging","/deployment/logging","5.deployment/logging",{"title":165,"path":166,"stem":167},"Monitoring","/deployment/monitoring","5.deployment/monitoring",{"title":169,"path":170,"stem":171},"Production Setup","/deployment/production","5.deployment/production",{"title":173,"path":174,"stem":175},"Security Hardening","/deployment/security-hardening","5.deployment/security-hardening",{"title":177,"path":178,"stem":179},"Zero Downtime Deployment","/deployment/zero-downtime","5.deployment/zero-downtime",{"title":181,"path":182,"stem":183,"children":184},"Cookbook","/cookbook","6.cookbook",[185,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,259],{"title":186,"path":182,"stem":187},"Recipes & How‑Tos","6.cookbook/index",{"title":189,"path":190,"stem":191},"Routing Recipes","/cookbook/routing","6.cookbook/1.routing",{"title":193,"path":194,"stem":195},"Caching Recipes","/cookbook/caching","6.cookbook/10.caching",{"title":197,"path":198,"stem":199},"Queue Infrastructure","/cookbook/queues-and-jobs","6.cookbook/11.queues-and-jobs",{"title":201,"path":202,"stem":203},"Notification Channels & Templates","/cookbook/notifications","6.cookbook/13.notifications",{"title":205,"path":206,"stem":207},"Storage","/cookbook/storage","6.cookbook/15.storage",{"title":209,"path":210,"stem":211},"Image Processing Examples","/cookbook/image-processing","6.cookbook/16.image-processing",{"title":213,"path":214,"stem":215},"Permissions and Authorization","/cookbook/permissions-and-authorization","6.cookbook/18.permissions-and-authorization",{"title":217,"path":218,"stem":219},"Session Analytics","/cookbook/sessions-analytics","6.cookbook/19.sessions-analytics",{"title":221,"path":222,"stem":223},"Writing Middleware","/cookbook/middleware","6.cookbook/2.middleware",{"title":225,"path":226,"stem":227},"API Metrics","/cookbook/api-metrics","6.cookbook/20.api-metrics",{"title":229,"path":230,"stem":231},"Performance Deep Dive","/cookbook/performance","6.cookbook/21.performance",{"title":233,"path":234,"stem":235},"Memory Management","/cookbook/memory-management","6.cookbook/22.memory-management",{"title":237,"path":238,"stem":239},"Writing Console Commands","/cookbook/console-commands","6.cookbook/23.console-commands",{"title":241,"path":242,"stem":243},"Glueful Extensions","/cookbook/extensions","6.cookbook/25.extensions",{"title":245,"path":246,"stem":247},"Error Handling Guide","/cookbook/error-handling","6.cookbook/4.error-handling",{"title":249,"path":250,"stem":251},"Security Guide","/cookbook/security","6.cookbook/5.security",{"title":253,"path":254,"stem":255},"Service Options Resolver","/cookbook/configuration","6.cookbook/6.configuration",{"title":161,"path":257,"stem":258},"/cookbook/logging","6.cookbook/7.logging",{"title":260,"path":261,"stem":262},"Database Advanced Features","/cookbook/database","6.cookbook/8.database",{"title":264,"path":265,"stem":266},"API Reference","/api-reference","7.api-reference",{"title":268,"path":269,"stem":270},"CLI Reference","/cli-reference","8.cli-reference",{"title":272,"path":273,"stem":274},"Contributing","/contributing","9.contributing",{"title":276,"path":277,"stem":278},"Extensions","/extensions","extensions",{"title":280,"path":281,"stem":282},"Release Notes","/releases","releases",{"title":284,"path":285,"stem":286},"Release Archive","/releases-archive","releases-archive",{"id":288,"title":284,"body":289,"description":26078,"extension":26079,"links":26080,"meta":26081,"navigation":5211,"path":285,"seo":26082,"stem":286,"__hash__":26083},"docs/releases-archive.md",{"type":290,"value":291,"toc":25712},"minimark",[292,300,305,311,346,351,410,414,427,451,454,458,462,479,482,524,570,611,614,650,662,664,668,673,691,694,755,787,822,825,847,859,861,865,870,900,903,951,986,1031,1034,1117,1170,1172,1176,1181,1208,1211,1241,1268,1302,1305,1332,1344,1346,1350,1355,1383,1386,1454,1498,1538,1581,1584,1672,1684,1686,1690,1695,1719,1722,1776,1828,1882,1943,1965,1968,2067,2079,2081,2085,2090,2101,2104,2171,2208,2237,2283,2315,2361,2364,2478,2500,2502,2506,2511,2526,2529,2566,2608,2631,2671,2716,2762,2791,2794,2877,2879,2883,2888,2896,2899,2935,2957,2986,3017,3020,3062,3064,3068,3073,3086,3089,3094,3096,3100,3104,3115,3118,3170,3210,3225,3228,3233,3235,3239,3243,3254,3257,3262,3264,3268,3272,3285,3288,3293,3295,3299,3303,3315,3318,3359,3387,3413,3431,3434,3467,3469,3473,3478,3490,3493,3509,3531,3543,3586,3620,3623,3701,3703,3707,3712,3727,3730,3754,3788,3814,3817,3836,3838,3842,3847,3862,3865,3915,3938,3964,3988,3991,4031,4033,4037,4042,4057,4060,4089,4113,4116,4143,4145,4149,4154,4162,4165,4191,4236,4239,4250,4252,4256,4260,4272,4276,4288,4291,4296,4298,4302,4306,4314,4317,4340,4379,4391,4394,4440,4442,4446,4451,4459,4462,4495,4532,4555,4558,4584,4586,4590,4594,4605,4608,4660,4664,4687,4689,4693,4697,4704,4707,4731,4772,4814,4817,4832,4834,4838,4843,4850,4853,4888,4923,4926,4940,4942,4946,4951,4958,4961,5015,5037,5076,5126,5130,5137,5332,5335,5352,5354,5358,5363,5371,5374,5442,5473,5494,5522,5526,5614,5617,5632,5634,5638,5643,5651,5654,5692,5713,5734,5738,5747,5840,5843,5857,5859,5863,5867,5874,5877,5909,5927,5952,5956,5963,5967,6293,6296,6311,6313,6317,6321,6328,6331,6358,6394,6421,6447,6485,6503,6507,6838,6841,6969,6972,6987,6989,6993,6997,7004,7007,7046,7079,7111,7135,7138,7347,7350,7364,7366,7370,7375,7386,7389,7421,7446,7472,7504,7533,7537,7540,7654,7657,7723,7726,7742,7744,7748,7753,7761,7764,7785,7806,7857,7894,7927,7930,7935,8159,8164,8196,8200,8205,8215,8230,8232,8236,8240,8248,8251,8281,8309,8336,8358,8361,8366,8369,8414,8419,8422,8477,8482,8495,8497,8501,8505,8513,8516,8558,8594,8633,8636,8639,8682,8684,8688,8693,8700,8704,8735,8774,8777,8783,8823,8828,8875,8877,8881,8885,8893,8896,8920,8941,8962,8980,8983,8988,9061,9066,9103,9107,9388,9392,10099,10102,10460,10463,10530,10532,10536,10540,10548,10551,10582,10606,10633,10655,10659,10663,10732,10737,10789,10794,10837,10841,10968,10971,11334,11338,11505,11509,11612,11615,11897,11900,11908,11932,11934,11938,11942,11949,11952,11972,12008,12026,12047,12051,12055,12116,12121,12164,12169,12204,12207,12212,12336,12341,12386,12390,12393,12399,12402,12804,12807,13229,13232,13241,13258,13260,13264,13268,13276,13279,13315,13342,13360,13364,13368,13410,13415,13478,13483,13523,13526,13873,13877,13880,13886,13889,14055,14058,14065,14083,14085,14089,14093,14101,14104,14128,14148,14166,14170,14174,14216,14219,14330,14334,14395,14398,14405,14424,14426,14430,14434,14442,14445,14493,14531,14558,14562,14567,14649,14654,14717,14722,14825,14829,14834,14953,14956,14966,14971,14998,15002,15010,15012,15016,15020,15028,15031,15067,15110,15137,15141,15146,15230,15235,15356,15360,15364,15407,15412,15507,15511,15515,15547,15552,15604,15607,15960,16145,16149,16301,16304,16337,16339,16343,16348,16356,16359,16396,16438,16465,16469,16473,16544,16549,16631,16636,16708,16711,17291,17294,17383,17386,17397,17399,17403,17407,17414,17417,17438,17459,17480,17484,17488,17539,17544,17618,17623,17705,17710,17792,17795,18262,18265,18357,18360,18375,18377,18381,18385,18392,18395,18422,18455,18459,18462,18467,18586,18591,18644,18649,18701,18705,18710,18769,18772,19009,19012,19026,19028,19032,19037,19045,19048,19082,19110,19141,19145,19160,19164,19185,19188,19214,19216,19220,19225,19233,19236,19268,19313,19317,19331,19335,19350,19353,19406,19409,19424,19426,19430,19435,19443,19446,19470,19473,19505,19509,19523,19526,19536,19566,19568,19572,19577,19584,19587,19614,19617,19622,19624,19628,19633,19640,19643,19703,19706,19721,19723,19727,19732,19739,19742,19769,19772,19783,19785,19789,19794,19801,19804,19837,19839,19843,19847,19854,19857,19883,19885,19889,19893,19900,19903,19935,19939,19944,19946,19950,19955,19962,19965,19996,20030,20087,20091,20131,20134,20149,20151,20155,20160,20167,20171,20185,20188,20203,20205,20209,20213,20220,20223,20238,20240,20243,20247,20252,20259,20262,20312,20333,20366,20370,20375,20377,20381,20385,20392,20395,20420,20441,20444,20452,20454,20458,20463,20470,20474,20483,20487,20492,20494,20498,20502,20509,20512,20548,20551,20598,20601,20606,20608,20612,20616,20626,20629,20657,20660,20678,20681,20689,20692,20706,20947,20949,20953,20958,20968,20971,20998,21001,21027,21030,21076,21079,21088,21090,21094,21099,21109,21112,21134,21138,21182,21186,21472,21476,21479,21483,21495,21497,21501,21506,21516,21519,21537,21540,21545,21548,21580,21584,21587,21611,21615,21659,21663,21674,21678,21686,21690,21695,21698,21717,21721,21726,21766,21771,21815,21819,21823,21865,21869,22000,22004,22008,22042,22046,22135,22138,22157,22159,22163,22168,22178,22181,22203,22206,22239,22243,22375,22388,22391,22402,22404,22408,22413,22423,22426,22453,22456,22458,22478,22642,22646,22657,23104,23116,23120,23123,23142,23145,23177,23181,23202,23371,23375,23398,23402,23413,23416,23425,23429,23432,23436,23513,23517,23860,23864,23867,23871,23917,23921,24167,24171,24174,24178,24263,24267,24590,24594,24597,24739,24743,24746,24750,24793,24797,24926,24930,24933,24938,25002,25007,25103,25107,25110,25114,25155,25159,25195,25198,25232,25234,25238,25241,25312,25316,25323,25343,25347,25367,25371,25374,25461,25465,25469,25476,25479,25500,25520,25524,25535,25538,25552,25554,25558,25562,25569,25573,25600,25603,25608,25610,25614,25618,25625,25628,25642,25646,25656,25658,25662,25666,25673,25676,25693,25696,25706,25708],[293,294,295,296,299],"p",{},"Release notes for older versions (v1.49.1 and earlier). For the latest releases and the complete version table, see ",[297,298,280],"a",{"href":281},".",[301,302,304],"h2",{"id":303},"v1491-jishui","v1.49.1 - Jishui",[293,306,307],{},[308,309,310],"strong",{},"Released: June 1, 2026",[312,313,317],"u-alert",{"color":314,"icon":315,"variant":316},"success","i-tabler-bug-off","subtle",[318,319,321],"template",{"v-slot:description":320},"",[293,322,323,324,328,329,332,333,332,336,332,339,332,342,345],{},"A focused bug fix: ",[325,326,327],"code",{},"QueryValidator"," no longer rejects SQL reserved words used as column names (",[325,330,331],{},"from",", ",[325,334,335],{},"order",[325,337,338],{},"group",[325,340,341],{},"key",[325,343,344],{},"values",", …). Column identifiers are always quoted by the query builders, so these were valid SQL all along. Framework-only — no API breaks, no env vars, no migrations.",[347,348,350],"h3",{"id":349},"key-highlights","Key Highlights",[352,353,354,359],"card",{},[318,355,356],{"v-slot:title":320},[293,357,358],{},"Reserved words are valid column names",[318,360,361],{"v-slot:description":320},[293,362,363,366,367,370,371,373,374,376,377,380,381,384,385,388,389,392,393,396,397,401,402,405,406,409],{},[325,364,365],{},"QueryValidator::validateColumnName()"," previously threw ",[325,368,369],{},"Column name '\u003Cx>' is a reserved SQL keyword"," in strict mode for columns like ",[325,372,331],{}," or ",[325,375,335],{},", even though ",[325,378,379],{},"InsertBuilder","/",[325,382,383],{},"UpdateBuilder"," always emit column identifiers through the driver's ",[325,386,387],{},"wrapIdentifier()"," (",[325,390,391],{},"`from`"," / ",[325,394,395],{},"\"from\"",") — valid SQL on every driver. The keyword check is dropped for ",[398,399,400],"em",{},"column"," names; the SQL-injection character guard stays, and reserved-word checks for unquoted table/schema/alias names are unchanged. This also fixes a latent inconsistency where ",[325,403,404],{},"to"," was accepted only because ",[325,407,408],{},"TO"," was missing from the keyword list.",[347,411,413],{"id":412},"migration-notes","Migration Notes",[415,416,417],"ul",{},[418,419,420,426],"li",{},[308,421,422,425],{},[325,423,424],{},"composer update"," is sufficient"," — no API changes, env vars, or migrations.",[428,429,433],"pre",{"className":430,"code":431,"language":432,"meta":320,"style":320},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark monokai","composer update glueful/framework\n","bash",[325,434,435],{"__ignoreMap":320},[436,437,440,444,448],"span",{"class":438,"line":439},"line",1,[436,441,443],{"class":442},"sR7ES","composer",[436,445,447],{"class":446},"sLACW"," update",[436,449,450],{"class":446}," glueful/framework\n",[452,453],"hr",{},[301,455,457],{"id":456},"v1490-jishui","v1.49.0 - Jishui",[293,459,460],{},[308,461,310],{},[312,463,466],{"color":464,"icon":465,"variant":316},"warning","i-tabler-shield-lock",[318,467,468],{"v-slot:description":320},[293,469,470,471,474,475,478],{},"A maintenance + hardening release: ",[325,472,473],{},"Http\\Client"," now forwards per-request HTTP Basic auth, the notification queue accepts a ",[325,476,477],{},"whatsapp"," type, image processing moves to Intervention Image v4, and all known dependency advisories are patched. No framework API breaks, no new env vars, no migrations — and the PHP 8.3 floor is preserved.",[347,480,350],{"id":481},"key-highlights-1",[352,483,484,495],{},[318,485,486],{"v-slot:title":320},[293,487,488,491,492,494],{},[325,489,490],{},"auth_basic"," + ",[325,493,477],{}," plumbing",[318,496,497],{"v-slot:description":320},[293,498,499,502,503,505,506,509,510,513,514,516,517,520,521,523],{},[325,500,501],{},"Http\\Client::transformOptions()"," now forwards the ",[325,504,490],{}," option to Symfony HttpClient (it was silently dropped before), so callers can send ",[325,507,508],{},"['auth_basic' => [$user, $pass], 'form_params' => [...]]"," without hand-building an ",[325,511,512],{},"Authorization"," header. Separately, ",[325,515,477],{}," is now a recognized ",[325,518,519],{},"SendNotification"," queue type, so phone-messaging extensions that register a ",[325,522,477],{}," notification channel can be dispatched asynchronously through the framework's notification job.",[352,525,526,531],{},[318,527,528],{"v-slot:title":320},[293,529,530],{},"Intervention Image v4",[318,532,533],{"v-slot:description":320},[293,534,535,538,539,542,543,546,547,380,550,380,553,380,556,559,560,563,564,542,566,569],{},[325,536,537],{},"intervention/image"," is upgraded to ",[325,540,541],{},"^4.1"," and ",[325,544,545],{},"ImageProcessor"," is ported to the v4 API (",[325,548,549],{},"decode",[325,551,552],{},"createImage",[325,554,555],{},"insert",[325,557,558],{},"flip(Direction)","/named ",[325,561,562],{},"save"," options). The public ",[325,565,545],{},[325,567,568],{},"image()"," helper API is unchanged — apps using Glueful's image facade need no changes.",[352,571,572,577],{},[318,573,574],{"v-slot:title":320},[293,575,576],{},"Dependency hardening",[318,578,579],{"v-slot:description":320},[293,580,581,582,392,585,588,589,592,593,596,597,600,601,542,604,607,608,610],{},"All known dependency advisories are patched within the existing ",[325,583,584],{},"^7.4",[325,586,587],{},"^10.5"," constraints — Symfony components to ",[325,590,591],{},"7.4.x"," (including HIGH-severity mailer/mime header & SMTP-command injection CVEs) and PHPUnit to ",[325,594,595],{},"10.5.63",". ",[325,598,599],{},"composer audit"," is clean. ",[325,602,603],{},"symfony/event-dispatcher",[325,605,606],{},"symfony/string"," are pinned to ",[325,609,584],{}," so a transitive update can't pull the Symfony 8.x (PHP 8.4-only) lines.",[347,612,413],{"id":613},"migration-notes-1",[415,615,616,623],{},[418,617,618,622],{},[308,619,620,425],{},[325,621,424],{}," — no framework API changes, env vars, or migrations.",[418,624,625,631,632,634,635,638,639,380,641,643,644,299],{},[308,626,627,628,299],{},"Intervention Image is now ",[325,629,630],{},"^4"," Only apps depending on ",[325,633,537],{}," ",[398,636,637],{},"directly"," (not via Glueful's ",[325,640,568],{},[325,642,545],{},") need to move to the ",[297,645,649],{"href":646,"rel":647},"https://image.intervention.io/v4",[648],"nofollow","v4 API",[428,651,652],{"className":430,"code":431,"language":432,"meta":320,"style":320},[325,653,654],{"__ignoreMap":320},[436,655,656,658,660],{"class":438,"line":439},[436,657,443],{"class":442},[436,659,447],{"class":446},[436,661,450],{"class":446},[452,663],{},[301,665,667],{"id":666},"v1480-imai","v1.48.0 - Imai",[293,669,670],{},[308,671,672],{},"Released: May 31, 2026",[312,674,677],{"color":675,"icon":676,"variant":316},"primary","i-tabler-route",[318,678,679],{"v-slot:description":320},[293,680,681,542,684,687,688,690],{},[325,682,683],{},"PATCH",[325,685,686],{},"OPTIONS"," become first-class routing verbs — both were previously unreachable through the public routing API. Explicit ",[325,689,686],{}," routes now win over the automatic CORS preflight responder, and the router's route-precedence model is documented and locked down with tests. Purely additive: no breaking changes, no new env vars, no migrations.",[347,692,350],{"id":693},"key-highlights-2",[352,695,696,701],{},[318,697,698],{"v-slot:title":320},[293,699,700],{},"First-Class PATCH and OPTIONS",[318,702,703],{"v-slot:description":320},[293,704,705,706,542,709,712,713,380,716,380,719,380,722,380,725,728,729,542,732,735,736,739,740,332,742,542,744,747,748,751,752,754],{},"New ",[325,707,708],{},"$router->patch()",[325,710,711],{},"$router->options()"," shortcuts join ",[325,714,715],{},"get",[325,717,718],{},"post",[325,720,721],{},"put",[325,723,724],{},"delete",[325,726,727],{},"head",", with matching ",[325,730,731],{},"#[Patch]",[325,733,734],{},"#[Options]"," attributes. The generic ",[325,737,738],{},"#[Route(methods: [...])]"," form now accepts ",[325,741,683],{},[325,743,686],{},[325,745,746],{},"HEAD"," too — previously it threw ",[325,749,750],{},"InvalidArgumentException"," for anything but GET/POST/PUT/DELETE, so ",[325,753,683],{}," (the standard partial-update verb) had no public route-registration path at all.",[352,756,757,762],{},[318,758,759],{"v-slot:title":320},[293,760,761],{},"Explicit OPTIONS Beats Auto-CORS",[318,763,764],{"v-slot:description":320},[293,765,766,769,770,772,773,776,777,780,781,783,784,786],{},[325,767,768],{},"Router::dispatch()"," still answers ",[325,771,686],{}," automatically for CORS preflight (a ",[325,774,775],{},"204"," with an ",[325,778,779],{},"Allow"," header) when no ",[325,782,686],{}," route is registered. But an explicitly registered ",[325,785,686],{}," route now runs its own handler instead of being silently shadowed by the preflight responder — so you can take over preflight when you need to, and the automatic behavior remains the default everywhere else.",[352,788,789,794],{},[318,790,791],{"v-slot:title":320},[293,792,793],{},"Route Precedence, Documented and Pinned",[318,795,796],{"v-slot:description":320},[293,797,798,799,802,803,388,806,809,810,813,814,817,818,821],{},"The router's precedence model is now explicit: ",[308,800,801],{},"static routes beat dynamic ones","; a ",[308,804,805],{},"literal first segment beats a parameter first segment",[325,807,808],{},"/users/{id}"," over ",[325,811,812],{},"/{resource}/{id}",", independent of order); and ",[308,815,816],{},"within a first-segment group, registration order wins"," — so register the more specific overlapping pattern first. The model is locked down by ",[325,819,820],{},"RoutePrecedenceTest",", and a misleading in-code comment claiming a specificity sort that never existed was corrected.",[347,823,413],{"id":824},"migration-notes-2",[415,826,827,836],{},[418,828,829,832,833,835],{},[308,830,831],{},"No action required."," Framework-only, fully backward-compatible release — no migrations, no env vars, no breaking changes. ",[325,834,424],{}," is sufficient.",[418,837,838,839,842,843,846],{},"The existing api-skeleton ",[325,840,841],{},"^1.47.0"," constraint already permits 1.48.0; the skeleton constraint is bumped to ",[325,844,845],{},"^1.48.0"," for clarity.",[428,848,849],{"className":430,"code":431,"language":432,"meta":320,"style":320},[325,850,851],{"__ignoreMap":320},[436,852,853,855,857],{"class":438,"line":439},[436,854,443],{"class":442},[436,856,447],{"class":446},[436,858,450],{"class":446},[452,860],{},[301,862,864],{"id":863},"v1470-hadar","v1.47.0 - Hadar",[293,866,867],{},[308,868,869],{},"Released: May 30, 2026",[312,871,873],{"color":464,"icon":872,"variant":316},"i-tabler-puzzle",[318,874,875],{"v-slot:description":320},[293,876,877,878,885,886,889,890,542,893,896,897,899],{},"The extension system is rebuilt around a single model: ",[308,879,880,881,884],{},"Composer discovers, one ",[325,882,883],{},"enabled"," list activates, a pure resolver orders and validates."," The four overlapping discovery sources, the multi-key config files, and the dev↔prod parity hazard are gone. This is a ",[308,887,888],{},"breaking config change"," — ",[325,891,892],{},"config/extensions.php",[325,894,895],{},"config/serviceproviders.php"," become a single ",[325,898,883],{}," list of plain string FQCNs. Shipped as a minor per the pre-public policy; see the migration guide.",[347,901,350],{"id":902},"key-highlights-3",[352,904,905,910],{},[318,906,907],{"v-slot:title":320},[293,908,909],{},"One Discovery Path, One Allow-List",[318,911,912],{"v-slot:description":320},[293,913,914,915,918,919,922,923,925,926,928,929,392,932,392,935,392,938,392,941,944,945,948,949,299],{},"Discovery is now ",[308,916,917],{},"Composer-only",": installed ",[325,920,921],{},"glueful-extension"," packages are the candidates, and ",[325,924,892],{}," → ",[325,927,883],{}," is the single activation allow-list. Installing a package no longer auto-loads it — its provider FQCN must be enabled. The old ",[325,930,931],{},"only",[325,933,934],{},"dev_only",[325,936,937],{},"disabled",[325,939,940],{},"local_path",[325,942,943],{},"scan_composer"," keys, the local-folder scan, runtime PSR-4 registration, and ",[325,946,947],{},"ProviderLocator"," are removed. App providers move to the same single-key shape in ",[325,950,895],{},[352,952,953,958],{},[318,954,955],{"v-slot:title":320},[293,956,957],{},"Pure Resolver, No Dev↔Prod Drift",[318,959,960],{"v-slot:description":320},[293,961,962,963,966,967,969,970,973,974,977,978,981,982,985],{},"A pure ",[325,964,965],{},"ExtensionResolver"," selects from ",[325,968,883],{},", validates (missing provider/dependency, framework-version mismatch via ",[325,971,972],{},"composer/semver",", dependency cycle), and topologically orders providers — reading no environment, so development and production resolve identically. A single shared ",[325,975,976],{},"ProviderClassResolver"," is used by both the ",[325,979,980],{},"ExtensionManager"," and the container factory, so there is one resolution implementation, not two that drift. Production boots only from the compiled manifest (",[325,983,984],{},"extensions:cache",") and fails fast if it's missing.",[352,987,988,993],{},[318,989,990],{"v-slot:title":320},[293,991,992],{},"CLI That Can't Leave You Broken",[318,994,995],{"v-slot:description":320},[293,996,997,392,1000,634,1003,1006,1007,1009,1010,1013,1014,392,1017,392,1020,1023,1024,596,1027,1030],{},[325,998,999],{},"extensions:enable",[325,1001,1002],{},"extensions:disable",[308,1004,1005],{},"validate before writing"," — enabling an extension whose dependency isn't enabled, or disabling one another enabled extension depends on, is refused and the config is left untouched. They accept the package name, provider FQCN, or slug (case-insensitive), edit the ",[325,1008,883],{}," list, and recompile the cache. ",[325,1011,1012],{},"extensions:list"," shows each extension's state (",[325,1015,1016],{},"enabled ✓",[325,1018,1019],{},"available ○",[325,1021,1022],{},"enabled-but-missing ⚠",") and folds in the old ",[325,1025,1026],{},"extensions:why",[325,1028,1029],{},"create:extension"," now scaffolds a real Composer package + path repository.",[347,1032,413],{"id":1033},"migration-notes-3",[415,1035,1036,1083,1100],{},[418,1037,1038,1041,1042,542,1044,1046,1047,1049,1050,1053,1054,1061,1062,1064,1065,332,1067,1069,1070,1064,1072,491,1074,332,1077,1079,1080,1082],{},[308,1039,1040],{},"Breaking config change."," Convert ",[325,1043,892],{},[325,1045,895],{}," to the single ",[325,1048,883],{}," list of plain string FQCNs (no ",[325,1051,1052],{},"::class","). Map old keys per ",[297,1055,1058],{"href":1056,"rel":1057},"https://github.com/glueful/framework/blob/main/docs/EXTENSIONS_UPGRADE.md",[648],[325,1059,1060],{},"docs/EXTENSIONS_UPGRADE.md",": ",[325,1063,931],{},"→",[325,1066,883],{},[325,1068,937],{},"→omit, ",[325,1071,934],{},[325,1073,883],{},[325,1075,1076],{},"require-dev",[325,1078,940],{},"→Composer path repository, ",[325,1081,943],{},"→removed.",[418,1084,1085,1088,1089,1091,1092,1095,1096,1099],{},[308,1086,1087],{},"New dependency."," Adds ",[325,1090,972],{}," to the framework's ",[325,1093,1094],{},"require"," — run ",[325,1097,1098],{},"composer update glueful/framework"," so it installs (the resolver fatals at boot without it).",[418,1101,1102,634,1105,1108,1109,1112,1113,1116],{},[308,1103,1104],{},"Enable explicitly; cache in production.",[325,1106,1107],{},"composer require"," an extension, then ",[325,1110,1111],{},"php glueful extensions:enable \u003Cname>",". Add ",[325,1114,1115],{},"php glueful extensions:cache"," to your production deploy step — production no longer resolves live.",[428,1118,1120],{"className":430,"code":1119,"language":432,"meta":320,"style":320},"composer update glueful/framework\nphp glueful extensions:enable \u003Cname>\nphp glueful extensions:cache   # required in production\n",[325,1121,1122,1130,1156],{"__ignoreMap":320},[436,1123,1124,1126,1128],{"class":438,"line":439},[436,1125,443],{"class":442},[436,1127,447],{"class":446},[436,1129,450],{"class":446},[436,1131,1133,1136,1139,1142,1146,1149,1153],{"class":438,"line":1132},2,[436,1134,1135],{"class":442},"php",[436,1137,1138],{"class":446}," glueful",[436,1140,1141],{"class":446}," extensions:enable",[436,1143,1145],{"class":1144},"sGXK2"," \u003C",[436,1147,1148],{"class":446},"nam",[436,1150,1152],{"class":1151},"ss--_","e",[436,1154,1155],{"class":1144},">\n",[436,1157,1159,1161,1163,1166],{"class":438,"line":1158},3,[436,1160,1135],{"class":442},[436,1162,1138],{"class":446},[436,1164,1165],{"class":446}," extensions:cache",[436,1167,1169],{"class":1168},"ss7Ak","   # required in production\n",[452,1171],{},[301,1173,1175],{"id":1174},"v1460-gienah","v1.46.0 - Gienah",[293,1177,1178],{},[308,1179,1180],{},"Released: May 28, 2026",[312,1182,1184],{"color":675,"icon":1183,"variant":316},"i-tabler-database",[318,1185,1186],{"v-slot:description":320},[293,1187,1188,1191,1192,380,1194,380,1197,380,1200,1203,1204,1207],{},[325,1189,1190],{},"QueryBuilder::cache(ttl, tags)"," is now actually wired up. Previously the fluent method set builder flags that execution ignored — a silent no-op since the method was introduced. It now caches read queries (",[325,1193,715],{},[325,1195,1196],{},"first",[325,1198,1199],{},"count",[325,1201,1202],{},"max",") through ",[325,1205,1206],{},"QueryCacheService",", tagging entries with the involved tables plus any caller-supplied tags for targeted invalidation. Also marks the start of the framework-wide PHPStan level-8 hardening initiative — the ~914-error gap is now catalogued.",[347,1209,350],{"id":1210},"key-highlights-4",[352,1212,1213,1218],{},[318,1214,1215],{"v-slot:title":320},[293,1216,1217],{},"Fluent Query Result Caching",[318,1219,1220],{"v-slot:description":320},[293,1221,1222,1225,1226,1228,1229,1232,1233,1236,1237,1240],{},[325,1223,1224],{},"QueryBuilder::cache(?int $ttl = null, array $tags = [])"," activates caching for a single read query, with no global toggle required. Results are cached via ",[325,1227,1206],{}," and tagged automatically by the tables involved, plus any caller-supplied ",[325,1230,1231],{},"$tags"," — so an app can invalidate targeted groups (",[325,1234,1235],{},"$cache->invalidateTags(['users'])",") alongside the automatic per-table invalidation. Backward compatible: existing ",[325,1238,1239],{},"selectRaw","/builder usage is unchanged; the cache method is opt-in per query. The executor lazily resolves a cache backend and degrades to uncached execution if none is configured.",[352,1242,1243,1252],{},[318,1244,1245],{"v-slot:title":320},[293,1246,1247,1248,1251],{},"Closed: ",[325,1249,1250],{},"->cache()"," Was a Silent No-Op",[318,1253,1254],{"v-slot:description":320},[293,1255,1256,1257,1259,1260,1263,1264,1267],{},"The fluent ",[325,1258,1250],{}," method existed before this release but set builder-local flags that ",[325,1261,1262],{},"get()"," never propagated to the executor, so per-query caching and the TTL were ignored, and there was no ",[325,1265,1266],{},"tags"," parameter. The advertised behavior didn't match the code — closing exactly the kind of \"trust gap\" the 1.44.0 \"Errai\" release was about. Now the method actually caches and accepts invalidation tags.",[352,1269,1270,1275],{},[318,1271,1272],{"v-slot:title":320},[293,1273,1274],{},"PHPStan Level-8 Hardening (Initiative Kickoff)",[318,1276,1277],{"v-slot:description":320},[293,1278,1279,1280,1283,1284,1287,1288,1291,1292,1294,1295,380,1298,1301],{},"The framework's eventual goal is to run PHPStan ",[308,1281,1282],{},"level 8"," across all of ",[325,1285,1286],{},"src/"," and enforce it in CI. The CI gate today remains level 6 (green), but the full ~914-error level-8 gap is now catalogued in ",[325,1289,1290],{},"docs/LEVEL8_TYPING_DEBT.md"," — with by-area counts (largest: ",[325,1293,53],{}," 201), error categories, risk notes, and an area-by-area incremental adoption strategy (ratcheting baselines 6 → 7 → 8). This release also lands two binding-path typing fixes (",[325,1296,1297],{},"ParameterBinder",[325,1299,1300],{},"QueryExecutor",") as the first slice. Behavior-preserving internal work; no API change.",[347,1303,413],{"id":1304},"migration-notes-4",[415,1306,1307,1316],{},[418,1308,1309,1311,1312,1315],{},[308,1310,831],{}," Framework-only release; no migrations, no env vars, no api-skeleton changes. The existing ",[325,1313,1314],{},"^1.45"," constraint already permits 1.46.",[418,1317,1318,1323,1324,1327,1328,1331],{},[308,1319,1320,1322],{},[325,1321,1250],{}," semantics changed from \"no-op\" to \"actually caches.\""," If you have code calling ",[325,1325,1326],{},"->cache(ttl)"," expecting nothing to happen, it'll now cache. The cache key is ",[325,1329,1330],{},"query+params"," (no auth/context scoping), so make sure cached queries don't return user-scoped rows without an appropriate user-discriminating clause in the SQL.",[428,1333,1334],{"className":430,"code":431,"language":432,"meta":320,"style":320},[325,1335,1336],{"__ignoreMap":320},[436,1337,1338,1340,1342],{"class":438,"line":439},[436,1339,443],{"class":442},[436,1341,447],{"class":446},[436,1343,450],{"class":446},[452,1345],{},[301,1347,1349],{"id":1348},"v1450-fomalhaut","v1.45.0 - Fomalhaut",[293,1351,1352],{},[308,1353,1354],{},"Released: May 27, 2026",[312,1356,1358],{"color":675,"icon":1357,"variant":316},"i-tabler-lock",[318,1359,1360],{"v-slot:description":320},[293,1361,1362,1363,1366,1367,1370,1371,1374,1375,1378,1379,1382],{},"Baseline email-PIN two-factor authentication ships in framework core — opt-in, ",[308,1364,1365],{},"off by default",", and byte-for-byte identical on the wire to a normal login once completed. When ",[325,1368,1369],{},"TWO_FACTOR_ENABLED=false"," (the default) nothing changes: the ",[325,1372,1373],{},"/2fa/*"," routes aren't even registered. Alongside 2FA, ",[325,1376,1377],{},"selectRaw()"," gains parameter bindings (closing the last unsafe-by-design gap in the query builder), a new ",[325,1380,1381],{},"docs/SECURITY.md"," documents the SQL-injection and XSS model, and the admin permission middleware drops a dead MFA-token placeholder.",[347,1384,350],{"id":1385},"key-highlights-5",[352,1387,1388,1393],{},[318,1389,1390],{"v-slot:title":320},[293,1391,1392],{},"Core Email-PIN 2FA (Opt-In)",[318,1394,1395],{"v-slot:description":320},[293,1396,1397,1398,1401,1402,1405,1406,1409,1410,1413,1414,1417,1418,1421,1422,332,1425,332,1428,1431,1432,388,1435,1438,1439,1442,1443,634,1446,1449,1450,1453],{},"When enabled, ",[325,1399,1400],{},"POST /auth/login"," for an enrolled user returns a ",[325,1403,1404],{},"challenge_token"," and emails a 6-digit PIN instead of tokens; the client completes login at ",[325,1407,1408],{},"POST /2fa/verify",". PINs are bcrypt-hashed via ",[325,1411,1412],{},"Glueful\\Security\\OTP"," and cached under ",[325,1415,1416],{},"2fa:pin:{jti}"," with a strictly-projected user array — no password hash can leak through the cache. New ",[325,1419,1420],{},"src/Auth/TwoFactor/"," services (",[325,1423,1424],{},"TwoFactorService",[325,1426,1427],{},"ChallengeTokenIssuer",[325,1429,1430],{},"JtiBlocklist","), a ",[325,1433,1434],{},"TwoFactorController",[325,1436,1437],{},"/2fa/enable|verify|disable",", IP-rate-limited), ",[325,1440,1441],{},"2fa:enable|disable|status"," CLI commands, and a ",[325,1444,1445],{},"config/auth.php",[325,1447,1448],{},"two_factor"," block. Richer factors (TOTP, WebAuthn, recovery codes) remain ",[325,1451,1452],{},"glueful/mfa"," scope.",[352,1455,1456,1461],{},[318,1457,1458],{"v-slot:title":320},[293,1459,1460],{},"Re-Validation and Session-Scoped Freshness",[318,1462,1463],{"v-slot:description":320},[293,1464,1465,1468,1469,1472,1473,380,1476,332,1479,1482,1483,1486,1487,1489,1490,1493,1494,1497],{},[325,1466,1467],{},"/2fa/verify"," re-reads the account before minting a session and rejects if the user no longer exists, the status left the login allowlist, or 2FA was disabled during the challenge window — closing the \"stale pre-2FA authentication\" gap. Sessions are issued via ",[325,1470,1471],{},"TokenManager::createUserSession"," (real ",[325,1474,1475],{},"sid",[325,1477,1478],{},"ver",[325,1480,1481],{},"auth_sessions"," row, refresh-token store), and a ",[308,1484,1485],{},"session-scoped"," freshness marker keyed by the issued token's ",[325,1488,1475],{}," gates ",[325,1491,1492],{},"/2fa/disable",", so a stolen token from a ",[398,1495,1496],{},"different"," session can't ride on a legitimate user's recent verify.",[352,1499,1500,1505],{},[318,1501,1502],{"v-slot:title":320},[293,1503,1504],{},"Identical Login Response Across Both Paths",[318,1506,1507],{"v-slot:description":320},[293,1508,1509,1512,1513,491,1516,1519,1520,1523,1524,1526,1527,1530,1531,380,1534,1537],{},[325,1510,1511],{},"AuthenticationService::authenticate()","'s username/password branch was split into ",[325,1514,1515],{},"verifyCredentials()",[325,1517,1518],{},"issueSession()"," to expose a \"verified user, no session yet\" gate (the provider short-circuit for token/API-key credentials is unchanged). ",[325,1521,1522],{},"AuthController::login()"," inserts the 2FA branch there, and both the no-2FA path and ",[325,1525,1467],{}," shape their response through a new ",[325,1528,1529],{},"LoginResponseShaper"," — so a 2FA-completed login carries the same CSRF token and fires the same ",[325,1532,1533],{},"LoginResponseBuilding",[325,1535,1536],{},"LoginResponseBuilt"," events as a direct login.",[352,1539,1540,1547],{},[318,1541,1542],{"v-slot:title":320},[293,1543,1544,1546],{},[325,1545,1377],{}," Parameter Bindings + Security Docs",[318,1548,1549],{"v-slot:description":320},[293,1550,1551,1554,1555,1558,1559,1562,1563,1566,1567,1570,1571,1573,1574,380,1577,1580],{},[325,1552,1553],{},"QueryBuilder::selectRaw(string $expression, array $bindings = [])"," now binds positional ",[325,1556,1557],{},"?"," values, closing the last unsafe-by-design gap in the SELECT clause. Bindings are stored on ",[325,1560,1561],{},"QueryState"," and returned by ",[325,1564,1565],{},"getBindings()"," in true SQL clause order; a latent ",[325,1568,1569],{},"clone()"," column/binding mismatch is fixed along the way. New ",[325,1572,1381],{}," documents the framework's actual SQL-injection and XSS defenses. The admin permission middleware also drops its dead ",[325,1575,1576],{},"validateMfaToken()",[325,1578,1579],{},"X-MFA-Token"," placeholder.",[347,1582,413],{"id":1583},"migration-notes-5",[415,1585,1586,1617,1646,1660],{},[418,1587,1588,1591,1592,1594,1595,1598,1599,1602,1603,1606,1607,1610,1611,373,1614,299],{},[308,1589,1590],{},"2FA is opt-in and off by default."," With ",[325,1593,1369],{}," (the default) there is no behavioral change. To enable: run the ",[325,1596,1597],{},"010_AddTwoFactorEnabledToUsers"," migration (ships in api-skeleton ",[325,1600,1601],{},"^1.28.0","), install ",[325,1604,1605],{},"glueful/email-notification",", set ",[325,1608,1609],{},"TWO_FACTOR_ENABLED=true",", and enroll users via ",[325,1612,1613],{},"POST /2fa/enable",[325,1615,1616],{},"php glueful 2fa:enable \u003Cuuid>",[418,1618,1619,634,1622,1625,1626,1629,1630,332,1633,332,1636,332,1639,332,1642,1645],{},[308,1620,1621],{},"New optional env vars.",[325,1623,1624],{},"TWO_FACTOR_ENABLED"," (default ",[325,1627,1628],{},"false",") plus tunables ",[325,1631,1632],{},"TWO_FACTOR_PIN_LENGTH",[325,1634,1635],{},"TWO_FACTOR_PIN_TTL",[325,1637,1638],{},"TWO_FACTOR_CHALLENGE_TTL",[325,1640,1641],{},"TWO_FACTOR_DISABLE_FRESHNESS",[325,1643,1644],{},"TWO_FACTOR_TEMPLATE",". Defaults preserve current behavior.",[418,1647,1648,634,1653,1656,1657,1659],{},[308,1649,1650,1652],{},[325,1651,1579],{}," header path removed.",[325,1654,1655],{},"require_mfa"," routes now rely solely on the session MFA handshake. The removed header path always returned ",[325,1658,1628],{},", so no working flow relied on it.",[418,1661,1662,1667,1668,1671],{},[308,1663,1664,1666],{},[325,1665,1377],{}," is backward compatible."," Existing ",[325,1669,1670],{},"selectRaw($expr)"," calls are unaffected; the bindings argument is optional.",[428,1673,1674],{"className":430,"code":431,"language":432,"meta":320,"style":320},[325,1675,1676],{"__ignoreMap":320},[436,1677,1678,1680,1682],{"class":438,"line":439},[436,1679,443],{"class":442},[436,1681,447],{"class":446},[436,1683,450],{"class":446},[452,1685],{},[301,1687,1689],{"id":1688},"v1440-errai","v1.44.0 - Errai",[293,1691,1692],{},[308,1693,1694],{},"Released: May 22, 2026",[312,1696,1698],{"color":675,"icon":1697,"variant":316},"i-tabler-shield-check",[318,1699,1700],{"v-slot:description":320},[293,1701,1702,1703,1706,1707,1710,1711,1714,1715,1718],{},"A focused follow-up to Dabih that closes four trust gaps — places where the README, CLI, or public API advertised behavior the code didn't deliver. Tag-aware cache invalidation actually works on Redis. ",[325,1704,1705],{},"restoreFromArchive()"," actually restores. ",[325,1708,1709],{},"security:report"," no longer ships ",[325,1712,1713],{},"rand()"," values under the name of a security audit. ",[325,1716,1717],{},"fields:whitelist-check"," inspects your real routes instead of a hardcoded placeholder list.",[347,1720,350],{"id":1721},"key-highlights-6",[352,1723,1724,1729],{},[318,1725,1726],{"v-slot:title":320},[293,1727,1728],{},"Real Tag-Aware Cache Invalidation on Redis",[318,1730,1731],{"v-slot:description":320},[293,1732,1733,542,1736,1739,1740,1743,1744,1747,1748,1751,1752,1755,1756,1759,1760,332,1762,332,1765,1768,1769,1772,1773,1775],{},[325,1734,1735],{},"RedisCacheDriver::addTags()",[325,1737,1738],{},"invalidateTags()"," are now backed by Redis SETs (",[325,1741,1742],{},"_gf_tag:{tag}"," → set of cache keys), with pipelined ",[325,1745,1746],{},"SADD"," on association and bulk ",[325,1749,1750],{},"DEL"," (keys + tag sets) on invalidation. ",[325,1753,1754],{},"getCapabilities()['features']['tags']"," is now ",[325,1757,1758],{},"true",". This unblocks ",[325,1761,1206],{},[325,1763,1764],{},"DistributedCacheService",[325,1766,1767],{},"ResponseCachingTrait",", and ",[325,1770,1771],{},"php glueful cache:clear --tags"," — all of which previously called the methods only to receive a silent ",[325,1774,1628],{},". Memcached and File drivers stay no-ops with explicit documentation (Memcached lacks set primitives; File would need a separate index layer).",[352,1777,1778,1783],{},[318,1779,1780],{"v-slot:title":320},[293,1781,1782],{},"Real Archive Restore",[318,1784,1785],{"v-slot:description":320},[293,1786,1787,1790,1791,1061,1794,1797,1798,380,1801,1804,1805,388,1808,1811,1812,1815,1816,1819,1820,1823,1824,1827],{},[325,1788,1789],{},"ArchiveService::restoreFromArchive()"," previously returned a typed failure regardless of input. It now replays archived rows into a target table inside a database transaction, honoring ",[325,1792,1793],{},"ArchiveRestoreOptions",[325,1795,1796],{},"targetTable"," (defaults to the source), ",[325,1799,1800],{},"offset",[325,1802,1803],{},"limit"," for partial restore, and ",[325,1806,1807],{},"conflictResolution",[325,1809,1810],{},"skip"," records collisions in the result; ",[325,1813,1814],{},"overwrite"," hard-deletes the existing row to bypass soft-delete and reinserts). Primary key detection prefers ",[325,1817,1818],{},"uuid"," then ",[325,1821,1822],{},"id",". The existing ",[325,1825,1826],{},"loadArchive()"," already handled checksum verify + decrypt + decompress; only the row replay was missing.",[352,1829,1830,1837],{},[318,1831,1832],{"v-slot:title":320},[293,1833,1834,1835],{},"Honest ",[325,1836,1709],{},[318,1838,1839],{"v-slot:description":320},[293,1840,1841,1842,332,1845,332,1848,332,1851,1854,1855,1857,1858,1861,1862,1865,1866,332,1869,332,1872,332,1875,1878,1879,299],{},"Stripped the command of every fabricated section. Removed ",[325,1843,1844],{},"analyzeAuthenticationSecurity()",[325,1846,1847],{},"getAuditSummary()",[325,1849,1850],{},"runVulnerabilityAssessment()",[325,1852,1853],{},"gatherSecurityMetrics()"," (all returned ",[325,1856,1713],{}," values across 12+ fields), the ",[325,1859,1860],{},"sendReportByEmail()"," stub, and ",[325,1863,1864],{},"assessCompliance()"," (hardcoded strings). Dropped the ",[325,1867,1868],{},"--include-vulnerabilities",[325,1870,1871],{},"--include-metrics",[325,1873,1874],{},"--email",[325,1876,1877],{},"--days"," options and the PDF format (never implemented). The command now exports HTML/JSON/text reports of the production readiness score, environment configuration, system info, and derived recommendations only. For dependency CVE scanning, users are directed to ",[325,1880,1881],{},"security:vulnerabilities",[352,1883,1884,1891],{},[318,1885,1886],{"v-slot:title":320},[293,1887,1888,1890],{},[325,1889,1717],{}," Inspects Real Routes",[318,1892,1893],{"v-slot:description":320},[293,1894,1895,1896,542,1899,1902,1903,1906,1907,1910,1911,1914,1915,1918,1919,1922,1923,1926,1927,1930,1931,1934,1935,1938,1939,1942],{},"The analyzer used to iterate a hardcoded three-entry placeholder list regardless of the application's actual routes. It now reads ",[325,1897,1898],{},"Router::getStaticRoutes()",[325,1900,1901],{},"Router::getDynamicRoutes()"," and inspects each ",[325,1904,1905],{},"Route::getFieldsConfig()"," for the actual ",[325,1908,1909],{},"#[Fields]"," attribute data (",[325,1912,1913],{},"allowed"," list, ",[325,1916,1917],{},"strict"," flag). Added a new low-severity ",[325,1920,1921],{},"NON_STRICT_WHITELIST"," finding for ",[325,1924,1925],{},"/api/"," routes with a whitelist that isn't strict — disallowed fields get silently dropped instead of rejected. The fabricated ",[325,1928,1929],{},"pattern_frequency"," block (",[325,1932,1933],{},"65/25/10",") is gone; the renamed ",[325,1936,1937],{},"getReferenceFieldPatterns()"," helper now documents itself as static defaults seeding ",[325,1940,1941],{},"--suggest-whitelist",", not telemetry.",[352,1944,1945,1950],{},[318,1946,1947],{"v-slot:title":320},[293,1948,1949],{},"README and Driver Docs Reconciled",[318,1951,1952],{"v-slot:description":320},[293,1953,1954,1955,1958,1959,380,1962,1964],{},"The README cache claim now reads \"Multi-driver support (Redis/Memcached/File) with distributed caching; tag-based invalidation on the Redis driver\" — accurate for the driver matrix that actually ships. The Memcached and File drivers' ",[325,1956,1957],{},"'tags' => false"," capability now carries an explanatory comment instead of the misleading \"Not implemented yet\" TODO. ",[325,1960,1961],{},"addTags()",[325,1963,1738],{}," docblocks point callers at the capability flag for driver-agnostic branching.",[347,1966,413],{"id":1967},"migration-notes-6",[415,1969,1970,2018,2038,2049,2061],{},[418,1971,1972,1977,1978,332,1981,332,1984,332,1987,1768,1990,1993,1994,332,1996,332,1998,2000,2001,2003,2004,2007,2008,332,2011,1768,2014,2017],{},[308,1973,1974,1976],{},[325,1975,1709],{}," output shape changed."," Consumers parsing the JSON output should expect ",[325,1979,1980],{},"authentication",[325,1982,1983],{},"audit_summary",[325,1985,1986],{},"vulnerabilities",[325,1988,1989],{},"metrics",[325,1991,1992],{},"compliance"," keys to be absent. Scripts depending on the removed ",[325,1995,1868],{},[325,1997,1871],{},[325,1999,1874],{},", or ",[325,2002,1877],{}," options must be updated — those flags now produce ",[325,2005,2006],{},"InvalidOptionException",". PDF format is also gone; only ",[325,2009,2010],{},"html",[325,2012,2013],{},"json",[325,2015,2016],{},"text"," are accepted.",[418,2019,2020,2023,2024,373,2027,2030,2031,2033,2034,2037],{},[308,2021,2022],{},"Cache tagging is Redis-only."," If your application calls ",[325,2025,2026],{},"$cache->addTags($key, $tags)",[325,2028,2029],{},"$cache->invalidateTags($tags)"," while running on the Memcached or File driver, those calls continue to return ",[325,2032,1628],{}," (unchanged), but the capability is now documented as deliberate. Branch on ",[325,2035,2036],{},"$cache->getCapabilities()['features']['tags']"," if you need driver-agnostic behavior, or switch to Redis for real tag invalidation.",[418,2039,2040,2045,2046,2048],{},[308,2041,2042,2044],{},[325,2043,1717],{}," will now report your real routes."," Previously it analyzed the same three placeholder entries every run. Routes without ",[325,2047,1909],{}," or with non-strict whitelists may surface as findings now that the analyzer sees them.",[418,2050,2051,2056,2057,2060],{},[308,2052,2053,2055],{},[325,2054,1705],{}," no longer always fails."," Code that called this method and treated the failure as expected (e.g., catch-and-log scaffolding) should be reviewed — it will actually restore rows now. Use ",[325,2058,2059],{},"ArchiveRestoreOptions::testRestore()"," (limit: 10, skip on conflict) for a safe dry-run shape.",[418,2062,2063,2066],{},[308,2064,2065],{},"No env var changes."," No new variables; no defaults changed.",[428,2068,2069],{"className":430,"code":431,"language":432,"meta":320,"style":320},[325,2070,2071],{"__ignoreMap":320},[436,2072,2073,2075,2077],{"class":438,"line":439},[436,2074,443],{"class":442},[436,2076,447],{"class":446},[436,2078,450],{"class":446},[452,2080],{},[301,2082,2084],{"id":2083},"v1430-dabih","v1.43.0 - Dabih",[293,2086,2087],{},[308,2088,2089],{},"Released: May 21, 2026",[312,2091,2092],{"color":675,"icon":1697,"variant":316},[318,2093,2094],{"v-slot:description":320},[293,2095,2096,2097,2100],{},"A production-hardening release that ships four feature areas at once: an ORM-aware N+1 detector with strict-mode CI enforcement, driver-aware query EXPLAIN, Kubernetes-conventional health probes, and a dedicated ",[325,2098,2099],{},"api_keys"," table with scopes, IP allowlists, rotation grace, and environment-prefixed keys. Four behaviorally-meaningful bug fixes in the ORM relation/eager-loading paths land alongside.",[347,2102,350],{"id":2103},"key-highlights-7",[352,2105,2106,2111],{},[318,2107,2108],{"v-slot:title":320},[293,2109,2110],{},"ORM-Aware N+1 Detection",[318,2112,2113],{"v-slot:description":320},[293,2114,705,2115,2118,2119,2122,2123,2126,2127,332,2130,2133,2134,2137,2138,2141,2142,2145,2146,2148,2149,2152,2153,2156,2157,2160,2161,2163,2164,2166,2167,2170],{},[325,2116,2117],{},"PreventsLazyLoading"," trait on ",[325,2120,2121],{},"Model"," watches for relations lazy-loaded on members of a hydrated collection — the exact shape of an N+1 — and reports the model class and relation name in the warning (",[325,2124,2125],{},"User::posts lazy-loaded from a collection of 50, add ->with('posts')","). Four modes: ",[325,2128,2129],{},"off",[325,2131,2132],{},"warn"," (logs ",[325,2135,2136],{},"[GLUEFUL-N+1]"," via ",[325,2139,2140],{},"error_log()"," with per-",[325,2143,2144],{},"(model, relation)"," dedupe per request), ",[325,2147,1917],{}," (throws ",[325,2150,2151],{},"LazyLoadingViolationException"," — extends ",[325,2154,2155],{},"\\LogicException","), and ",[325,2158,2159],{},"auto"," (resolves to ",[325,2162,2132],{}," in development, ",[325,2165,2129],{}," otherwise). Per-model opt-out via ",[325,2168,2169],{},"$instanceLazyLoadingMode = 'off'",". Custom violation handler hook for routing to Sentry / PSR logger.",[352,2172,2173,2181],{},[318,2174,2175],{"v-slot:title":320},[293,2176,2177,2178],{},"Driver-Aware ",[325,2179,2180],{},"$query->explain()",[318,2182,2183],{"v-slot:description":320},[293,2184,2185,2188,2189,2192,2193,2196,2197,2199,2200,2203,2204,2207],{},[325,2186,2187],{},"QueryBuilder::explain()"," is now driver-aware — SQLite uses ",[325,2190,2191],{},"EXPLAIN QUERY PLAN"," (the useful form) instead of plain ",[325,2194,2195],{},"EXPLAIN"," (which returns a raw opcode dump). MySQL and PostgreSQL continue with ",[325,2198,2195],{},". A new ",[325,2201,2202],{},"Builder::explain()"," on the ORM applies global scopes and delegates. ",[325,2205,2206],{},"QueryExecutorInterface::getDriverName()"," exposes the underlying PDO driver name for other callers that need the same kind of branching. Pairs naturally with N+1 detection for debugging the queries it flags.",[352,2209,2210,2215],{},[318,2211,2212],{"v-slot:title":320},[293,2213,2214],{},"Kubernetes-Conventional Health Probes",[318,2216,2217],{"v-slot:description":320},[293,2218,2219,2220,332,2223,332,2226,2229,2230,542,2233,2236],{},"Three new routes at the canonical paths orchestrators expect — ",[325,2221,2222],{},"GET /health/live",[325,2224,2225],{},"GET /health/ready",[325,2227,2228],{},"GET /health/startup",". Liveness is dependency-free (200 when the process can respond); readiness reports database, cache, and config status with 503 on any failure; startup reports initialization complete. The existing ",[325,2231,2232],{},"/healthz",[325,2234,2235],{},"/ready"," endpoints continue to work — the new paths are additive, so Pod specs that reference either form keep functioning.",[352,2238,2239,2244],{},[318,2240,2241],{"v-slot:title":320},[293,2242,2243],{},"Hardened API Keys",[318,2245,2246],{"v-slot:description":320},[293,2247,2248,2249,2251,2252,2255,2256,2259,2260,2263,2264,2267,2268,2271,2272,2275,2276,2279,2280,299],{},"Dedicated ",[325,2250,2099],{}," table with per-key scopes (",[325,2253,2254],{},"['read:*', 'write:posts']","), CIDR/IP allowlists, expiration, rotation with grace period, and environment-prefixed plaintext (",[325,2257,2258],{},"gf_live_*"," in production, ",[325,2261,2262],{},"gf_test_*"," elsewhere). Keys are SHA-256 hashed before storage; the first 16 chars are stored as an indexed prefix for O(1) lookup. The ",[325,2265,2266],{},"key_hash"," column is ",[325,2269,2270],{},"UNIQUE"," and the verify path is collision-tolerant. Rotation creates a new key and expires the old after the grace window so you can roll without downtime. New ",[325,2273,2274],{},"#[RequireScope]"," route attribute (repeatable — OR within, AND across) auto-attaches the ",[325,2277,2278],{},"require_scope"," middleware. Four CLI commands: ",[325,2281,2282],{},"apikey:create|list|rotate|revoke",[352,2284,2285,2290],{},[318,2286,2287],{"v-slot:title":320},[293,2288,2289],{},"Router Exposes Matched Route on Request",[318,2291,2292],{"v-slot:description":320},[293,2293,2294,2296,2297,542,2300,2303,2304,2307,2308,2310,2311,2314],{},[325,2295,768],{}," now sets ",[325,2298,2299],{},"_route",[325,2301,2302],{},"_route_params"," on ",[325,2305,2306],{},"$request->attributes"," before middleware runs. Middleware can read route-level metadata (",[325,2309,2274],{}," config, ",[325,2312,2313],{},"#[RateLimit]"," config, future attribute systems) without re-resolving the route — a small but load-bearing piece of plumbing.",[352,2316,2317,2322],{},[318,2318,2319],{"v-slot:title":320},[293,2320,2321],{},"ORM Bug Fixes",[318,2323,2324],{"v-slot:description":320},[293,2325,2326,2327,2330,2331,2334,2335,2338,2339,2342,2343,2346,2347,596,2350,2353,2354,2357,2358,299],{},"Four pre-existing ORM bugs surfaced and were fixed as prerequisites for the new detector. ",[325,2328,2329],{},"HasAttributes::getAttribute()"," now routes property access to relations (",[325,2332,2333],{},"$user->posts"," used to return null). ",[325,2336,2337],{},"__isset()"," is relation-aware, so ",[325,2340,2341],{},"$user->posts[0] ?? null"," correctly triggers lazy-load instead of swallowing the result. ",[325,2344,2345],{},"HasRelationships::newRelatedInstance()"," propagates the parent's ",[325,2348,2349],{},"ApplicationContext",[325,2351,2352],{},"Builder::getRelation()"," uses the standard ",[325,2355,2356],{},"Relation::noConstraints()"," pattern so eager loading no longer emits ",[325,2359,2360],{},"WHERE x = NULL",[347,2362,413],{"id":2363},"migration-notes-7",[415,2365,2366,2390,2431,2440,2461,2467],{},[418,2367,2368,634,2371,2374,2375,2378,2379,2382,2383,2386,2387,2389],{},[308,2369,2370],{},"Run the new migration.",[325,2372,2373],{},"glueful/api-skeleton ^1.26.0"," ships ",[325,2376,2377],{},"009_CreateApiKeysTable.php",". Run ",[325,2380,2381],{},"php glueful migrate:run"," after upgrading. The ",[325,2384,2385],{},"apikey:*"," CLI commands and the new auth provider both require the ",[325,2388,2099],{}," table.",[418,2391,2392,2398,2399,2402,2403,2406,2407,2410,2411,332,2414,332,2417,332,2420,2423,2424,2427,2428,2430],{},[308,2393,2394,2397],{},[325,2395,2396],{},"ApiKeyAuthenticationProvider"," is single-track."," The legacy ",[325,2400,2401],{},"users.api_key"," fallback (which queried a column that doesn't exist in the canonical schema — see ",[325,2404,2405],{},"001_CreateInitialSchema.php",") is gone. All four ",[325,2408,2409],{},"AuthenticationProviderInterface"," methods (",[325,2412,2413],{},"authenticate",[325,2415,2416],{},"validateToken",[325,2418,2419],{},"refreshTokens",[325,2421,2422],{},"generateTokens",") now use ",[325,2425,2426],{},"ApiKeyService::verify()"," exclusively. Anyone relying on a custom ",[325,2429,2401],{}," column must migrate keys into the new table.",[418,2432,2433,2439],{},[308,2434,2435,2438],{},[325,2436,2437],{},"UserRepository::findByApiKey()"," removed."," Zero callers verified across the framework, all official extensions, api-skeleton, and other org repos. External subclasses that called it must remove the reference.",[418,2441,2442,2448,2449,925,2451,2163,2453,2455,2456,2458,2459,299],{},[308,2443,2444,2445,299],{},"New env var (optional): ",[325,2446,2447],{},"DB_LAZY_LOADING_MODE"," Defaults to ",[325,2450,2159],{},[325,2452,2132],{},[325,2454,2129],{}," elsewhere. Set to ",[325,2457,1917],{}," in CI to fail tests on accidental N+1 patterns. Per-model override via ",[325,2460,2169],{},[418,2462,2463,2466],{},[308,2464,2465],{},"No breaking changes to existing routes."," Health-probe paths and API-key transport (X-API-Key header, Authorization: ApiKey, query string) are unchanged.",[418,2468,2469,2470,2473,2474,2477],{},"See ",[325,2471,2472],{},"docs/API_KEYS.md"," for the full API key usage guide and ",[325,2475,2476],{},"docs/ORM/N_PLUS_ONE_DETECTION.md"," for the N+1 detector reference.",[428,2479,2481],{"className":430,"code":2480,"language":432,"meta":320,"style":320},"composer update glueful/framework\nphp glueful migrate:run\n",[325,2482,2483,2491],{"__ignoreMap":320},[436,2484,2485,2487,2489],{"class":438,"line":439},[436,2486,443],{"class":442},[436,2488,447],{"class":446},[436,2490,450],{"class":446},[436,2492,2493,2495,2497],{"class":438,"line":1132},[436,2494,1135],{"class":442},[436,2496,1138],{"class":446},[436,2498,2499],{"class":446}," migrate:run\n",[452,2501],{},[301,2503,2505],{"id":2504},"v1420-caph","v1.42.0 - Caph",[293,2507,2508],{},[308,2509,2510],{},"Released: May 20, 2026",[312,2512,2514],{"color":675,"icon":2513,"variant":316},"i-tabler-file-code",[318,2515,2516],{"v-slot:description":320},[293,2517,2518,2519,332,2522,2525],{},"Closes the trust gap between Glueful's generated OpenAPI spec and runtime behavior, and makes the spec rich enough that off-the-shelf SDK generators (",[325,2520,2521],{},"openapi-typescript",[325,2523,2524],{},"openapi-generator-cli",", …) produce high-quality clients without manual editing. One documented breaking change to the permission-exception envelope.",[347,2527,350],{"id":2528},"key-highlights-8",[352,2530,2531,2536],{},[318,2532,2533],{"v-slot:title":320},[293,2534,2535],{},"Config-Driven Security Schemes",[318,2537,2538],{"v-slot:description":320},[293,2539,705,2540,2543,2544,542,2547,2550,2551,2554,2555,2558,2559,2561,2562,2565],{},[325,2541,2542],{},"SecuritySchemeRegistry"," reads ",[325,2545,2546],{},"documentation.security_schemes",[325,2548,2549],{},"documentation.middleware_map"," from config. Replaces 15 hardcoded ",[325,2552,2553],{},"BearerAuth"," literals across the documentation generators. Per-operation ",[325,2556,2557],{},"security"," requirements are now derived from each route's declared middleware — JWT routes get ",[325,2560,2553],{},", API-key routes get ",[325,2563,2564],{},"ApiKeyAuth",", mixed routes emit both.",[352,2567,2568,2577],{},[318,2569,2570],{"v-slot:title":320},[293,2571,2572,2573,2576],{},"Unified ",[325,2574,2575],{},"ErrorResponse"," Schema",[318,2578,2579],{"v-slot:description":320},[293,2580,2581,2582,2585,2586,2589,2590,332,2593,332,2596,2599,2600,2603,2604,2607],{},"New OpenAPI component describes the ",[325,2583,2584],{},"{success, message, error: {code, error_code, timestamp, request_id}}"," envelope with an ",[325,2587,2588],{},"error_code"," enum (",[325,2591,2592],{},"NOT_FOUND",[325,2594,2595],{},"FORBIDDEN",[325,2597,2598],{},"UNPROCESSABLE_ENTITY",", …). All CRUD endpoint 4xx responses ",[325,2601,2602],{},"$ref"," this schema so generated SDKs can typecheck error responses. The legacy ",[325,2605,2606],{},"Error"," schema is preserved for backward compatibility but is no longer referenced.",[352,2609,2610,2615],{},[318,2611,2612],{"v-slot:title":320},[293,2613,2614],{},"Deterministic Operation IDs",[318,2616,2617],{"v-slot:description":320},[293,2618,705,2619,2622,2623,2626,2627,2630],{},[325,2620,2621],{},"OperationIdGenerator"," produces stable camelCase IDs (",[325,2624,2625],{},"getV1UsersByUuid",") with collision-numbering for SDK method names. Also closes a hidden gap where comment-driven generation emitted operations without any ",[325,2628,2629],{},"operationId",", forcing downstream tools into auto-derived garbage names.",[352,2632,2633,2638],{},[318,2634,2635],{"v-slot:title":320},[293,2636,2637],{},"Pagination & Field Selection",[318,2639,2640],{"v-slot:description":320},[293,2641,705,2642,2645,2646,332,2649,2652,2653,2656,2657,2660,2661,542,2664,2667,2668,299],{},[325,2643,2644],{},"PaginationSchemaBuilder"," emits ",[325,2647,2648],{},"PaginationMeta",[325,2650,2651],{},"PaginationLinks",", and per-resource envelope schemas that match ",[325,2654,2655],{},"PaginatedResourceResponse"," exactly. List endpoints reference these components for uniform typing across resources. New ",[325,2658,2659],{},"addRouteWithFieldsAttribute()"," helper surfaces ",[325,2662,2663],{},"?fields=",[325,2665,2666],{},"?expand="," query params with an enum of allowed paths derived from ",[325,2669,2670],{},"#[Fields(allowed: [...], strict: true)]",[352,2672,2673,2678],{},[318,2674,2675],{"v-slot:title":320},[293,2676,2677],{},"Auto-Derived Request Examples",[318,2679,2680],{"v-slot:description":320},[293,2681,705,2682,2685,2686,925,2689,332,2692,2694,2695,392,2698,2701,2702,332,2705,332,2708,2711,2712,2715],{},[325,2683,2684],{},"ExampleDeriver"," populates JSON request bodies with realistic example payloads inferred from Validator rules and schema properties — ",[325,2687,2688],{},"email",[325,2690,2691],{},"user@example.com",[325,2693,1818],{}," → a valid UUID, integers respect ",[325,2696,2697],{},"min:",[325,2699,2700],{},"max:"," ranges. Field-name heuristics handle common cases like ",[325,2703,2704],{},"first_name",[325,2706,2707],{},"slug",[325,2709,2710],{},"title",". The ",[325,2713,2714],{},"@example"," annotation in docblocks overrides the derived value.",[352,2717,2718,2723],{},[318,2719,2720],{"v-slot:title":320},[293,2721,2722],{},"OpenAPI 3.1 Webhooks Block",[318,2724,2725],{"v-slot:description":320},[293,2726,705,2727,2730,2731,2734,2735,2738,2739,2742,2743,2746,2747,2750,2751,2754,2755,2758,2759,2761],{},[325,2728,2729],{},"WebhookDocsBuilder"," emits the top-level ",[325,2732,2733],{},"webhooks"," object from ",[325,2736,2737],{},"documentation.webhooks"," config. Each declared event surfaces the actual ",[325,2740,2741],{},"X-Glueful-Signature"," (Stripe-style ",[325,2744,2745],{},"t=…,v1=…",") and ",[325,2748,2749],{},"X-Glueful-Timestamp"," headers sent by ",[325,2752,2753],{},"WebhookDeliveryService",", plus the ",[325,2756,2757],{},"WebhookEnvelope"," payload shape. SDK generators (",[325,2760,2521],{}," and friends) scaffold handler types automatically.",[352,2763,2764,2772],{},[318,2765,2766],{"v-slot:title":320},[293,2767,2768,2771],{},[325,2769,2770],{},"generate:client"," CLI Wrapper",[318,2773,2774],{"v-slot:description":320},[293,2775,2776,2777,2779,2780,2782,2783,2786,2787,2790],{},"Thin command that shells out to ",[325,2778,2521],{}," for TypeScript and ",[325,2781,2524],{}," for everything else. Glueful does not own codegen logic — the command builds the right shell invocation with safe-by-construction language sanitization and ",[325,2784,2785],{},"escapeshellarg"," for paths. Prints the command by default; ",[325,2788,2789],{},"--execute"," runs it.",[347,2792,413],{"id":2793},"migration-notes-8",[415,2795,2796,2824,2845,2867],{},[418,2797,2798,889,2801,2804,2805,2808,2809,2811,2812,373,2814,2816,2817,542,2820,2823],{},[308,2799,2800],{},"Permission exception envelope (breaking)",[325,2802,2803],{},"PermissionUnauthorizedException"," previously returned ",[325,2806,2807],{},"{success, message, code, error_code}",". It now returns the unified ",[325,2810,2584],{}," shape, identical to every other HTTP exception. Consumers reading top-level ",[325,2813,325],{},[325,2815,2588],{}," must read ",[325,2818,2819],{},"error.code",[325,2821,2822],{},"error.error_code"," instead. All other 4xx/5xx responses already used the nested shape, so most consumers are unaffected.",[418,2825,2826,2829,2830,332,2832,332,2834,1768,2836,2838,2839,925,2842,2844],{},[308,2827,2828],{},"Regenerate SDK clients"," — After upgrading, regenerate downstream clients. The ",[325,2831,2575],{},[325,2833,2648],{},[325,2835,2651],{},[325,2837,2757],{}," components are new; operation IDs are now deterministic camelCase (e.g., ",[325,2840,2841],{},"getUsers",[325,2843,2625],{},") which may rename existing SDK methods.",[418,2846,2847,2850,2851,388,2854,332,2857,332,2860,2862,2863,2866],{},[308,2848,2849],{},"No new env vars"," — All new configuration lives in ",[325,2852,2853],{},"config/documentation.php",[325,2855,2856],{},"security_schemes",[325,2858,2859],{},"middleware_map",[325,2861,2733],{},"). Existing deployments need no ",[325,2864,2865],{},".env"," changes.",[418,2868,2869,2872,2873,2876],{},[308,2870,2871],{},"Discriminator support deferred"," — The plan included optional ",[325,2874,2875],{},"discriminator"," emission for polymorphic resources, gated on actual polymorphism in the codebase. The gate found none, so this is deferred to a future release.",[452,2878],{},[301,2880,2882],{"id":2881},"v1410-beid","v1.41.0 - Beid",[293,2884,2885],{},[308,2886,2887],{},"Released: March 3, 2026",[312,2889,2891],{"color":675,"icon":2890,"variant":316},"i-tabler-settings",[318,2892,2893],{"v-slot:description":320},[293,2894,2895],{},"Introduces profile-driven logging bootstrap with deterministic defaults per environment, production safety checks for logging configuration, and fixes for upsert column handling and audit toggle alignment.",[347,2897,350],{"id":2898},"key-highlights-9",[352,2900,2901,2906],{},[318,2902,2903],{"v-slot:title":320},[293,2904,2905],{},"Profile-Driven Logging Bootstrap",[318,2907,2908],{"v-slot:description":320},[293,2909,2910,2913,2914,2917,2918,2921,2922,332,2925,332,2928,1768,2931,2934],{},[325,2911,2912],{},"config/logging.php"," now resolves defaults from ",[325,2915,2916],{},"LOG_PROFILE"," (or ",[325,2919,2920],{},"APP_ENV",") before applying explicit env overrides. Built-in profiles for ",[325,2923,2924],{},"development",[325,2926,2927],{},"staging",[325,2929,2930],{},"production",[325,2932,2933],{},"testing"," provide safe, deterministic startup behavior including log levels, sink settings, and per-channel retention windows.",[352,2936,2937,2942],{},[318,2938,2939],{"v-slot:title":320},[293,2940,2941],{},"Production Safety Checks",[318,2943,2944],{"v-slot:description":320},[293,2945,2946,2949,2950,542,2953,2956],{},[325,2947,2948],{},"system:check --production"," now flags unsafe logging configurations: no durable log sink (",[325,2951,2952],{},"LOG_TO_FILE=false",[325,2954,2955],{},"LOG_TO_DB=false","), disabled event/audit toggles, debug-level production logging, and invalid retention values.",[352,2958,2959,2964],{},[318,2960,2961],{"v-slot:title":320},[293,2962,2963],{},"Upsert Column Fix",[318,2965,2966],{"v-slot:description":320},[293,2967,2968,2971,2972,2975,2976,2979,2980,2983,2984,299],{},[325,2969,2970],{},"InsertBuilder::buildUpsertQuery()"," now passes column names (",[325,2973,2974],{},"array_keys($data)",") instead of full data arrays to driver ",[325,2977,2978],{},"upsert()"," SQL builders. Fixes PostgreSQL crash where ",[325,2981,2982],{},"null"," values were passed into ",[325,2985,387],{},[352,2987,2988,2993],{},[318,2989,2990],{"v-slot:title":320},[293,2991,2992],{},"Audit Toggle Alignment",[318,2994,2995],{"v-slot:description":320},[293,2996,2997,2998,3001,3002,332,3005,1768,3008,3010,3011,3013,3014,299],{},"Core activity audit subscriber registration and ",[325,2999,3000],{},"LogManager"," now respect ",[325,3003,3004],{},"EVENTS_ENABLED",[325,3006,3007],{},"EVENTS_AUDIT_LOGGING",[325,3009,2952],{}," during framework boot. Removes debug ",[325,3012,2140],{}," noise from ",[325,3015,3016],{},"RequestUserContext",[347,3018,413],{"id":3019},"migration-notes-9",[415,3021,3022,3044,3055],{},[418,3023,3024,3030,3031,3033,3034,3036,3037,3040,3041,3043],{},[308,3025,3026,3029],{},[325,3027,3028],{},"LOG_TO_DB"," default changed",": Previously defaulted to ",[325,3032,1758],{}," when the env var was absent. Now defaults to ",[325,3035,1628],{}," in all profiles. Add ",[325,3038,3039],{},"LOG_TO_DB=true"," to your ",[325,3042,2865],{}," if your application requires database logging.",[418,3045,3046,1061,3049,332,3051,3054],{},[308,3047,3048],{},"New env vars recognized",[325,3050,2916],{},[325,3052,3053],{},"LOG_RETENTION_*_DAYS",". No action needed if unset — profiles provide safe defaults.",[418,3056,3057,3058,3061],{},"Review ",[325,3059,3060],{},"docs/LOGGING_BOOTSTRAP.md"," for the full profile matrix and production baseline.",[452,3063],{},[301,3065,3067],{"id":3066},"v1404-alnair-patch","v1.40.4 - Alnair (Patch)",[293,3069,3070],{},[308,3071,3072],{},"Released: February 21, 2026",[312,3074,3077],{"color":3075,"icon":3076,"variant":316},"info","i-tabler-brush",[318,3078,3079],{"v-slot:description":320},[293,3080,3081,3082,3085],{},"Code style fix only — extracts a long error message string in ",[325,3083,3084],{},"WhereClause::getConditionsArray()"," to comply with the 120-character PHPCS line limit. No runtime behavior changes.",[347,3087,413],{"id":3088},"migration-notes-10",[415,3090,3091],{},[418,3092,3093],{},"Patch release. No breaking changes. Drop-in replacement for 1.40.3.",[452,3095],{},[301,3097,3099],{"id":3098},"v1403-alnair-patch","v1.40.3 - Alnair (Patch)",[293,3101,3102],{},[308,3103,3072],{},[312,3105,3107],{"color":464,"icon":3106,"variant":316},"i-tabler-bug",[318,3108,3109],{"v-slot:description":320},[293,3110,3111,3112,3114],{},"Fixes three production issues: mutation WHERE clauses crashing on non-equality operators, queue Redis config rejecting string values from ",[325,3113,2865],{},", and async notification dispatch failures crashing API requests.",[347,3116,350],{"id":3117},"key-highlights-10",[352,3119,3120,3125],{},[318,3121,3122],{"v-slot:title":320},[293,3123,3124],{},"Mutation WHERE Operator Support",[318,3126,3127],{"v-slot:description":320},[293,3128,3129,332,3132,1768,3134,3137,3138,332,3141,332,3144,332,3147,332,3150,332,3153,332,3156,332,3159,332,3162,3165,3166,3169],{},[325,3130,3131],{},"WhereClause",[325,3133,383],{},[325,3135,3136],{},"DeleteBuilder"," now support comparison and null operators (",[325,3139,3140],{},"\u003C",[325,3142,3143],{},"\u003C=",[325,3145,3146],{},">",[325,3148,3149],{},">=",[325,3151,3152],{},"!=",[325,3154,3155],{},"LIKE",[325,3157,3158],{},"IN",[325,3160,3161],{},"IS NULL",[325,3163,3164],{},"IS NOT NULL",") in UPDATE/DELETE queries. Previously only ",[325,3167,3168],{},"="," was supported, causing queue and notification cleanup jobs to crash.",[352,3171,3172,3177],{},[318,3173,3174],{"v-slot:title":320},[293,3175,3176],{},"Queue Config String Coercion",[318,3178,3179],{"v-slot:description":320},[293,3180,3181,3184,3185,380,3187,380,3189,380,3192,380,3195,380,3198,380,3201,380,3204,3206,3207,3209],{},[325,3182,3183],{},"DriverRegistry"," config validation now accepts numeric strings for int/port fields and boolean-like strings (",[325,3186,1758],{},[325,3188,1628],{},[325,3190,3191],{},"1",[325,3193,3194],{},"0",[325,3196,3197],{},"yes",[325,3199,3200],{},"no",[325,3202,3203],{},"on",[325,3205,2129],{},"), matching how ",[325,3208,2865],{}," values arrive in PHP. Fixes Redis config rejection in production environments.",[352,3211,3212,3217],{},[318,3213,3214],{"v-slot:title":320},[293,3215,3216],{},"Async Notification Best-Effort",[318,3218,3219],{"v-slot:description":320},[293,3220,3221,3224],{},[325,3222,3223],{},"NotificationService::queueAsyncDispatch()"," is now wrapped in try/catch — logs the error and returns gracefully. Side-effect failures (e.g., queue unavailable) no longer crash the primary API operation that triggered the notification.",[347,3226,413],{"id":3227},"migration-notes-11",[415,3229,3230],{},[418,3231,3232],{},"Patch release. No breaking changes. Drop-in replacement for 1.40.2.",[452,3234],{},[301,3236,3238],{"id":3237},"v1402-alnair-patch","v1.40.2 - Alnair (Patch)",[293,3240,3241],{},[308,3242,3072],{},[312,3244,3245],{"color":464,"icon":3106,"variant":316},[318,3246,3247],{"v-slot:description":320},[293,3248,3249,3250,3253],{},"Fixes 500 errors on event-driven flows (e.g., comment creation) caused by ",[325,3251,3252],{},"array_unique()"," crashing on config lists containing nested arrays/objects. Replaces with hash-based dedup that safely handles all value types.",[347,3255,413],{"id":3256},"migration-notes-12",[415,3258,3259],{},[418,3260,3261],{},"Patch release. No breaking changes. Drop-in replacement for 1.40.1.",[452,3263],{},[301,3265,3267],{"id":3266},"v1401-alnair-patch","v1.40.1 - Alnair (Patch)",[293,3269,3270],{},[308,3271,3072],{},[312,3273,3274],{"color":464,"icon":3106,"variant":316},[318,3275,3276],{"v-slot:description":320},[293,3277,3278,3279,3282,3283,299],{},"Fixes \"Array to string conversion\" warnings in config merging when nested associative arrays (e.g., ",[325,3280,3281],{},"session.providers",") were incorrectly treated as lists and passed through ",[325,3284,3252],{},[347,3286,413],{"id":3287},"migration-notes-13",[415,3289,3290],{},[418,3291,3292],{},"Patch release. No breaking changes. Drop-in replacement for 1.40.0.",[452,3294],{},[301,3296,3298],{"id":3297},"v1400-alnair","v1.40.0 - Alnair",[293,3300,3301],{},[308,3302,3072],{},[312,3304,3306],{"color":675,"icon":3305,"variant":316},"i-tabler-bell",[318,3307,3308],{"v-slot:description":320},[293,3309,3310,3311,3314],{},"Notification delivery orchestration — split sync/async channel delivery, per-channel delivery state tracking, DB-indexed idempotency, policy-based success evaluation, and targeted async retry. Also adds ",[325,3312,3313],{},"ProvisioningException"," for account setup failures.",[347,3316,350],{"id":3317},"key-highlights-11",[352,3319,3320,3325],{},[318,3321,3322],{"v-slot:title":320},[293,3323,3324],{},"Split Delivery API",[318,3326,3327],{"v-slot:description":320},[293,3328,3329,3332,3333,3336,3337,332,3340,332,3343,388,3346,332,3349,332,3352,2156,3355,3358],{},[325,3330,3331],{},"NotificationService::sendSplit()"," provides first-class sync/async channel separation. ",[325,3334,3335],{},"send()"," now supports ",[325,3338,3339],{},"sync_channels",[325,3341,3342],{},"async_channels",[325,3344,3345],{},"channel_failure_policy",[325,3347,3348],{},"any_success",[325,3350,3351],{},"require_critical",[325,3353,3354],{},"all",[325,3356,3357],{},"critical_channels"," — giving callers precise control over which channels block the request and which fire-and-forget via queue.",[352,3360,3361,3366],{},[318,3362,3363],{"v-slot:title":320},[293,3364,3365],{},"Per-Channel Delivery Tracking",[318,3367,3368],{"v-slot:description":320},[293,3369,705,3370,3373,3374,332,3377,332,3380,332,3383,3386],{},[325,3371,3372],{},"notification_deliveries"," table tracks delivery lifecycle per channel with status, attempt count, error details, and timestamps. Repository APIs (",[325,3375,3376],{},"ensureDeliveryRecords",[325,3378,3379],{},"recordDeliveryAttempt",[325,3381,3382],{},"getChannelsNeedingDispatch",[325,3384,3385],{},"getFailedDeliveryChannels",") enable targeted retry — async retries only dispatch channels still needing work.",[352,3388,3389,3394],{},[318,3390,3391],{"v-slot:title":320},[293,3392,3393],{},"DB-Indexed Idempotency",[318,3395,3396],{"v-slot:description":320},[293,3397,2248,3398,3401,3402,3405,3406,3409,3410,3412],{},[325,3399,3400],{},"notifications.idempotency_key"," column with a database index replaces the previous ",[325,3403,3404],{},"_meta"," JSON scan. Channel-level idempotency via unique key on ",[325,3407,3408],{},"(notification_uuid, channel)"," in ",[325,3411,3372],{},". Both layers are now DB-native with no PHP-side row scanning.",[352,3414,3415,3420],{},[318,3416,3417],{"v-slot:title":320},[293,3418,3419],{},"Provisioning Exception",[318,3421,3422],{"v-slot:description":320},[293,3423,705,3424,3426,3427,3430],{},[325,3425,3313],{}," for account setup failures (e.g., post-registration handler errors) maps to HTTP 500 and the ",[325,3428,3429],{},"api"," log channel, replacing misleading 401 responses when user creation succeeds but provisioning fails.",[347,3432,413],{"id":3433},"migration-notes-14",[415,3435,3436,3439,3448,3458],{},[418,3437,3438],{},"Non-backward-compatible changes to notification sending flow and response structure.",[418,3440,705,3441,3443,3444,3447],{},[325,3442,3372],{}," table required via migration (",[325,3445,3446],{},"004_CreateNotificationSystemTables",").",[418,3449,3450,3453,3454,3457],{},[325,3451,3452],{},"notifications"," table requires new ",[325,3455,3456],{},"idempotency_key"," column with index.",[418,3459,3460,3463,3464,3466],{},[325,3461,3462],{},"sendWithTemplate()"," now routes through ",[325,3465,3335],{}," — any code relying on the previous direct-dispatch behavior should be reviewed.",[452,3468],{},[301,3470,3472],{"id":3471},"v1390-menkent","v1.39.0 - Menkent",[293,3474,3475],{},[308,3476,3477],{},"Released: February 20, 2026",[312,3479,3481],{"color":3480,"icon":465,"variant":316},"error",[318,3482,3483],{"v-slot:description":320},[293,3484,3485,3486,3489],{},"Token and session management reimplementation — hash-only refresh tokens with one-time-use rotation, session versioning for instant access-token invalidation, replay detection with session-scope revocation. ",[308,3487,3488],{},"Breaking change",": existing sessions become invalid at cutover.",[347,3491,350],{"id":3492},"key-highlights-12",[352,3494,3495,3500],{},[318,3496,3497],{"v-slot:title":320},[293,3498,3499],{},"Hash-Only Refresh Tokens",[318,3501,3502],{"v-slot:description":320},[293,3503,3504,3505,3508],{},"Refresh tokens are stored as SHA-256 hashes only — no raw tokens at rest. One-time-use rotation in a single ",[325,3506,3507],{},"SELECT ... FOR UPDATE"," transaction prevents race conditions and ensures atomic token exchange.",[352,3510,3511,3516],{},[318,3512,3513],{"v-slot:title":320},[293,3514,3515],{},"Session Versioning",[318,3517,3518],{"v-slot:description":320},[293,3519,3520,3521,3523,3524,3526,3527,3530],{},"Access JWTs now carry ",[325,3522,1475],{}," (session UUID) and ",[325,3525,1478],{}," (session version) claims. Token validation checks server-side session state and version, enabling instant invalidation via ",[325,3528,3529],{},"session_version"," bump without maintaining a token blocklist.",[352,3532,3533,3538],{},[318,3534,3535],{"v-slot:title":320},[293,3536,3537],{},"Replay Detection",[318,3539,3540],{"v-slot:description":320},[293,3541,3542],{},"Presenting a consumed or revoked refresh token triggers session-scope revocation — all active refresh tokens for that session are immediately invalidated. An optional configurable idempotency window (1-2s) can handle concurrent browser tab refreshes gracefully.",[352,3544,3545,3550],{},[318,3546,3547],{"v-slot:title":320},[293,3548,3549],{},"Clean Service Architecture",[318,3551,3552],{"v-slot:description":320},[293,3553,3554,3555,491,3558,491,3561,3564,3565,332,3568,332,3571,332,3574,332,3577,332,3580,1768,3583,299],{},"The monolithic ",[325,3556,3557],{},"TokenManager",[325,3559,3560],{},"SessionStore",[325,3562,3563],{},"AuthenticationService"," tangle is decomposed into focused services: ",[325,3566,3567],{},"RefreshService",[325,3569,3570],{},"AccessTokenIssuer",[325,3572,3573],{},"ProviderTokenIssuer",[325,3575,3576],{},"SessionRepository",[325,3578,3579],{},"RefreshTokenRepository",[325,3581,3582],{},"RefreshTokenStore",[325,3584,3585],{},"SessionStateCache",[352,3587,3588,3593],{},[318,3589,3590],{"v-slot:title":320},[293,3591,3592],{},"AuthenticatedUser Value Object",[318,3594,3595],{"v-slot:description":320},[293,3596,3597,3598,332,3600,332,3603,332,3606,332,3609,3612,3613,3616,3617,299],{},"New minimal runtime identity object (",[325,3599,1818],{},[325,3601,3602],{},"sessionUuid",[325,3604,3605],{},"provider",[325,3607,3608],{},"roles",[325,3610,3611],{},"permissions",") replaces ad-hoc array passing across controllers, traits, and middleware. ",[325,3614,3615],{},"BaseController::$currentUser"," is now typed as ",[325,3618,3619],{},"AuthenticatedUser|null",[347,3621,413],{"id":3622},"migration-notes-15",[415,3624,3625,3630,3640,3663,3680],{},[418,3626,3627,3629],{},[308,3628,3488],{},": All existing sessions and tokens become invalid at cutover. Users must re-authenticate.",[418,3631,3632,3633,3636,3637,3447],{},"Create ",[325,3634,3635],{},"auth_refresh_tokens"," table via migration (schema in ",[325,3638,3639],{},"docs/TOKEN_SESSION_REIMPLEMENTATION_PLAN.md",[418,3641,3642,3643,1061,3645,332,3648,332,3651,332,3654,332,3657,332,3660,299],{},"Drop legacy columns from ",[325,3644,1481],{},[325,3646,3647],{},"access_token",[325,3649,3650],{},"refresh_token",[325,3652,3653],{},"access_expires_at",[325,3655,3656],{},"refresh_expires_at",[325,3658,3659],{},"last_token_refresh",[325,3661,3662],{},"token_fingerprint",[418,3664,3665,3666,332,3668,332,3671,332,3674,3677,3678,299],{},"Add ",[325,3667,3529],{},[325,3669,3670],{},"expires_at",[325,3672,3673],{},"last_seen_at",[325,3675,3676],{},"revoked_at"," to ",[325,3679,1481],{},[418,3681,3682,3683,3685,3686,332,3689,332,3692,332,3695,332,3698,299],{},"Update ",[325,3684,2865],{}," with ",[325,3687,3688],{},"JWT_KEY",[325,3690,3691],{},"ACCESS_TOKEN_LIFETIME",[325,3693,3694],{},"REFRESH_TOKEN_LIFETIME",[325,3696,3697],{},"TOKEN_SALT",[325,3699,3700],{},"JWT_ALGORITHM",[452,3702],{},[301,3704,3706],{"id":3705},"v1380-lesath","v1.38.0 - Lesath",[293,3708,3709],{},[308,3710,3711],{},"Released: February 17, 2026",[312,3713,3715],{"color":314,"icon":3714,"variant":316},"i-tabler-bolt",[318,3716,3717],{"v-slot:description":320},[293,3718,3719,3720,3722,3723,3726],{},"Auth token-refresh performance optimization — eliminates redundant ",[325,3721,1481],{}," database lookups during token refresh, removes direct ",[325,3724,3725],{},"new Connection()"," instantiation, and adds request-level caching for refresh-token session lookups.",[347,3728,350],{"id":3729},"key-highlights-13",[352,3731,3732,3737],{},[318,3733,3734],{"v-slot:title":320},[293,3735,3736],{},"Token-Refresh DB Lookup Reduction",[318,3738,3739],{"v-slot:description":320},[293,3740,3741,3744,3745,542,3747,3750,3751,3753],{},[325,3742,3743],{},"TokenManager::getSessionFromRefreshToken()"," now fetches ",[325,3746,3605],{},[325,3748,3749],{},"remember_me"," in the initial query. Two subsequent ",[325,3752,1481],{}," queries that re-fetched these fields during token refresh are eliminated, reducing per-refresh DB round-trips from 3 to 1.",[352,3755,3756,3761],{},[318,3757,3758],{"v-slot:title":320},[293,3759,3760],{},"AuthenticationService DI Cleanup",[318,3762,3763],{"v-slot:description":320},[293,3764,3765,3768,3769,3772,3773,3776,3777,3780,3781,3783,3784,3787],{},[325,3766,3767],{},"refreshTokens()"," resolves the session via ",[325,3770,3771],{},"SessionStore::getByRefreshToken()"," up front and passes ",[325,3774,3775],{},"user_uuid"," directly to ",[325,3778,3779],{},"getUserDataByUuid()",". Removes direct ",[325,3782,3725],{}," instantiation in favour of the injected ",[325,3785,3786],{},"UserRepository",", improving testability and DI consistency.",[352,3789,3790,3795],{},[318,3791,3792],{"v-slot:title":320},[293,3793,3794],{},"Request-Level Refresh-Token Cache",[318,3796,3797],{"v-slot:description":320},[293,3798,3799,3801,3802,3805,3806,3809,3810,3813],{},[325,3800,3771],{}," now caches results in ",[325,3803,3804],{},"$requestCache"," keyed by ",[325,3807,3808],{},"refresh:{hash}",", matching the existing ",[325,3811,3812],{},"getByAccessToken()"," pattern. Repeated lookups within the same request (e.g., validation then token generation) hit memory instead of the database.",[347,3815,413],{"id":3816},"migration-notes-16",[415,3818,3819,3826],{},[418,3820,3821,3822,3825],{},"No breaking changes. All modified methods are ",[325,3823,3824],{},"private"," or internal to the auth subsystem.",[418,3827,3828,3829,2303,3832,3835],{},"For optimal performance, add the composite index ",[325,3830,3831],{},"idx_auth_sessions_refresh_status",[325,3833,3834],{},"(refresh_token, status)"," to production databases.",[452,3837],{},[301,3839,3841],{"id":3840},"v1330-gacrux","v1.33.0 - Gacrux",[293,3843,3844],{},[308,3845,3846],{},"Released: February 14, 2026",[312,3848,3849],{"color":464,"icon":465,"variant":316},[318,3850,3851],{"v-slot:description":320},[293,3852,3853,3854,3857,3858,3861],{},"Eliminated all ",[325,3855,3856],{},"fromGlobals()"," fallbacks from service code — every auth and utility service now resolves ",[325,3859,3860],{},"RequestContext"," from the container's shared singleton, fixing memory exhaustion on high-header requests and enabling long-running server compatibility.",[347,3863,350],{"id":3864},"key-highlights-14",[352,3866,3867,3872],{},[318,3868,3869],{"v-slot:title":320},[293,3870,3871],{},"Container-Enforced Request Resolution",[318,3873,3874],{"v-slot:description":320},[293,3875,3876,3877,332,3879,332,3882,332,3884,332,3887,3889,3890,332,3893,332,3896,332,3899,332,3902,332,3904,3907,3908,373,3911,3914],{},"15 files across auth services (",[325,3878,3557],{},[325,3880,3881],{},"JwtAuthenticationProvider",[325,3883,3560],{},[325,3885,3886],{},"EmailVerification",[325,3888,3563],{},") and utility services (",[325,3891,3892],{},"RequestHelper",[325,3894,3895],{},"Utils",[325,3897,3898],{},"Cors",[325,3900,3901],{},"SpaManager",[325,3903,3786],{},[325,3905,3906],{},"SecurityManager",") no longer call ",[325,3909,3910],{},"RequestContext::fromGlobals()",[325,3912,3913],{},"Request::createFromGlobals()"," as fallbacks. All request data is resolved from the DI container's shared singleton, which is created once per request lifecycle.",[352,3916,3917,3922],{},[318,3918,3919],{"v-slot:title":320},[293,3920,3921],{},"Memory Safety for High-Header Requests",[318,3923,3924],{"v-slot:description":320},[293,3925,3926,3927,3929,3930,3933,3934,3937],{},"Previously, each ",[325,3928,3856],{}," call independently reconstructed a PSR-7 request from ",[325,3931,3932],{},"$_SERVER"," superglobals, allocating fresh header arrays. On requests with many headers, this caused unbounded memory growth — crashing at Nyholm's ",[325,3935,3936],{},"MessageTrait.php"," with 512MB exhaustion. The container singleton eliminates redundant construction entirely.",[352,3939,3940,3945],{},[318,3941,3942],{"v-slot:title":320},[293,3943,3944],{},"Silent Fallback Removal",[318,3946,3947],{"v-slot:description":320},[293,3948,3949,542,3952,3955,3956,3959,3960,3963],{},[325,3950,3951],{},"SessionStoreResolver",[325,3953,3954],{},"TokenManager::getSessionStore()"," no longer silently construct bare ",[325,3957,3958],{},"SessionStore()"," instances (with stale globals) when the container is unavailable. Container resolution failures now surface immediately with clear ",[325,3961,3962],{},"\\RuntimeException"," messages, making wiring bugs visible rather than hidden.",[352,3965,3966,3971],{},[318,3967,3968],{"v-slot:title":320},[293,3969,3970],{},"Long-Running Server Compatibility",[318,3972,3973],{"v-slot:description":320},[293,3974,3975,3976,332,3978,2000,3981,3984,3985,299],{},"Services that read ",[325,3977,3932],{},[325,3979,3980],{},"getallheaders()",[325,3982,3983],{},"apache_request_headers()"," directly would return stale data on RoadRunner, Swoole, or FrankenPHP after the first request. All request data now flows through the container singleton, which is reset between requests via ",[325,3986,3987],{},"Container::reset()",[347,3989,413],{"id":3990},"migration-notes-17",[415,3992,3993,3996,4013,4023],{},[418,3994,3995],{},"No breaking changes for services instantiated via the container (the standard path).",[418,3997,3998,3999,4002,4003,4005,4006,4008,4009,4012],{},"Direct ",[325,4000,4001],{},"new Service()"," calls without providing ",[325,4004,2349],{}," now throw ",[325,4007,3962],{}," instead of silently using stale globals. Pass ",[325,4010,4011],{},"context:"," to the constructor.",[418,4014,4015,4018,4019,4022],{},[325,4016,4017],{},"EmailVerification::sendPasswordResetEmail()"," has a new optional ",[325,4020,4021],{},"?ApplicationContext $context"," parameter. Existing callers without context continue to work but should add context for proper resolution.",[418,4024,4025,4027,4028,4030],{},[325,4026,3906],{}," constructor has a new optional ",[325,4029,4021],{}," parameter (appended, no positional break).",[452,4032],{},[301,4034,4036],{"id":4035},"v1320-fomalhaut","v1.32.0 - Fomalhaut",[293,4038,4039],{},[308,4040,4041],{},"Released: February 11, 2026",[312,4043,4044],{"color":675,"icon":1183,"variant":316},[318,4045,4046],{"v-slot:description":320},[293,4047,4048,4049,4052,4053,4056],{},"Schema builder ",[325,4050,4051],{},"alterTable"," now supports the same callback-style API as ",[325,4054,4055],{},"createTable",", enabling concise inline table alterations with automatic execution.",[347,4058,350],{"id":4059},"key-highlights-15",[352,4061,4062,4070],{},[318,4063,4064],{"v-slot:title":320},[293,4065,4066,4067,4069],{},"Dual-Mode ",[325,4068,4051],{}," API",[318,4071,4072],{"v-slot:description":320},[293,4073,4074,4077,4078,4081,4082,4085,4086,4088],{},[325,4075,4076],{},"alterTable()"," now accepts an optional callback parameter. Without a callback, it returns a fluent ",[325,4079,4080],{},"TableBuilder"," for chaining (existing behavior). With a callback, it passes the builder to the callback, executes the ALTER statements, and returns ",[325,4083,4084],{},"$this"," for schema-level chaining — matching the ",[325,4087,4055],{}," pattern.",[352,4090,4091,4096],{},[318,4092,4093],{"v-slot:title":320},[293,4094,4095],{},"ColumnBuilder Finalization Safety",[318,4097,4098],{"v-slot:description":320},[293,4099,4100,4101,4104,4105,4108,4109,4112],{},"The callback path calls ",[325,4102,4103],{},"gc_collect_cycles()"," before executing, forcing PHP to run ",[325,4106,4107],{},"ColumnBuilder"," destructors so that ",[325,4110,4111],{},"finalizeColumn()"," registers columns before the ALTER SQL is generated. This prevents empty ALTER statements when column definitions are created as temporaries inside the callback.",[347,4114,413],{"id":4115},"migration-notes-18",[415,4117,4118,4121],{},[418,4119,4120],{},"No breaking changes. All existing callers use the no-callback path and are unaffected.",[418,4122,4123,4124,332,4127,332,4130,332,4133,332,4136,332,4139,4142],{},"Convenience methods (",[325,4125,4126],{},"addColumn",[325,4128,4129],{},"dropColumn",[325,4131,4132],{},"addIndex",[325,4134,4135],{},"dropIndex",[325,4137,4138],{},"addForeignKey",[325,4140,4141],{},"dropForeignKey",") continue to work unchanged.",[452,4144],{},[301,4146,4148],{"id":4147},"v1310-enif","v1.31.0 - Enif",[293,4150,4151],{},[308,4152,4153],{},"Released: February 9, 2026",[312,4155,4157],{"color":675,"icon":4156,"variant":316},"i-tabler-plug-connected",[318,4158,4159],{"v-slot:description":320},[293,4160,4161],{},"Centralized context propagation: core services and ORM receive application context during framework boot, enabling cleaner static API usage.",[347,4163,350],{"id":4164},"key-highlights-16",[352,4166,4167,4172],{},[318,4168,4169],{"v-slot:title":320},[293,4170,4171],{},"ORM Default Context",[318,4173,4174],{"v-slot:description":320},[293,4175,4176,4179,4180,4183,4184,4186,4187,4190],{},[325,4177,4178],{},"Model::setDefaultContext()"," allows static model calls like ",[325,4181,4182],{},"User::find($id)"," without explicitly passing ",[325,4185,2349],{}," as the first argument. The framework sets this automatically during boot. Explicit context passing (",[325,4188,4189],{},"User::find($context, $id)",") continues to work and takes priority.",[352,4192,4193,4198],{},[318,4194,4195],{"v-slot:title":320},[293,4196,4197],{},"Boot-Time Context Propagation",[318,4199,4200],{"v-slot:description":320},[293,4201,4202,2296,4205,4207,4208,332,4210,332,4212,332,4215,332,4218,332,4221,332,4223,332,4226,1768,4229,4231,4232,4235],{},[325,4203,4204],{},"Framework::boot()",[325,4206,2349],{}," on core services during initialization: ",[325,4209,2121],{},[325,4211,3895],{},[325,4213,4214],{},"CacheHelper",[325,4216,4217],{},"SecureErrorResponse",[325,4219,4220],{},"RoutesManager",[325,4222,545],{},[325,4224,4225],{},"ConfigManager",[325,4227,4228],{},"Webhook",[325,4230,3016],{},". Eliminates scattered manual ",[325,4233,4234],{},"setContext()"," calls throughout application code.",[347,4237,413],{"id":4238},"migration-notes-19",[415,4240,4241,4244],{},[418,4242,4243],{},"No breaking changes. Existing code passing context explicitly is unaffected.",[418,4245,4246,4247,4249],{},"Default context is only available after ",[325,4248,4204],{}," completes. Service provider constructors must still pass context explicitly.",[452,4251],{},[301,4253,4255],{"id":4254},"v1301-diphda-patch","v1.30.1 - Diphda (Patch)",[293,4257,4258],{},[308,4259,4153],{},[312,4261,4263],{"color":3075,"icon":4262,"variant":316},"i-tabler-key",[318,4264,4265],{"v-slot:description":320},[293,4266,4267,4268,4271],{},"Ensures ",[325,4269,4270],{},"JWTService"," has access to the application context during authentication provider initialization.",[347,4273,4275],{"id":4274},"what-changed","What Changed",[415,4277,4278],{},[418,4279,4280,4283,4284,4287],{},[325,4281,4282],{},"AuthBootstrap::initialize()"," now calls ",[325,4285,4286],{},"JWTService::setContext()"," before creating JWT and API key authentication providers, fixing potential context-missing issues during token operations.",[347,4289,413],{"id":4290},"migration-notes-20",[415,4292,4293],{},[418,4294,4295],{},"No breaking changes. Drop-in patch.",[452,4297],{},[301,4299,4301],{"id":4300},"v1300-diphda","v1.30.0 - Diphda",[293,4303,4304],{},[308,4305,4153],{},[312,4307,4309],{"color":675,"icon":4308,"variant":316},"i-tabler-arrows-join-2",[318,4310,4311],{"v-slot:description":320},[293,4312,4313],{},"Unified exception handling: consolidated two overlapping exception handlers into a single source of truth with channel-based log routing and optimized context building.",[347,4315,350],{"id":4316},"key-highlights-17",[352,4318,4319,4324],{},[318,4320,4321],{"v-slot:title":320},[293,4322,4323],{},"Single Handler, Single Code Path",[318,4325,4326],{"v-slot:description":320},[293,4327,4328,4329,388,4332,4335,4336,4339],{},"The modern ",[325,4330,4331],{},"Handler",[325,4333,4334],{},"src/Http/Exceptions/Handler.php",") is now the sole authority for rendering, reporting, and event dispatch. The legacy ",[325,4337,4338],{},"ExceptionHandler"," has been reduced from 1041 lines to a ~250-line bootstrap shim that registers PHP global handlers and delegates to the DI-managed Handler instance.",[352,4341,4342,4347],{},[318,4343,4344],{"v-slot:title":320},[293,4345,4346],{},"Channel-Based Log Routing",[318,4348,4349],{"v-slot:description":320},[293,4350,4351,4352,332,4355,332,4358,332,4360,332,4363,332,4366,332,4368,332,4370,332,4372,4375,4376,299],{},"Exceptions are automatically routed to named log channels (",[325,4353,4354],{},"auth",[325,4356,4357],{},"database",[325,4359,2557],{},[325,4361,4362],{},"http",[325,4364,4365],{},"ratelimit",[325,4367,278],{},[325,4369,3429],{},[325,4371,3611],{},[325,4373,4374],{},"framework",") based on their type. Custom mappings can be registered via ",[325,4377,4378],{},"Handler::mapChannel()",[352,4380,4381,4386],{},[318,4382,4383],{"v-slot:title":320},[293,4384,4385],{},"Optimized Context Building",[318,4387,4388],{"v-slot:description":320},[293,4389,4390],{},"High-frequency exceptions (validation errors, 404s) get lightweight context (URI, method, IP). All others get full context including headers, memory usage, and processing time. Eliminates the previous three separate context-building methods.",[347,4392,413],{"id":4393},"migration-notes-21",[415,4395,4396,4412,4418],{},[418,4397,4398,4399,332,4402,332,4405,332,4408,4411],{},"No breaking changes. ",[325,4400,4401],{},"ExceptionHandler::logError()",[325,4403,4404],{},"setTestMode()",[325,4406,4407],{},"getTestResponse()",[325,4409,4410],{},"setLogger()"," continue to work as static methods.",[418,4413,4414,4417],{},[325,4415,4416],{},"ExceptionHandler::setContext()"," is now a no-op — can be removed from calling code.",[418,4419,4420,4421,332,4424,332,4427,2000,4430,4433,4434,373,4437,299],{},"Extensions using ",[325,4422,4423],{},"Glueful\\Exceptions\\HttpException",[325,4425,4426],{},"NotFoundException",[325,4428,4429],{},"BusinessLogicException",[325,4431,4432],{},"ValidationException"," should update imports to their modern namespaces under ",[325,4435,4436],{},"Glueful\\Http\\Exceptions\\*",[325,4438,4439],{},"Glueful\\Validation\\*",[452,4441],{},[301,4443,4445],{"id":4444},"v1290-capella","v1.29.0 - Capella",[293,4447,4448],{},[308,4449,4450],{},"Released: February 7, 2026",[312,4452,4454],{"color":675,"icon":4453,"variant":316},"i-tabler-rocket",[318,4455,4456],{"v-slot:description":320},[293,4457,4458],{},"Queue system overhaul with leaf worker mode, config normalization, distributed lock fix, and env-driven queue presets.",[347,4460,350],{"id":4461},"key-highlights-18",[352,4463,4464,4469],{},[318,4465,4466],{"v-slot:title":320},[293,4467,4468],{},"Leaf Worker Mode",[318,4470,4471],{"v-slot:description":320},[293,4472,705,4473,4476,4477,332,4480,332,4483,332,4486,332,4489,1768,4492,299],{},[325,4474,4475],{},"queue:work process"," action enables spawned workers to execute jobs directly in-process. Eliminates recursive manager spawning for cleaner process trees and better resource isolation. Supports ",[325,4478,4479],{},"--sleep",[325,4481,4482],{},"--max-jobs",[325,4484,4485],{},"--max-runtime",[325,4487,4488],{},"--stop-when-empty",[325,4490,4491],{},"--with-monitoring",[325,4493,4494],{},"--emit-heartbeat",[352,4496,4497,4502],{},[318,4498,4499],{"v-slot:title":320},[293,4500,4501],{},"Queue Presets & Env-Driven Config",[318,4503,4504],{"v-slot:description":320},[293,4505,4506,4507,332,4510,332,4513,332,4516,332,4519,332,4522,332,4525,4527,4528,4531],{},"Seven pre-configured queue profiles (",[325,4508,4509],{},"critical",[325,4511,4512],{},"maintenance",[325,4514,4515],{},"default",[325,4517,4518],{},"high",[325,4520,4521],{},"emails",[325,4523,4524],{},"reports",[325,4526,3452],{},") with per-queue workers, memory limits, timeouts, priorities, and autoscale toggles — all env-driven. Schedule queue names also env-backed via ",[325,4529,4530],{},"SCHEDULE_QUEUE_*"," variables.",[352,4533,4534,4539],{},[318,4535,4536],{"v-slot:title":320},[293,4537,4538],{},"Process Management Fixes",[318,4540,4541],{"v-slot:description":320},[293,4542,4543,4544,392,4547,4550,4551,4554],{},"ProcessManager config normalization (",[325,4545,4546],{},"max_workers",[325,4548,4549],{},"max_workers_global","), new ",[325,4552,4553],{},"stop()"," API with state cleanup, status payload includes worker runtime, and distributed lock changed from host-scoped to queue-scoped for correct multi-host coordination.",[347,4556,413],{"id":4557},"migration-notes-22",[415,4559,4560,4567,4573],{},[418,4561,4562,4563,4566],{},"No breaking changes. Existing ",[325,4564,4565],{},"queue:work"," behavior is unchanged.",[418,4568,4569,4570,299],{},"Auto-scaling is default-off for all queue presets. Enable per-queue via ",[325,4571,4572],{},"*_QUEUE_AUTO_SCALE=true",[418,4574,3057,4575,4578,4579,542,4582,4531],{},[325,4576,4577],{},".env.example"," for new ",[325,4580,4581],{},"QUEUE_*",[325,4583,4530],{},[452,4585],{},[301,4587,4589],{"id":4588},"v1283-bellatrix-patch","v1.28.3 - Bellatrix (Patch)",[293,4591,4592],{},[308,4593,4450],{},[312,4595,4596],{"color":3075,"icon":3106,"variant":316},[318,4597,4598],{"v-slot:description":320},[293,4599,4600,4601,4604],{},"Fix CLI option shortcut collision causing ",[325,4602,4603],{},"LogicException"," when running queue commands.",[347,4606,350],{"id":4607},"key-highlights-19",[352,4609,4610,4618],{},[293,4611,4612],{},[308,4613,4614,4617],{},[325,4615,4616],{},"-q"," Shortcut Collision Fix",[415,4619,4620,4638,4651],{},[418,4621,4622,332,4625,1768,4628,4631,4632,4634,4635],{},[325,4623,4624],{},"WorkCommand",[325,4626,4627],{},"ServerCommand",[325,4629,4630],{},"MaintenanceCommand"," all defined ",[325,4633,4616],{}," as shortcut for ",[325,4636,4637],{},"--queue",[418,4639,4640,4641,4643,4644,4647,4648,4650],{},"Symfony Console reserves ",[325,4642,4616],{}," for the global ",[325,4645,4646],{},"--quiet"," option, causing a ",[325,4649,4603],{}," at runtime",[418,4652,4653,4654,4656,4657,4659],{},"Removed the ",[325,4655,4616],{}," shortcut from all three commands — use ",[325,4658,4637],{}," instead",[347,4661,4663],{"id":4662},"risk-assessment","Risk Assessment",[415,4665,4666,4672,4681],{},[418,4667,4668,4671],{},[308,4669,4670],{},"Risk Level",": Low",[418,4673,4674,4677,4678,4680],{},[308,4675,4676],{},"Breaking Changes",": None — ",[325,4679,4616],{}," was never usable due to the collision",[418,4682,4683,4686],{},[308,4684,4685],{},"Migration Effort",": None — drop-in patch",[452,4688],{},[301,4690,4692],{"id":4691},"v1282-bellatrix-patch","v1.28.2 - Bellatrix (Patch)",[293,4694,4695],{},[308,4696,4450],{},[312,4698,4699],{"color":3075,"icon":3106,"variant":316},[318,4700,4701],{"v-slot:description":320},[293,4702,4703],{},"CLI migration commands now properly discover extension migrations. PostgreSQL schema introspection is now schema-safe.",[347,4705,350],{"id":4706},"key-highlights-20",[352,4708,4709,4714],{},[293,4710,4711],{},[308,4712,4713],{},"Container Self-Registration",[415,4715,4716,4725,4728],{},[418,4717,4718,4721,4722],{},[325,4719,4720],{},"ContainerFactory::create()"," now registers the built container under ",[325,4723,4724],{},"ContainerInterface",[418,4726,4727],{},"Enables autowiring to inject the fully-configured container into CLI commands",[418,4729,4730],{},"CLI commands no longer create a separate container that lacks extension state",[352,4732,4733,4738],{},[293,4734,4735],{},[308,4736,4737],{},"Migration Command DI Wiring",[415,4739,4740,4757,4760],{},[418,4741,4742,332,4745,332,4748,4751,4752,542,4754,4756],{},[325,4743,4744],{},"RunCommand",[325,4746,4747],{},"StatusCommand",[325,4749,4750],{},"RollbackCommand"," accept optional ",[325,4753,4724],{},[325,4755,2349],{}," via constructor",[418,4758,4759],{},"When booted via DI, commands receive the container with extension-registered migration paths",[418,4761,4762,332,4765,332,4768,4771],{},[325,4763,4764],{},"migrate:run",[325,4766,4767],{},"migrate:status",[325,4769,4770],{},"migrate:rollback"," now see extension migrations",[352,4773,4774,4779],{},[293,4775,4776],{},[308,4777,4778],{},"PostgreSQL Schema-Safe Introspection",[415,4780,4781,4795,4808],{},[418,4782,4783,4784,4787,4788,4791,4792],{},"All ",[325,4785,4786],{},"PostgreSQLSqlGenerator"," introspection queries now use ",[325,4789,4790],{},"current_schema()"," instead of hardcoding ",[325,4793,4794],{},"public",[418,4796,4797,4800,4801,332,4804,4807],{},[325,4798,4799],{},"getTableColumns()"," scoped with ",[325,4802,4803],{},"table_schema",[325,4805,4806],{},"pg_namespace"," joins, and schema-aware FK lookups",[418,4809,4810,4811,4813],{},"Enables correct behavior in multi-tenant setups and non-",[325,4812,4794],{}," schema deployments",[347,4815,4663],{"id":4816},"risk-assessment-1",[415,4818,4819,4823,4828],{},[418,4820,4821,4671],{},[308,4822,4670],{},[418,4824,4825,4827],{},[308,4826,4676],{},": None",[418,4829,4830,4686],{},[308,4831,4685],{},[452,4833],{},[301,4835,4837],{"id":4836},"v1281-bellatrix-patch","v1.28.1 - Bellatrix (Patch)",[293,4839,4840],{},[308,4841,4842],{},"Released: February 6, 2026",[312,4844,4845],{"color":3075,"icon":3106,"variant":316},[318,4846,4847],{"v-slot:description":320},[293,4848,4849],{},"Router stability fixes for applications using route caching with extensions.",[347,4851,350],{"id":4852},"key-highlights-21",[352,4854,4855,4860],{},[293,4856,4857],{},[308,4858,4859],{},"Router Group Stack Fix",[415,4861,4862,4878,4881],{},[418,4863,4864,4867,4868,4871,4872,542,4875],{},[325,4865,4866],{},"Router::group()"," now uses ",[325,4869,4870],{},"try/finally"," to always clean up ",[325,4873,4874],{},"groupStack",[325,4876,4877],{},"middlewareStack",[418,4879,4880],{},"Prevents route prefix leakage when exceptions occur inside nested group callbacks",[418,4882,4883,4884,4887],{},"Eliminates cascading path accumulation across extension route loading (e.g., ",[325,4885,4886],{},"/rbac/roles/auth/social/...",")",[352,4889,4890,4895],{},[293,4891,4892],{},[308,4893,4894],{},"Cache-Aware Route Registration",[415,4896,4897,4904,4910,4920],{},[418,4898,4899,4900,4903],{},"Router tracks when routes were pre-loaded from cache via ",[325,4901,4902],{},"routesLoadedFromCache"," flag",[418,4905,4906,4907],{},"Static routes: overwrites cached entry instead of throwing ",[325,4908,4909],{},"LogicException(\"Route already defined\")",[418,4911,4912,4913,542,4916,4919],{},"Dynamic routes: replaces cached entry in ",[325,4914,4915],{},"dynamicRoutes",[325,4917,4918],{},"routeBuckets"," instead of appending duplicates",[418,4921,4922],{},"Ensures fresh extension definitions always take priority over cached routes",[347,4924,4663],{"id":4925},"risk-assessment-2",[415,4927,4928,4932,4936],{},[418,4929,4930,4671],{},[308,4931,4670],{},[418,4933,4934,4827],{},[308,4935,4676],{},[418,4937,4938,4686],{},[308,4939,4685],{},[452,4941],{},[301,4943,4945],{"id":4944},"v1280-bellatrix-minor","v1.28.0 - Bellatrix (Minor)",[293,4947,4948],{},[308,4949,4950],{},"Released: February 5, 2026",[312,4952,4953],{"color":464,"icon":676,"variant":316},[318,4954,4955],{"v-slot:description":320},[293,4956,4957],{},"Route caching support through controller refactoring. Routes now use cacheable syntax for improved performance.",[347,4959,350],{"id":4960},"key-highlights-22",[352,4962,4963,4968],{},[293,4964,4965],{},[308,4966,4967],{},"ResourceController Refactoring",[415,4969,4970,4980,4998,5008],{},[418,4971,4972,4973,332,4976,4979],{},"Removed wrapper methods pattern (",[325,4974,4975],{},"listResources",[325,4977,4978],{},"showResource",", etc.)",[418,4981,4982,4983,332,4986,332,4989,332,4992,332,4995],{},"Renamed methods to RESTful conventions: ",[325,4984,4985],{},"index",[325,4987,4988],{},"show",[325,4990,4991],{},"store",[325,4993,4994],{},"update",[325,4996,4997],{},"destroy",[418,4999,5000,5001,542,5004,5007],{},"Added ",[325,5002,5003],{},"destroyBulk",[325,5005,5006],{},"updateBulk"," for bulk operations",[418,5009,5010,5011,5014],{},"Methods now accept ",[325,5012,5013],{},"Request"," directly instead of array parameters",[352,5016,5017,5022],{},[293,5018,5019],{},[308,5020,5021],{},"Cacheable Route Syntax",[415,5023,5024,5031,5034],{},[418,5025,5026,5027,5030],{},"All routes now use ",[325,5028,5029],{},"[Controller::class, 'method']"," syntax",[418,5032,5033],{},"Closures replaced throughout for route cache compatibility",[418,5035,5036],{},"Routes can be compiled and cached for faster resolution",[352,5038,5039,5044],{},[293,5040,5041],{},[308,5042,5043],{},"Route Caching Infrastructure",[415,5045,5046,5059,5066,5069],{},[418,5047,5048,5049,332,5052,332,5055,5058],{},"RouteCompiler: ",[325,5050,5051],{},"validateHandlers()",[325,5053,5054],{},"hasClosures()",[325,5056,5057],{},"getClosureRoutes()"," for detecting non-cacheable routes",[418,5060,5061,5062,5065],{},"RouteCache: ",[325,5063,5064],{},"cacheContainsClosures()"," auto-invalidates cache when closures detected",[418,5067,5068],{},"Logs warnings to help developers identify routes needing conversion",[418,5070,5071,5072,5075],{},"Use ",[325,5073,5074],{},"route:debug"," command to find closure-based routes",[352,5077,5078,5082],{},[293,5079,5080],{},[308,5081,4676],{},[415,5083,5084,5103,5117],{},[418,5085,5086,925,5088,332,5091,925,5094,332,5097,925,5100],{},[325,5087,1262],{},[325,5089,5090],{},"index()",[325,5092,5093],{},"getSingle()",[325,5095,5096],{},"show()",[325,5098,5099],{},"post()",[325,5101,5102],{},"store()",[418,5104,5105,925,5108,332,5111,925,5114],{},[325,5106,5107],{},"put()",[325,5109,5110],{},"update()",[325,5112,5113],{},"delete()",[325,5115,5116],{},"destroy()",[418,5118,5119,5120,3677,5123],{},"Method signatures changed from ",[325,5121,5122],{},"(array $params, array $data)",[325,5124,5125],{},"(Request $request)",[347,5127,5129],{"id":5128},"migration-guide","Migration Guide",[293,5131,5132,5133,5136],{},"If you extended ",[325,5134,5135],{},"ResourceController"," and overrode methods:",[428,5138,5141],{"className":5139,"code":5140,"language":1135,"meta":320,"style":320},"language-php shiki shiki-themes material-theme-lighter github-light github-dark monokai","// Before\npublic function get(array $params, array $queryParams)\n{\n    // custom logic\n}\n\n// After\npublic function index(Request $request): Response\n{\n    $table = $request->attributes->get('table', '');\n    $queryParams = $request->query->all();\n    // custom logic\n}\n",[325,5142,5143,5148,5189,5194,5200,5206,5213,5219,5247,5252,5296,5322,5327],{"__ignoreMap":320},[436,5144,5145],{"class":438,"line":439},[436,5146,5147],{"class":1168},"// Before\n",[436,5149,5150,5153,5157,5161,5165,5169,5172,5175,5178,5181,5183,5186],{"class":438,"line":1132},[436,5151,4794],{"class":5152},"sTNss",[436,5154,5156],{"class":5155},"srJo8"," function",[436,5158,5160],{"class":5159},"sD0ED"," get",[436,5162,5164],{"class":5163},"swvn1","(",[436,5166,5168],{"class":5167},"shWJe","array",[436,5170,5171],{"class":5163}," $",[436,5173,5174],{"class":1151},"params",[436,5176,5177],{"class":5163},",",[436,5179,5180],{"class":5167}," array",[436,5182,5171],{"class":5163},[436,5184,5185],{"class":1151},"queryParams",[436,5187,5188],{"class":5163},")\n",[436,5190,5191],{"class":438,"line":1158},[436,5192,5193],{"class":5163},"{\n",[436,5195,5197],{"class":438,"line":5196},4,[436,5198,5199],{"class":1168},"    // custom logic\n",[436,5201,5203],{"class":438,"line":5202},5,[436,5204,5205],{"class":5163},"}\n",[436,5207,5209],{"class":438,"line":5208},6,[436,5210,5212],{"emptyLinePlaceholder":5211},true,"\n",[436,5214,5216],{"class":438,"line":5215},7,[436,5217,5218],{"class":1168},"// After\n",[436,5220,5222,5224,5226,5229,5231,5234,5236,5239,5241,5244],{"class":438,"line":5221},8,[436,5223,4794],{"class":5152},[436,5225,5156],{"class":5155},[436,5227,5228],{"class":5159}," index",[436,5230,5164],{"class":5163},[436,5232,5013],{"class":5233},"s_MOj",[436,5235,5171],{"class":5163},[436,5237,5238],{"class":1151},"request",[436,5240,4887],{"class":5163},[436,5242,5243],{"class":1144},":",[436,5245,5246],{"class":5233}," Response\n",[436,5248,5250],{"class":438,"line":5249},9,[436,5251,5193],{"class":5163},[436,5253,5255,5258,5261,5263,5265,5267,5270,5273,5275,5277,5279,5283,5286,5288,5290,5293],{"class":438,"line":5254},10,[436,5256,5257],{"class":5163},"    $",[436,5259,5260],{"class":1151},"table ",[436,5262,3168],{"class":1144},[436,5264,5171],{"class":5163},[436,5266,5238],{"class":1151},[436,5268,5269],{"class":1144},"->",[436,5271,5272],{"class":1151},"attributes",[436,5274,5269],{"class":1144},[436,5276,715],{"class":5159},[436,5278,5164],{"class":5163},[436,5280,5282],{"class":5281},"siCPE","'",[436,5284,5285],{"class":446},"table",[436,5287,5282],{"class":5281},[436,5289,5177],{"class":5163},[436,5291,5292],{"class":5281}," ''",[436,5294,5295],{"class":5163},");\n",[436,5297,5299,5301,5304,5306,5308,5310,5312,5315,5317,5319],{"class":438,"line":5298},11,[436,5300,5257],{"class":5163},[436,5302,5303],{"class":1151},"queryParams ",[436,5305,3168],{"class":1144},[436,5307,5171],{"class":5163},[436,5309,5238],{"class":1151},[436,5311,5269],{"class":1144},[436,5313,5314],{"class":1151},"query",[436,5316,5269],{"class":1144},[436,5318,3354],{"class":5159},[436,5320,5321],{"class":5163},"();\n",[436,5323,5325],{"class":438,"line":5324},12,[436,5326,5199],{"class":1168},[436,5328,5330],{"class":438,"line":5329},13,[436,5331,5205],{"class":5163},[347,5333,4663],{"id":5334},"risk-assessment-3",[415,5336,5337,5342,5347],{},[418,5338,5339,5341],{},[308,5340,4670],{},": Medium",[418,5343,5344,5346],{},[308,5345,4676],{},": Yes - method names and signatures changed",[418,5348,5349,5351],{},[308,5350,4685],{},": Low for most users; update required if extending ResourceController",[452,5353],{},[301,5355,5357],{"id":5356},"v1270-avior-minor","v1.27.0 - Avior (Minor)",[293,5359,5360],{},[308,5361,5362],{},"Released: February 4, 2026",[312,5364,5366],{"color":314,"icon":5365,"variant":316},"i-tabler-terminal-2",[318,5367,5368],{"v-slot:description":320},[293,5369,5370],{},"Developer experience improvements with new CLI commands, route cache signatures, database transaction callbacks, and extension management enhancements.",[347,5372,350],{"id":5373},"key-highlights-23",[352,5375,5376,5381],{},[293,5377,5378],{},[308,5379,5380],{},"New CLI Commands",[415,5382,5383,5389,5406,5421,5430,5436],{},[418,5384,5385,5388],{},[325,5386,5387],{},"doctor"," - Quick health checks for local development (env, cache, database, routes, storage)",[418,5390,5391,5394,5395,5397,5398,5401,5402,5405],{},[325,5392,5393],{},"env:sync"," - Sync ",[325,5396,4577],{}," from config ",[325,5399,5400],{},"env()"," usage with ",[325,5403,5404],{},"--apply"," option",[418,5407,5408,5410,5411,332,5414,332,5417,5420],{},[325,5409,5074],{}," - Dump resolved routes with ",[325,5412,5413],{},"--method",[325,5415,5416],{},"--path",[325,5418,5419],{},"--name"," filters",[418,5422,5423,392,5426,5429],{},[325,5424,5425],{},"route:cache:clear",[325,5427,5428],{},"route:cache:status"," - Route cache management",[418,5431,5432,5435],{},[325,5433,5434],{},"cache:inspect"," - Inspect cache driver and PHP extension status",[418,5437,5438,5441],{},[325,5439,5440],{},"test:watch"," - Run tests on file changes with configurable polling",[352,5443,5444,5449],{},[293,5445,5446],{},[308,5447,5448],{},"Database Transaction Callbacks",[415,5450,5451,5457,5463,5470],{},[418,5452,5453,5456],{},[325,5454,5455],{},"Connection::afterCommit(callable)"," - Execute callback after transaction commits",[418,5458,5459,5462],{},[325,5460,5461],{},"Connection::afterRollback(callable)"," - Execute callback after transaction rollback",[418,5464,5465,5466,5469],{},"Shared ",[325,5467,5468],{},"TransactionManager"," ensures consistent state across QueryBuilders",[418,5471,5472],{},"Callbacks promoted to parent level for nested transactions (savepoints)",[352,5474,5475,5480],{},[293,5476,5477],{},[308,5478,5479],{},"Route Cache Improvements",[415,5481,5482,5485,5488,5491],{},[418,5483,5484],{},"Signature-based invalidation replaces TTL-based caching",[418,5486,5487],{},"SHA-256 hash of route file paths, mtimes, and sizes",[418,5489,5490],{},"Cache invalidates automatically when any source file changes",[418,5492,5493],{},"Works consistently across all environments",[352,5495,5496,5501],{},[293,5497,5498],{},[308,5499,5500],{},"Extensions Enable/Disable",[415,5502,5503,5509,5519],{},[418,5504,5505,5506,5508],{},"Commands now edit ",[325,5507,892],{}," directly (dev only)",[418,5510,5511,5514,5515,5518],{},[325,5512,5513],{},"--dry-run"," to preview changes, ",[325,5516,5517],{},"--backup"," to create .bak file",[418,5520,5521],{},"Disable comments out provider line (safer for trailing commas)",[347,5523,5525],{"id":5524},"example-usage","Example Usage",[428,5527,5529],{"className":430,"code":5528,"language":432,"meta":320,"style":320},"# Quick health check\nphp glueful doctor\n\n# Sync env variables from config\nphp glueful env:sync --apply\n\n# Debug routes\nphp glueful route:debug --method=GET --path=/api\n\n# Enable extension with preview\nphp glueful extensions:enable Meilisearch --dry-run\n",[325,5530,5531,5536,5545,5549,5554,5567,5571,5576,5591,5595,5600],{"__ignoreMap":320},[436,5532,5533],{"class":438,"line":439},[436,5534,5535],{"class":1168},"# Quick health check\n",[436,5537,5538,5540,5542],{"class":438,"line":1132},[436,5539,1135],{"class":442},[436,5541,1138],{"class":446},[436,5543,5544],{"class":446}," doctor\n",[436,5546,5547],{"class":438,"line":1158},[436,5548,5212],{"emptyLinePlaceholder":5211},[436,5550,5551],{"class":438,"line":5196},[436,5552,5553],{"class":1168},"# Sync env variables from config\n",[436,5555,5556,5558,5560,5563],{"class":438,"line":5202},[436,5557,1135],{"class":442},[436,5559,1138],{"class":446},[436,5561,5562],{"class":446}," env:sync",[436,5564,5566],{"class":5565},"sFhLe"," --apply\n",[436,5568,5569],{"class":438,"line":5208},[436,5570,5212],{"emptyLinePlaceholder":5211},[436,5572,5573],{"class":438,"line":5215},[436,5574,5575],{"class":1168},"# Debug routes\n",[436,5577,5578,5580,5582,5585,5588],{"class":438,"line":5221},[436,5579,1135],{"class":442},[436,5581,1138],{"class":446},[436,5583,5584],{"class":446}," route:debug",[436,5586,5587],{"class":5565}," --method=GET",[436,5589,5590],{"class":5565}," --path=/api\n",[436,5592,5593],{"class":438,"line":5249},[436,5594,5212],{"emptyLinePlaceholder":5211},[436,5596,5597],{"class":438,"line":5254},[436,5598,5599],{"class":1168},"# Enable extension with preview\n",[436,5601,5602,5604,5606,5608,5611],{"class":438,"line":5298},[436,5603,1135],{"class":442},[436,5605,1138],{"class":446},[436,5607,1141],{"class":446},[436,5609,5610],{"class":446}," Meilisearch",[436,5612,5613],{"class":5565}," --dry-run\n",[347,5615,4663],{"id":5616},"risk-assessment-4",[415,5618,5619,5623,5627],{},[418,5620,5621,4671],{},[308,5622,4670],{},[418,5624,5625,4827],{},[308,5626,4676],{},[418,5628,5629,5631],{},[308,5630,4685],{},": None required",[452,5633],{},[301,5635,5637],{"id":5636},"v1260-atria-minor","v1.26.0 - Atria (Minor)",[293,5639,5640],{},[308,5641,5642],{},"Released: January 31, 2026",[312,5644,5646],{"color":314,"icon":5645,"variant":316},"i-tabler-plug",[318,5647,5648],{"v-slot:description":320},[293,5649,5650],{},"Fixed extension discovery reliability and improved ExtensionManager efficiency for CLI tools and documentation generation.",[347,5652,350],{"id":5653},"key-highlights-24",[352,5655,5656,5661],{},[293,5657,5658],{},[308,5659,5660],{},"Extension Discovery Fallback",[415,5662,5663,5677,5687],{},[418,5664,5665,5668,5669,5672,5673,5676],{},[325,5666,5667],{},"PackageManifest"," now falls back to ",[325,5670,5671],{},"installed.json"," when ",[325,5674,5675],{},"installed.php"," lacks provider metadata",[418,5678,5679,5680,5682,5683,5686],{},"Composer's optimized ",[325,5681,5675],{}," may omit the ",[325,5684,5685],{},"extra"," field where providers are specified",[418,5688,5689,5691],{},[325,5690,5671],{}," contains complete package metadata and is used as reliable fallback",[352,5693,5694,5699],{},[293,5695,5696],{},[308,5697,5698],{},"Lazy Auto-Discovery",[415,5700,5701,5707,5710],{},[418,5702,5703,5706],{},[325,5704,5705],{},"ExtensionManager::getProviders()"," now triggers discovery if not yet run",[418,5708,5709],{},"CLI commands that create their own container automatically discover extensions",[418,5711,5712],{},"Fixes empty provider lists in documentation generation and other CLI tools",[352,5714,5715,5720],{},[293,5716,5717],{},[308,5718,5719],{},"Discovery Efficiency",[415,5721,5722,5728,5731],{},[418,5723,5000,5724,5727],{},[325,5725,5726],{},"$discovered"," flag to ensure discovery runs exactly once",[418,5729,5730],{},"Prevents redundant discovery when zero extensions are legitimately installed",[418,5732,5733],{},"More efficient than checking for empty providers array",[347,5735,5737],{"id":5736},"technical-details","Technical Details",[293,5739,5740,5741,5743,5744,5746],{},"The issue occurred because Composer's ",[325,5742,5675],{}," (used for fast autoloading) doesn't always include the ",[325,5745,5685],{}," field where Glueful extension providers are declared. The fix adds a fallback:",[428,5748,5750],{"className":5139,"code":5749,"language":1135,"meta":320,"style":320},"// PackageManifest::discover()\n$providers = $this->extractFromInstalledPhp($installed);\nif ($providers !== []) {\n    return $providers;\n}\n// Fallback to installed.json which has complete metadata\nreturn $this->extractFromInstalledJson();\n",[325,5751,5752,5757,5784,5804,5817,5821,5826],{"__ignoreMap":320},[436,5753,5754],{"class":438,"line":439},[436,5755,5756],{"class":1168},"// PackageManifest::discover()\n",[436,5758,5759,5762,5765,5767,5771,5773,5776,5779,5782],{"class":438,"line":1132},[436,5760,5761],{"class":5163},"$",[436,5763,5764],{"class":1151},"providers ",[436,5766,3168],{"class":1144},[436,5768,5770],{"class":5769},"sSBr1"," $this",[436,5772,5269],{"class":1144},[436,5774,5775],{"class":5159},"extractFromInstalledPhp",[436,5777,5778],{"class":5163},"($",[436,5780,5781],{"class":1151},"installed",[436,5783,5295],{"class":5163},[436,5785,5786,5790,5793,5795,5798,5801],{"class":438,"line":1158},[436,5787,5789],{"class":5788},"sRxSC","if",[436,5791,5792],{"class":5163}," ($",[436,5794,5764],{"class":1151},[436,5796,5797],{"class":1144},"!==",[436,5799,5800],{"class":5163}," [])",[436,5802,5803],{"class":5163}," {\n",[436,5805,5806,5809,5811,5814],{"class":438,"line":5196},[436,5807,5808],{"class":5788},"    return",[436,5810,5171],{"class":5163},[436,5812,5813],{"class":1151},"providers",[436,5815,5816],{"class":5163},";\n",[436,5818,5819],{"class":438,"line":5202},[436,5820,5205],{"class":5163},[436,5822,5823],{"class":438,"line":5208},[436,5824,5825],{"class":1168},"// Fallback to installed.json which has complete metadata\n",[436,5827,5828,5831,5833,5835,5838],{"class":438,"line":5215},[436,5829,5830],{"class":5788},"return",[436,5832,5770],{"class":5769},[436,5834,5269],{"class":1144},[436,5836,5837],{"class":5159},"extractFromInstalledJson",[436,5839,5321],{"class":5163},[347,5841,4663],{"id":5842},"risk-assessment-5",[415,5844,5845,5849,5853],{},[418,5846,5847,4671],{},[308,5848,4670],{},[418,5850,5851,4827],{},[308,5852,4676],{},[418,5854,5855,5631],{},[308,5856,4685],{},[452,5858],{},[301,5860,5862],{"id":5861},"v1250-ankaa-minor","v1.25.0 - Ankaa (Minor)",[293,5864,5865],{},[308,5866,5642],{},[312,5868,5869],{"color":314,"icon":676,"variant":316},[318,5870,5871],{"v-slot:description":320},[293,5872,5873],{},"Enhanced RouteManifest with automatic discovery of multiple application route files, enabling domain-driven route organization.",[347,5875,350],{"id":5876},"key-highlights-25",[352,5878,5879,5884],{},[293,5880,5881],{},[308,5882,5883],{},"Multi-File Route Discovery",[415,5885,5886,5896,5899,5906],{},[418,5887,4783,5888,5891,5892,5895],{},[325,5889,5890],{},"*.php"," files in ",[325,5893,5894],{},"routes/"," directory auto-discovered",[418,5897,5898],{},"Alphabetical loading order for deterministic behavior",[418,5900,5901,5902,5905],{},"Files starting with underscore (",[325,5903,5904],{},"_helpers.php",") excluded as partials",[418,5907,5908],{},"Double-load prevention tracks files to avoid duplicate registration",[352,5910,5911,5916],{},[293,5912,5913],{},[308,5914,5915],{},"Route Loading Priority",[415,5917,5918,5921,5924],{},[418,5919,5920],{},"Application routes load first (highest priority)",[418,5922,5923],{},"Framework API routes load second (act as fallbacks)",[418,5925,5926],{},"Public routes (health, docs) load last without prefix",[352,5928,5929,5934],{},[293,5930,5931],{},[308,5932,5933],{},"Domain-Driven Organization",[415,5935,5936,5939,5949],{},[418,5937,5938],{},"Split large route files into domain-specific files",[418,5940,5941,5942,542,5945,5948],{},"Each file receives ",[325,5943,5944],{},"$router",[325,5946,5947],{},"$context"," in scope",[418,5950,5951],{},"Full control over prefixes per file",[347,5953,5955],{"id":5954},"example-structure","Example Structure",[428,5957,5961],{"className":5958,"code":5960,"language":2016},[5959],"language-text","routes/\n├── api.php           # Main/shared routes\n├── identity.php      # Auth, profile, preferences\n├── parps.php         # Domain-specific routes\n├── social.php        # Follow, block\n├── engagement.php    # Reactions, comments, bookmarks\n├── moderation.php    # Reports\n└── _helpers.php      # Shared helpers (excluded from auto-load)\n",[325,5962,5960],{"__ignoreMap":320},[347,5964,5966],{"id":5965},"usage","Usage",[428,5968,5970],{"className":5139,"code":5969,"language":1135,"meta":320,"style":320},"// routes/identity.php\n$router->group(['prefix' => api_prefix($context)], function (Router $router) {\n    $router->post('/auth/login', [AuthController::class, 'login']);\n    $router->post('/auth/register', [AuthController::class, 'register']);\n    $router->get('/profile', [ProfileController::class, 'show']);\n});\n\n// routes/social.php\n$router->group(['prefix' => api_prefix($context)], function (Router $router) {\n    $router->post('/follow/{uuid}', [FollowController::class, 'follow']);\n    $router->delete('/follow/{uuid}', [FollowController::class, 'unfollow']);\n});\n",[325,5971,5972,5977,6027,6073,6113,6153,6158,6162,6167,6209,6250,6289],{"__ignoreMap":320},[436,5973,5974],{"class":438,"line":439},[436,5975,5976],{"class":1168},"// routes/identity.php\n",[436,5978,5979,5981,5984,5986,5988,5991,5993,5996,5998,6001,6004,6006,6009,6012,6014,6016,6019,6021,6023,6025],{"class":438,"line":1132},[436,5980,5761],{"class":5163},[436,5982,5983],{"class":1151},"router",[436,5985,5269],{"class":1144},[436,5987,338],{"class":5159},[436,5989,5990],{"class":5163},"([",[436,5992,5282],{"class":5281},[436,5994,5995],{"class":446},"prefix",[436,5997,5282],{"class":5281},[436,5999,6000],{"class":1144}," =>",[436,6002,6003],{"class":5159}," api_prefix",[436,6005,5778],{"class":5163},[436,6007,6008],{"class":1151},"context",[436,6010,6011],{"class":5163},")],",[436,6013,5156],{"class":5155},[436,6015,388],{"class":5163},[436,6017,6018],{"class":5233},"Router",[436,6020,5171],{"class":5163},[436,6022,5983],{"class":1151},[436,6024,4887],{"class":5163},[436,6026,5803],{"class":5163},[436,6028,6029,6031,6033,6035,6037,6039,6041,6044,6046,6048,6051,6054,6057,6060,6062,6065,6068,6070],{"class":438,"line":1158},[436,6030,5257],{"class":5163},[436,6032,5983],{"class":1151},[436,6034,5269],{"class":1144},[436,6036,718],{"class":5159},[436,6038,5164],{"class":5163},[436,6040,5282],{"class":5281},[436,6042,6043],{"class":446},"/auth/login",[436,6045,5282],{"class":5281},[436,6047,5177],{"class":5163},[436,6049,6050],{"class":5163}," [",[436,6052,6053],{"class":5233},"AuthController",[436,6055,6056],{"class":1144},"::",[436,6058,6059],{"class":5167},"class",[436,6061,5177],{"class":5163},[436,6063,6064],{"class":5281}," '",[436,6066,6067],{"class":446},"login",[436,6069,5282],{"class":5281},[436,6071,6072],{"class":5163},"]);\n",[436,6074,6075,6077,6079,6081,6083,6085,6087,6090,6092,6094,6096,6098,6100,6102,6104,6106,6109,6111],{"class":438,"line":5196},[436,6076,5257],{"class":5163},[436,6078,5983],{"class":1151},[436,6080,5269],{"class":1144},[436,6082,718],{"class":5159},[436,6084,5164],{"class":5163},[436,6086,5282],{"class":5281},[436,6088,6089],{"class":446},"/auth/register",[436,6091,5282],{"class":5281},[436,6093,5177],{"class":5163},[436,6095,6050],{"class":5163},[436,6097,6053],{"class":5233},[436,6099,6056],{"class":1144},[436,6101,6059],{"class":5167},[436,6103,5177],{"class":5163},[436,6105,6064],{"class":5281},[436,6107,6108],{"class":446},"register",[436,6110,5282],{"class":5281},[436,6112,6072],{"class":5163},[436,6114,6115,6117,6119,6121,6123,6125,6127,6130,6132,6134,6136,6139,6141,6143,6145,6147,6149,6151],{"class":438,"line":5202},[436,6116,5257],{"class":5163},[436,6118,5983],{"class":1151},[436,6120,5269],{"class":1144},[436,6122,715],{"class":5159},[436,6124,5164],{"class":5163},[436,6126,5282],{"class":5281},[436,6128,6129],{"class":446},"/profile",[436,6131,5282],{"class":5281},[436,6133,5177],{"class":5163},[436,6135,6050],{"class":5163},[436,6137,6138],{"class":5233},"ProfileController",[436,6140,6056],{"class":1144},[436,6142,6059],{"class":5167},[436,6144,5177],{"class":5163},[436,6146,6064],{"class":5281},[436,6148,4988],{"class":446},[436,6150,5282],{"class":5281},[436,6152,6072],{"class":5163},[436,6154,6155],{"class":438,"line":5208},[436,6156,6157],{"class":5163},"});\n",[436,6159,6160],{"class":438,"line":5215},[436,6161,5212],{"emptyLinePlaceholder":5211},[436,6163,6164],{"class":438,"line":5221},[436,6165,6166],{"class":1168},"// routes/social.php\n",[436,6168,6169,6171,6173,6175,6177,6179,6181,6183,6185,6187,6189,6191,6193,6195,6197,6199,6201,6203,6205,6207],{"class":438,"line":5249},[436,6170,5761],{"class":5163},[436,6172,5983],{"class":1151},[436,6174,5269],{"class":1144},[436,6176,338],{"class":5159},[436,6178,5990],{"class":5163},[436,6180,5282],{"class":5281},[436,6182,5995],{"class":446},[436,6184,5282],{"class":5281},[436,6186,6000],{"class":1144},[436,6188,6003],{"class":5159},[436,6190,5778],{"class":5163},[436,6192,6008],{"class":1151},[436,6194,6011],{"class":5163},[436,6196,5156],{"class":5155},[436,6198,388],{"class":5163},[436,6200,6018],{"class":5233},[436,6202,5171],{"class":5163},[436,6204,5983],{"class":1151},[436,6206,4887],{"class":5163},[436,6208,5803],{"class":5163},[436,6210,6211,6213,6215,6217,6219,6221,6223,6226,6228,6230,6232,6235,6237,6239,6241,6243,6246,6248],{"class":438,"line":5254},[436,6212,5257],{"class":5163},[436,6214,5983],{"class":1151},[436,6216,5269],{"class":1144},[436,6218,718],{"class":5159},[436,6220,5164],{"class":5163},[436,6222,5282],{"class":5281},[436,6224,6225],{"class":446},"/follow/{uuid}",[436,6227,5282],{"class":5281},[436,6229,5177],{"class":5163},[436,6231,6050],{"class":5163},[436,6233,6234],{"class":5233},"FollowController",[436,6236,6056],{"class":1144},[436,6238,6059],{"class":5167},[436,6240,5177],{"class":5163},[436,6242,6064],{"class":5281},[436,6244,6245],{"class":446},"follow",[436,6247,5282],{"class":5281},[436,6249,6072],{"class":5163},[436,6251,6252,6254,6256,6258,6260,6262,6264,6266,6268,6270,6272,6274,6276,6278,6280,6282,6285,6287],{"class":438,"line":5298},[436,6253,5257],{"class":5163},[436,6255,5983],{"class":1151},[436,6257,5269],{"class":1144},[436,6259,724],{"class":5159},[436,6261,5164],{"class":5163},[436,6263,5282],{"class":5281},[436,6265,6225],{"class":446},[436,6267,5282],{"class":5281},[436,6269,5177],{"class":5163},[436,6271,6050],{"class":5163},[436,6273,6234],{"class":5233},[436,6275,6056],{"class":1144},[436,6277,6059],{"class":5167},[436,6279,5177],{"class":5163},[436,6281,6064],{"class":5281},[436,6283,6284],{"class":446},"unfollow",[436,6286,5282],{"class":5281},[436,6288,6072],{"class":5163},[436,6290,6291],{"class":438,"line":5324},[436,6292,6157],{"class":5163},[347,6294,4663],{"id":6295},"risk-assessment-6",[415,6297,6298,6302,6306],{},[418,6299,6300,4671],{},[308,6301,4670],{},[418,6303,6304,4827],{},[308,6305,4676],{},[418,6307,6308,6310],{},[308,6309,4685],{},": None required (backward compatible with single route file)",[452,6312],{},[301,6314,6316],{"id":6315},"v1240-alpheratz-minor","v1.24.0 - Alpheratz (Minor)",[293,6318,6319],{},[308,6320,5642],{},[312,6322,6323],{"color":314,"icon":465,"variant":316},[318,6324,6325],{"v-slot:description":320},[293,6326,6327],{},"Comprehensive encryption service providing secure, easy-to-use AES-256-GCM encryption for strings, files, and database fields with key rotation support.",[347,6329,350],{"id":6330},"key-highlights-26",[352,6332,6333,6338],{},[293,6334,6335],{},[308,6336,6337],{},"EncryptionService Core",[415,6339,6340,6343,6346,6349,6352],{},[418,6341,6342],{},"AES-256-GCM authenticated encryption (industry standard)",[418,6344,6345],{},"Random 12-byte nonce per encryption (prevents ciphertext repetition)",[418,6347,6348],{},"16-byte authentication tag for tamper detection",[418,6350,6351],{},"Key ID in output format enables O(1) key lookup during rotation",[418,6353,6354,6355],{},"Self-identifying format: ",[325,6356,6357],{},"$glueful$v1$\u003Ckey_id>$\u003Cnonce>$\u003Cciphertext>$\u003Ctag>",[352,6359,6360,6365],{},[293,6361,6362],{},[308,6363,6364],{},"String & Binary Encryption",[415,6366,6367,6376,6385,6391],{},[418,6368,6369,392,6372,6375],{},[325,6370,6371],{},"encrypt($value, $aad)",[325,6373,6374],{},"decrypt($encrypted, $aad)"," for UTF-8 strings",[418,6377,6378,392,6381,6384],{},[325,6379,6380],{},"encryptBinary()",[325,6382,6383],{},"decryptBinary()"," for arbitrary binary data",[418,6386,6387,6390],{},[325,6388,6389],{},"isEncrypted($value)"," to detect encrypted strings by format",[418,6392,6393],{},"AAD (Additional Authenticated Data) binding prevents cross-field attacks",[352,6395,6396,6401],{},[293,6397,6398],{},[308,6399,6400],{},"File Encryption",[415,6402,6403,6409,6415],{},[418,6404,6405,6408],{},[325,6406,6407],{},"encryptFile($source, $dest)"," - Encrypt entire files",[418,6410,6411,6414],{},[325,6412,6413],{},"decryptFile($source, $dest)"," - Decrypt encrypted files",[418,6416,6417,6418],{},"CLI: ",[325,6419,6420],{},"php glueful encryption:file encrypt /path/to/file",[352,6422,6423,6428],{},[293,6424,6425],{},[308,6426,6427],{},"Key Rotation",[415,6429,6430,6436,6439,6444],{},[418,6431,6432,6435],{},[325,6433,6434],{},"encryption.previous_keys"," config array for old keys",[418,6437,6438],{},"O(1) key lookup via key ID (no trial decryption needed)",[418,6440,6417,6441],{},[325,6442,6443],{},"php glueful encryption:rotate --table=users --columns=ssn,api_key",[418,6445,6446],{},"Seamless migration: old data decrypts with previous keys",[352,6448,6449,6454],{},[293,6450,6451],{},[308,6452,6453],{},"CLI Commands",[415,6455,6456,6462,6474],{},[418,6457,6458,6461],{},[325,6459,6460],{},"encryption:test"," - Verify encryption is working (6 self-tests)",[418,6463,6464,6467,6468,332,6471],{},[325,6465,6466],{},"encryption:file"," - Encrypt/decrypt files with ",[325,6469,6470],{},"--force",[325,6472,6473],{},"--delete-source",[418,6475,6476,6479,6480,332,6483],{},[325,6477,6478],{},"encryption:rotate"," - Re-encrypt database columns with ",[325,6481,6482],{},"--batch-size",[325,6484,5513],{},[352,6486,6487,6492],{},[293,6488,6489],{},[308,6490,6491],{},"Test Coverage",[415,6493,6494,6497,6500],{},[418,6495,6496],{},"32 unit tests covering all functionality",[418,6498,6499],{},"Core encryption, AAD binding, key validation, binary handling",[418,6501,6502],{},"Key rotation, file encryption, error handling",[347,6504,6506],{"id":6505},"usage-example","Usage Example",[428,6508,6510],{"className":5139,"code":6509,"language":1135,"meta":320,"style":320},"use Glueful\\Encryption\\EncryptionService;\n\n$encryption = new EncryptionService($context);\n\n// Basic encryption\n$encrypted = $encryption->encrypt('sensitive data');\n$decrypted = $encryption->decrypt($encrypted);\n\n// With AAD (prevents cross-field attacks)\n$encrypted = $encryption->encrypt($ssn, aad: 'user.ssn');\n$decrypted = $encryption->decrypt($encrypted, aad: 'user.ssn');\n\n// Binary data\n$encrypted = $encryption->encryptBinary($binaryData);\n$binary = $encryption->decryptBinary($encrypted);\n\n// File encryption\n$encryption->encryptFile('/path/to/file', '/path/to/file.enc');\n$encryption->decryptFile('/path/to/file.enc', '/path/to/file');\n",[325,6511,6512,6536,6540,6561,6565,6570,6600,6625,6629,6634,6672,6706,6710,6715,6740,6765,6770,6776,6808],{"__ignoreMap":320},[436,6513,6514,6517,6521,6525,6528,6530,6534],{"class":438,"line":439},[436,6515,6516],{"class":5167},"use",[436,6518,6520],{"class":6519},"s91G_"," Glueful",[436,6522,6524],{"class":6523},"sv8o3","\\",[436,6526,6527],{"class":6519},"Encryption",[436,6529,6524],{"class":6523},[436,6531,6533],{"class":6532},"seZir","EncryptionService",[436,6535,5816],{"class":5163},[436,6537,6538],{"class":438,"line":1132},[436,6539,5212],{"emptyLinePlaceholder":5211},[436,6541,6542,6544,6547,6549,6552,6555,6557,6559],{"class":438,"line":1158},[436,6543,5761],{"class":5163},[436,6545,6546],{"class":1151},"encryption ",[436,6548,3168],{"class":1144},[436,6550,6551],{"class":5167}," new",[436,6553,6554],{"class":5233}," EncryptionService",[436,6556,5778],{"class":5163},[436,6558,6008],{"class":1151},[436,6560,5295],{"class":5163},[436,6562,6563],{"class":438,"line":5196},[436,6564,5212],{"emptyLinePlaceholder":5211},[436,6566,6567],{"class":438,"line":5202},[436,6568,6569],{"class":1168},"// Basic encryption\n",[436,6571,6572,6574,6577,6579,6581,6584,6586,6589,6591,6593,6596,6598],{"class":438,"line":5208},[436,6573,5761],{"class":5163},[436,6575,6576],{"class":1151},"encrypted ",[436,6578,3168],{"class":1144},[436,6580,5171],{"class":5163},[436,6582,6583],{"class":1151},"encryption",[436,6585,5269],{"class":1144},[436,6587,6588],{"class":5159},"encrypt",[436,6590,5164],{"class":5163},[436,6592,5282],{"class":5281},[436,6594,6595],{"class":446},"sensitive data",[436,6597,5282],{"class":5281},[436,6599,5295],{"class":5163},[436,6601,6602,6604,6607,6609,6611,6613,6615,6618,6620,6623],{"class":438,"line":5215},[436,6603,5761],{"class":5163},[436,6605,6606],{"class":1151},"decrypted ",[436,6608,3168],{"class":1144},[436,6610,5171],{"class":5163},[436,6612,6583],{"class":1151},[436,6614,5269],{"class":1144},[436,6616,6617],{"class":5159},"decrypt",[436,6619,5778],{"class":5163},[436,6621,6622],{"class":1151},"encrypted",[436,6624,5295],{"class":5163},[436,6626,6627],{"class":438,"line":5221},[436,6628,5212],{"emptyLinePlaceholder":5211},[436,6630,6631],{"class":438,"line":5249},[436,6632,6633],{"class":1168},"// With AAD (prevents cross-field attacks)\n",[436,6635,6636,6638,6640,6642,6644,6646,6648,6650,6652,6655,6657,6661,6663,6665,6668,6670],{"class":438,"line":5254},[436,6637,5761],{"class":5163},[436,6639,6576],{"class":1151},[436,6641,3168],{"class":1144},[436,6643,5171],{"class":5163},[436,6645,6583],{"class":1151},[436,6647,5269],{"class":1144},[436,6649,6588],{"class":5159},[436,6651,5778],{"class":5163},[436,6653,6654],{"class":1151},"ssn",[436,6656,5177],{"class":5163},[436,6658,6660],{"class":6659},"sQqfL"," aad",[436,6662,5243],{"class":5163},[436,6664,6064],{"class":5281},[436,6666,6667],{"class":446},"user.ssn",[436,6669,5282],{"class":5281},[436,6671,5295],{"class":5163},[436,6673,6674,6676,6678,6680,6682,6684,6686,6688,6690,6692,6694,6696,6698,6700,6702,6704],{"class":438,"line":5298},[436,6675,5761],{"class":5163},[436,6677,6606],{"class":1151},[436,6679,3168],{"class":1144},[436,6681,5171],{"class":5163},[436,6683,6583],{"class":1151},[436,6685,5269],{"class":1144},[436,6687,6617],{"class":5159},[436,6689,5778],{"class":5163},[436,6691,6622],{"class":1151},[436,6693,5177],{"class":5163},[436,6695,6660],{"class":6659},[436,6697,5243],{"class":5163},[436,6699,6064],{"class":5281},[436,6701,6667],{"class":446},[436,6703,5282],{"class":5281},[436,6705,5295],{"class":5163},[436,6707,6708],{"class":438,"line":5324},[436,6709,5212],{"emptyLinePlaceholder":5211},[436,6711,6712],{"class":438,"line":5329},[436,6713,6714],{"class":1168},"// Binary data\n",[436,6716,6718,6720,6722,6724,6726,6728,6730,6733,6735,6738],{"class":438,"line":6717},14,[436,6719,5761],{"class":5163},[436,6721,6576],{"class":1151},[436,6723,3168],{"class":1144},[436,6725,5171],{"class":5163},[436,6727,6583],{"class":1151},[436,6729,5269],{"class":1144},[436,6731,6732],{"class":5159},"encryptBinary",[436,6734,5778],{"class":5163},[436,6736,6737],{"class":1151},"binaryData",[436,6739,5295],{"class":5163},[436,6741,6743,6745,6748,6750,6752,6754,6756,6759,6761,6763],{"class":438,"line":6742},15,[436,6744,5761],{"class":5163},[436,6746,6747],{"class":1151},"binary ",[436,6749,3168],{"class":1144},[436,6751,5171],{"class":5163},[436,6753,6583],{"class":1151},[436,6755,5269],{"class":1144},[436,6757,6758],{"class":5159},"decryptBinary",[436,6760,5778],{"class":5163},[436,6762,6622],{"class":1151},[436,6764,5295],{"class":5163},[436,6766,6768],{"class":438,"line":6767},16,[436,6769,5212],{"emptyLinePlaceholder":5211},[436,6771,6773],{"class":438,"line":6772},17,[436,6774,6775],{"class":1168},"// File encryption\n",[436,6777,6779,6781,6783,6785,6788,6790,6792,6795,6797,6799,6801,6804,6806],{"class":438,"line":6778},18,[436,6780,5761],{"class":5163},[436,6782,6583],{"class":1151},[436,6784,5269],{"class":1144},[436,6786,6787],{"class":5159},"encryptFile",[436,6789,5164],{"class":5163},[436,6791,5282],{"class":5281},[436,6793,6794],{"class":446},"/path/to/file",[436,6796,5282],{"class":5281},[436,6798,5177],{"class":5163},[436,6800,6064],{"class":5281},[436,6802,6803],{"class":446},"/path/to/file.enc",[436,6805,5282],{"class":5281},[436,6807,5295],{"class":5163},[436,6809,6811,6813,6815,6817,6820,6822,6824,6826,6828,6830,6832,6834,6836],{"class":438,"line":6810},19,[436,6812,5761],{"class":5163},[436,6814,6583],{"class":1151},[436,6816,5269],{"class":1144},[436,6818,6819],{"class":5159},"decryptFile",[436,6821,5164],{"class":5163},[436,6823,5282],{"class":5281},[436,6825,6803],{"class":446},[436,6827,5282],{"class":5281},[436,6829,5177],{"class":5163},[436,6831,6064],{"class":5281},[436,6833,6794],{"class":446},[436,6835,5282],{"class":5281},[436,6837,5295],{"class":5163},[347,6839,121],{"id":6840},"configuration",[428,6842,6844],{"className":5139,"code":6843,"language":1135,"meta":320,"style":320},"// config/encryption.php\nreturn [\n    'key' => env('APP_KEY'),  // base64:... format supported\n    'cipher' => 'aes-256-gcm',\n    'previous_keys' => array_filter(\n        explode(',', env('APP_PREVIOUS_KEYS', ''))\n    ),\n];\n",[325,6845,6846,6851,6858,6887,6908,6926,6959,6964],{"__ignoreMap":320},[436,6847,6848],{"class":438,"line":439},[436,6849,6850],{"class":1168},"// config/encryption.php\n",[436,6852,6853,6855],{"class":438,"line":1132},[436,6854,5830],{"class":5788},[436,6856,6857],{"class":5163}," [\n",[436,6859,6860,6863,6865,6867,6869,6872,6874,6876,6879,6881,6884],{"class":438,"line":1158},[436,6861,6862],{"class":5281},"    '",[436,6864,341],{"class":446},[436,6866,5282],{"class":5281},[436,6868,6000],{"class":1144},[436,6870,6871],{"class":5159}," env",[436,6873,5164],{"class":5163},[436,6875,5282],{"class":5281},[436,6877,6878],{"class":446},"APP_KEY",[436,6880,5282],{"class":5281},[436,6882,6883],{"class":5163},"),",[436,6885,6886],{"class":1168},"  // base64:... format supported\n",[436,6888,6889,6891,6894,6896,6898,6900,6903,6905],{"class":438,"line":5196},[436,6890,6862],{"class":5281},[436,6892,6893],{"class":446},"cipher",[436,6895,5282],{"class":5281},[436,6897,6000],{"class":1144},[436,6899,6064],{"class":5281},[436,6901,6902],{"class":446},"aes-256-gcm",[436,6904,5282],{"class":5281},[436,6906,6907],{"class":5163},",\n",[436,6909,6910,6912,6915,6917,6919,6923],{"class":438,"line":5202},[436,6911,6862],{"class":5281},[436,6913,6914],{"class":446},"previous_keys",[436,6916,5282],{"class":5281},[436,6918,6000],{"class":1144},[436,6920,6922],{"class":6921},"sMLJd"," array_filter",[436,6924,6925],{"class":5163},"(\n",[436,6927,6928,6931,6933,6935,6937,6939,6941,6943,6945,6947,6950,6952,6954,6956],{"class":438,"line":5208},[436,6929,6930],{"class":6921},"        explode",[436,6932,5164],{"class":5163},[436,6934,5282],{"class":5281},[436,6936,5177],{"class":446},[436,6938,5282],{"class":5281},[436,6940,5177],{"class":5163},[436,6942,6871],{"class":5159},[436,6944,5164],{"class":5163},[436,6946,5282],{"class":5281},[436,6948,6949],{"class":446},"APP_PREVIOUS_KEYS",[436,6951,5282],{"class":5281},[436,6953,5177],{"class":5163},[436,6955,5292],{"class":5281},[436,6957,6958],{"class":5163},"))\n",[436,6960,6961],{"class":438,"line":5215},[436,6962,6963],{"class":5163},"    ),\n",[436,6965,6966],{"class":438,"line":5221},[436,6967,6968],{"class":5163},"];\n",[347,6970,4663],{"id":6971},"risk-assessment-7",[415,6973,6974,6978,6982],{},[418,6975,6976,4671],{},[308,6977,4670],{},[418,6979,6980,4827],{},[308,6981,4676],{},[418,6983,6984,6986],{},[308,6985,4685],{},": None required (opt-in feature)",[452,6988],{},[301,6990,6992],{"id":6991},"v1230-aldebaran-minor","v1.23.0 - Aldebaran (Minor)",[293,6994,6995],{},[308,6996,5642],{},[312,6998,6999],{"color":314,"icon":1357,"variant":316},[318,7000,7001],{"v-slot:description":320},[293,7002,7003],{},"Enhanced blob storage system with per-blob visibility controls, HMAC-signed URLs for secure temporary access, and comprehensive test coverage.",[347,7005,350],{"id":7006},"key-highlights-27",[352,7008,7009,7014],{},[293,7010,7011],{},[308,7012,7013],{},"Per-Blob Visibility",[415,7015,7016,7024,7031,7038,7043],{},[418,7017,7018,7019,373,7021,7023],{},"Blobs can now be marked as ",[325,7020,4794],{},[325,7022,3824],{}," individually",[418,7025,7026,7027,7030],{},"Upload requests accept ",[325,7028,7029],{},"visibility"," parameter",[418,7032,7033,7034,7037],{},"Defaults to configured ",[325,7035,7036],{},"uploads.default_visibility"," (private)",[418,7039,7040,7041,4887],{},"Public blobs accessible without auth (unless global access is ",[325,7042,3824],{},[418,7044,7045],{},"Private blobs require authentication or valid signed URL",[352,7047,7048,7053],{},[293,7049,7050],{},[308,7051,7052],{},"Signed URL Support",[415,7054,7055,7061,7064,7070,7073],{},[418,7056,705,7057,7060],{},[325,7058,7059],{},"SignedUrl"," helper class for HMAC-based URL signing",[418,7062,7063],{},"Time-limited access with customizable TTL (default 1 hour, max 7 days)",[418,7065,7066,7067],{},"New endpoint: ",[325,7068,7069],{},"POST /blobs/{uuid}/signed-url",[418,7071,7072],{},"Automatic signature validation on blob retrieval",[418,7074,7075,7076,7078],{},"Falls back to ",[325,7077,6878],{}," if no dedicated secret configured",[352,7080,7081,7086],{},[293,7082,7083],{},[308,7084,7085],{},"Configuration Options",[415,7087,7088,7093,7099,7105],{},[418,7089,7090,7092],{},[325,7091,7036],{}," - Set default visibility for new uploads",[418,7094,7095,7098],{},[325,7096,7097],{},"uploads.signed_urls.enabled"," - Enable/disable signed URL generation",[418,7100,7101,7104],{},[325,7102,7103],{},"uploads.signed_urls.secret"," - Dedicated secret for URL signing",[418,7106,7107,7110],{},[325,7108,7109],{},"uploads.signed_urls.ttl"," - Default TTL in seconds (default: 3600)",[352,7112,7113,7118],{},[293,7114,7115],{},[308,7116,7117],{},"Comprehensive Test Coverage",[415,7119,7120,7126,7132],{},[418,7121,7122,7125],{},[325,7123,7124],{},"SignedUrlTest"," - 17 tests covering URL generation, validation, expiration, tampering",[418,7127,7128,7131],{},[325,7129,7130],{},"UploadControllerTest"," - 38 tests covering resize params, caching, access control, visibility",[418,7133,7134],{},"Total: 55 new tests with 95 assertions",[347,7136,6506],{"id":7137},"usage-example-1",[428,7139,7141],{"className":5139,"code":7140,"language":1135,"meta":320,"style":320},"// Upload with visibility\nPOST /blobs\n{\n    \"file\": \"...\",\n    \"visibility\": \"private\"\n}\n\n// Generate signed URL for temporary access\nPOST /blobs/{uuid}/signed-url?ttl=7200\n\n// Response\n{\n    \"uuid\": \"abc123\",\n    \"signed_url\": \"https://example.com/blobs/abc123?expires=...&signature=...\",\n    \"expires_in\": 7200,\n    \"expires_at\": \"2026-01-31 14:00:00\"\n}\n",[325,7142,7143,7148,7160,7164,7187,7204,7208,7212,7217,7258,7262,7267,7271,7290,7310,7326,7343],{"__ignoreMap":320},[436,7144,7145],{"class":438,"line":439},[436,7146,7147],{"class":1168},"// Upload with visibility\n",[436,7149,7150,7154,7157],{"class":438,"line":1132},[436,7151,7153],{"class":7152},"sQeA1","POST",[436,7155,7156],{"class":1144}," /",[436,7158,7159],{"class":7152},"blobs\n",[436,7161,7162],{"class":438,"line":1158},[436,7163,5193],{"class":5163},[436,7165,7166,7169,7172,7175,7177,7180,7183,7185],{"class":438,"line":5196},[436,7167,7168],{"class":5281},"    \"",[436,7170,7171],{"class":446},"file",[436,7173,7174],{"class":5281},"\"",[436,7176,5243],{"class":5163},[436,7178,7179],{"class":5281}," \"",[436,7181,7182],{"class":446},"...",[436,7184,7174],{"class":5281},[436,7186,6907],{"class":5163},[436,7188,7189,7191,7193,7195,7197,7199,7201],{"class":438,"line":5202},[436,7190,7168],{"class":5281},[436,7192,7029],{"class":446},[436,7194,7174],{"class":5281},[436,7196,5243],{"class":5163},[436,7198,7179],{"class":5281},[436,7200,3824],{"class":446},[436,7202,7203],{"class":5281},"\"\n",[436,7205,7206],{"class":438,"line":5208},[436,7207,5205],{"class":5163},[436,7209,7210],{"class":438,"line":5215},[436,7211,5212],{"emptyLinePlaceholder":5211},[436,7213,7214],{"class":438,"line":5221},[436,7215,7216],{"class":1168},"// Generate signed URL for temporary access\n",[436,7218,7219,7221,7223,7226,7228,7231,7233,7236,7238,7241,7244,7247,7249,7252,7254],{"class":438,"line":5249},[436,7220,7153],{"class":7152},[436,7222,7156],{"class":1144},[436,7224,7225],{"class":7152},"blobs",[436,7227,380],{"class":1144},[436,7229,7230],{"class":5163},"{",[436,7232,1818],{"class":7152},[436,7234,7235],{"class":5163},"}",[436,7237,380],{"class":1144},[436,7239,7240],{"class":7152},"signed",[436,7242,7243],{"class":1144},"-",[436,7245,7246],{"class":7152},"url",[436,7248,1557],{"class":1144},[436,7250,7251],{"class":7152},"ttl",[436,7253,3168],{"class":1144},[436,7255,7257],{"class":7256},"sYThS","7200\n",[436,7259,7260],{"class":438,"line":5254},[436,7261,5212],{"emptyLinePlaceholder":5211},[436,7263,7264],{"class":438,"line":5298},[436,7265,7266],{"class":1168},"// Response\n",[436,7268,7269],{"class":438,"line":5324},[436,7270,5193],{"class":5163},[436,7272,7273,7275,7277,7279,7281,7283,7286,7288],{"class":438,"line":5329},[436,7274,7168],{"class":5281},[436,7276,1818],{"class":446},[436,7278,7174],{"class":5281},[436,7280,5243],{"class":5163},[436,7282,7179],{"class":5281},[436,7284,7285],{"class":446},"abc123",[436,7287,7174],{"class":5281},[436,7289,6907],{"class":5163},[436,7291,7292,7294,7297,7299,7301,7303,7306,7308],{"class":438,"line":6717},[436,7293,7168],{"class":5281},[436,7295,7296],{"class":446},"signed_url",[436,7298,7174],{"class":5281},[436,7300,5243],{"class":5163},[436,7302,7179],{"class":5281},[436,7304,7305],{"class":446},"https://example.com/blobs/abc123?expires=...&signature=...",[436,7307,7174],{"class":5281},[436,7309,6907],{"class":5163},[436,7311,7312,7314,7317,7319,7321,7324],{"class":438,"line":6742},[436,7313,7168],{"class":5281},[436,7315,7316],{"class":446},"expires_in",[436,7318,7174],{"class":5281},[436,7320,5243],{"class":5163},[436,7322,7323],{"class":7256}," 7200",[436,7325,6907],{"class":5163},[436,7327,7328,7330,7332,7334,7336,7338,7341],{"class":438,"line":6767},[436,7329,7168],{"class":5281},[436,7331,3670],{"class":446},[436,7333,7174],{"class":5281},[436,7335,5243],{"class":5163},[436,7337,7179],{"class":5281},[436,7339,7340],{"class":446},"2026-01-31 14:00:00",[436,7342,7203],{"class":5281},[436,7344,7345],{"class":438,"line":6772},[436,7346,5205],{"class":5163},[347,7348,4663],{"id":7349},"risk-assessment-8",[415,7351,7352,7356,7360],{},[418,7353,7354,4671],{},[308,7355,4670],{},[418,7357,7358,4827],{},[308,7359,4676],{},[418,7361,7362,5631],{},[308,7363,4685],{},[452,7365],{},[301,7367,7369],{"id":7368},"v1220-achernar-minor","v1.22.0 - Achernar (Minor)",[293,7371,7372],{},[308,7373,7374],{},"Released: January 30, 2026",[312,7376,7378],{"color":464,"icon":7377,"variant":316},"i-tabler-replace",[318,7379,7380],{"v-slot:description":320},[293,7381,7382,7383,7385],{},"Major refactoring release replacing global state with explicit dependency injection via ",[325,7384,2349],{},". Improves testability, enables multi-app support, and prepares for long-running server environments.",[347,7387,350],{"id":7388},"key-highlights-28",[352,7390,7391,7396],{},[293,7392,7393],{},[308,7394,7395],{},"ApplicationContext Dependency Injection",[415,7397,7398,7404,7415,7418],{},[418,7399,7400,7401,7403],{},"All helper functions now require ",[325,7402,2349],{}," as first parameter",[418,7405,7406,332,7409,332,7412],{},[325,7407,7408],{},"config($context, $key)",[325,7410,7411],{},"app($context, $id)",[325,7413,7414],{},"base_path($context, $path)",[418,7416,7417],{},"Enables true state isolation for testing and multi-app scenarios",[418,7419,7420],{},"Prepares framework for Swoole/RoadRunner long-running servers",[352,7422,7423,7428],{},[293,7424,7425],{},[308,7426,7427],{},"PHP 8.3 Compatibility",[415,7429,7430,7436,7443],{},[418,7431,705,7432,7435],{},[325,7433,7434],{},"QueueContextHolder"," class replaces deprecated static trait properties",[418,7437,7438,7439,7442],{},"Fixed ",[325,7440,7441],{},"InteractsWithQueue"," trait to avoid deprecated static method calls on traits",[418,7444,7445],{},"All deprecation warnings resolved",[352,7447,7448,7453],{},[293,7449,7450],{},[308,7451,7452],{},"Service Provider Updates",[415,7454,7455,7466,7469],{},[418,7456,7457,542,7460,7463,7464,7030],{},[325,7458,7459],{},"register()",[325,7461,7462],{},"boot()"," methods now receive ",[325,7465,2349],{},[418,7467,7468],{},"Extensions must update to new signatures",[418,7470,7471],{},"Enables proper DI access throughout provider lifecycle",[352,7473,7474,7479],{},[293,7475,7476],{},[308,7477,7478],{},"Console Command Auto-Discovery",[415,7480,7481,7488,7495,7498],{},[418,7482,7483,7484,7487],{},"Commands auto-discovered from ",[325,7485,7486],{},"src/Console/Commands/"," directory",[418,7489,7490,7491,7494],{},"Just add ",[325,7492,7493],{},"#[AsCommand]"," attribute - no manual registration needed",[418,7496,7497],{},"Production caching for fast startup (auto-generated on first run)",[418,7499,705,7500,7503],{},[325,7501,7502],{},"commands:cache"," CLI command for cache management",[352,7505,7506,7511],{},[293,7507,7508],{},[308,7509,7510],{},"Code Quality Improvements",[415,7512,7513,7516,7519,7530],{},[418,7514,7515],{},"Fixed PHPStan errors (duplicate properties, missing returns, visibility)",[418,7517,7518],{},"Fixed 25+ PHPCS line length violations",[418,7520,7521,7522,7525,7526,7529],{},"Added PHPStan ",[325,7523,7524],{},"banned_code"," rule to prevent ",[325,7527,7528],{},"$GLOBALS"," usage",[418,7531,7532],{},"Cleaned up phpstan.neon excludePaths for removed files",[347,7534,7536],{"id":7535},"migration-required","Migration Required",[293,7538,7539],{},"This release requires updating code that uses helper functions:",[428,7541,7543],{"className":5139,"code":7542,"language":1135,"meta":320,"style":320},"// Before (1.21.x)\n$value = config('app.name');\n$service = app(MyService::class);\n\n// After (1.22.0)\n$value = config($context, 'app.name');\n$service = app($context, MyService::class);\n",[325,7544,7545,7550,7573,7596,7600,7605,7629],{"__ignoreMap":320},[436,7546,7547],{"class":438,"line":439},[436,7548,7549],{"class":1168},"// Before (1.21.x)\n",[436,7551,7552,7554,7557,7559,7562,7564,7566,7569,7571],{"class":438,"line":1132},[436,7553,5761],{"class":5163},[436,7555,7556],{"class":1151},"value ",[436,7558,3168],{"class":1144},[436,7560,7561],{"class":5159}," config",[436,7563,5164],{"class":5163},[436,7565,5282],{"class":5281},[436,7567,7568],{"class":446},"app.name",[436,7570,5282],{"class":5281},[436,7572,5295],{"class":5163},[436,7574,7575,7577,7580,7582,7585,7587,7590,7592,7594],{"class":438,"line":1158},[436,7576,5761],{"class":5163},[436,7578,7579],{"class":1151},"service ",[436,7581,3168],{"class":1144},[436,7583,7584],{"class":5159}," app",[436,7586,5164],{"class":5163},[436,7588,7589],{"class":5233},"MyService",[436,7591,6056],{"class":1144},[436,7593,6059],{"class":5167},[436,7595,5295],{"class":5163},[436,7597,7598],{"class":438,"line":5196},[436,7599,5212],{"emptyLinePlaceholder":5211},[436,7601,7602],{"class":438,"line":5202},[436,7603,7604],{"class":1168},"// After (1.22.0)\n",[436,7606,7607,7609,7611,7613,7615,7617,7619,7621,7623,7625,7627],{"class":438,"line":5208},[436,7608,5761],{"class":5163},[436,7610,7556],{"class":1151},[436,7612,3168],{"class":1144},[436,7614,7561],{"class":5159},[436,7616,5778],{"class":5163},[436,7618,6008],{"class":1151},[436,7620,5177],{"class":5163},[436,7622,6064],{"class":5281},[436,7624,7568],{"class":446},[436,7626,5282],{"class":5281},[436,7628,5295],{"class":5163},[436,7630,7631,7633,7635,7637,7639,7641,7643,7645,7648,7650,7652],{"class":438,"line":5215},[436,7632,5761],{"class":5163},[436,7634,7579],{"class":1151},[436,7636,3168],{"class":1144},[436,7638,7584],{"class":5159},[436,7640,5778],{"class":5163},[436,7642,6008],{"class":1151},[436,7644,5177],{"class":5163},[436,7646,7647],{"class":5233}," MyService",[436,7649,6056],{"class":1144},[436,7651,6059],{"class":5167},[436,7653,5295],{"class":5163},[293,7655,7656],{},"Extensions must update provider signatures:",[428,7658,7660],{"className":5139,"code":7659,"language":1135,"meta":320,"style":320},"// Before\npublic function boot(): void { }\n\n// After\npublic function boot(ApplicationContext $context): void { }\n",[325,7661,7662,7666,7689,7693,7697],{"__ignoreMap":320},[436,7663,7664],{"class":438,"line":439},[436,7665,5147],{"class":1168},[436,7667,7668,7670,7672,7675,7678,7680,7683,7686],{"class":438,"line":1132},[436,7669,4794],{"class":5152},[436,7671,5156],{"class":5155},[436,7673,7674],{"class":5159}," boot",[436,7676,7677],{"class":5163},"()",[436,7679,5243],{"class":1144},[436,7681,7682],{"class":5167}," void",[436,7684,7685],{"class":5163}," {",[436,7687,7688],{"class":5163}," }\n",[436,7690,7691],{"class":438,"line":1158},[436,7692,5212],{"emptyLinePlaceholder":5211},[436,7694,7695],{"class":438,"line":5196},[436,7696,5218],{"class":1168},[436,7698,7699,7701,7703,7705,7707,7709,7711,7713,7715,7717,7719,7721],{"class":438,"line":5202},[436,7700,4794],{"class":5152},[436,7702,5156],{"class":5155},[436,7704,7674],{"class":5159},[436,7706,5164],{"class":5163},[436,7708,2349],{"class":5233},[436,7710,5171],{"class":5163},[436,7712,6008],{"class":1151},[436,7714,4887],{"class":5163},[436,7716,5243],{"class":1144},[436,7718,7682],{"class":5167},[436,7720,7685],{"class":5163},[436,7722,7688],{"class":5163},[347,7724,4663],{"id":7725},"risk-assessment-9",[415,7727,7728,7732,7737],{},[418,7729,7730,5341],{},[308,7731,4670],{},[418,7733,7734,7736],{},[308,7735,4676],{},": Helper function signatures, ServiceProvider interface",[418,7738,7739,7741],{},[308,7740,4685],{},": Low-Medium (search-replace for most cases)",[452,7743],{},[301,7745,7747],{"id":7746},"v1210-mira-minor","v1.21.0 - Mira (Minor)",[293,7749,7750],{},[308,7751,7752],{},"Released: January 24, 2026",[312,7754,7756],{"color":314,"icon":7755,"variant":316},"i-tabler-upload",[318,7757,7758],{"v-slot:description":320},[293,7759,7760],{},"Feature release refactoring the file upload system with improved architecture, pure PHP media metadata extraction, and enhanced configurability.",[347,7762,350],{"id":7763},"key-highlights-29",[352,7765,7766,7771],{},[293,7767,7768],{},[308,7769,7770],{},"ThumbnailGenerator",[415,7772,7773,7776,7779,7782],{},[418,7774,7775],{},"New dedicated class for thumbnail creation using ImageProcessor (Intervention Image)",[418,7777,7778],{},"Configurable width, height, and quality settings via config or method parameters",[418,7780,7781],{},"Configurable supported formats (JPEG, PNG, GIF, WebP by default)",[418,7783,7784],{},"Configurable thumbnail subdirectory for organized storage",[352,7786,7787,7792],{},[293,7788,7789],{},[308,7790,7791],{},"MediaMetadataExtractor with getID3",[415,7793,7794,7797,7800,7803],{},[418,7795,7796],{},"Pure PHP metadata extraction — no external binaries required",[418,7798,7799],{},"Removed fragile ffprobe/shell_exec dependency for video duration",[418,7801,7802],{},"Supports images, audio, and video files",[418,7804,7805],{},"Falls back gracefully when getID3 is not installed",[352,7807,7808,7813],{},[293,7809,7810],{},[308,7811,7812],{},"MediaMetadata Value Object",[415,7814,7815,7818,7833,7848],{},[418,7816,7817],{},"New readonly value object for type-safe metadata representation",[418,7819,7820,7821,332,7824,332,7827,332,7830],{},"Properties: ",[325,7822,7823],{},"type",[325,7825,7826],{},"width",[325,7828,7829],{},"height",[325,7831,7832],{},"durationSeconds",[418,7834,7835,7836,332,7839,332,7842,332,7845],{},"Helper methods: ",[325,7837,7838],{},"isImage()",[325,7840,7841],{},"isVideo()",[325,7843,7844],{},"isAudio()",[325,7846,7847],{},"hasDimensions()",[418,7849,7850,542,7853,7856],{},[325,7851,7852],{},"getAspectRatio()",[325,7854,7855],{},"getFormattedDuration()"," utilities",[352,7858,7859,7864],{},[293,7860,7861],{},[308,7862,7863],{},"Enhanced Configuration",[415,7865,7866,7872,7879,7888,7891],{},[418,7867,705,7868,7871],{},[325,7869,7870],{},"filesystem.uploader"," configuration section",[418,7873,7874,7875,7878],{},"Global toggle: ",[325,7876,7877],{},"THUMBNAIL_ENABLED"," to enable/disable thumbnails",[418,7880,7881,7882,332,7885],{},"Configurable dimensions: ",[325,7883,7884],{},"THUMBNAIL_WIDTH",[325,7886,7887],{},"THUMBNAIL_HEIGHT",[418,7889,7890],{},"Configurable quality and subdirectory settings",[418,7892,7893],{},"Configurable thumbnail formats array",[352,7895,7896,7901],{},[293,7897,7898],{},[308,7899,7900],{},"Storage Adapter Documentation",[415,7902,7903,7906,7912,7918,7924],{},[418,7904,7905],{},"Added installation instructions for optional Flysystem adapters",[418,7907,7908,7909],{},"S3/MinIO/DigitalOcean Spaces: ",[325,7910,7911],{},"league/flysystem-aws-s3-v3",[418,7913,7914,7915],{},"Google Cloud Storage: ",[325,7916,7917],{},"league/flysystem-google-cloud-storage",[418,7919,7920,7921],{},"Azure Blob Storage: ",[325,7922,7923],{},"league/flysystem-azure-blob-storage",[418,7925,7926],{},"SFTP/FTP adapters documented",[347,7928,5966],{"id":7929},"usage-1",[293,7931,7932],{},[308,7933,7934],{},"Upload media with automatic thumbnail:",[428,7936,7938],{"className":5139,"code":7937,"language":1135,"meta":320,"style":320},"use Glueful\\Uploader\\FileUploader;\n\n$uploader = new FileUploader($storage);\n$result = $uploader->uploadMedia($file, 'media/images');\n\n// Result includes file info, thumbnail URL, and metadata\n$metadata = $result['metadata'];\nif ($metadata->isImage()) {\n    echo \"Image: {$metadata->width}x{$metadata->height}\";\n} elseif ($metadata->isVideo()) {\n    echo \"Video duration: \" . $metadata->getFormattedDuration();\n}\n",[325,7939,7940,7958,7962,7983,8017,8021,8026,8052,8070,8110,8130,8155],{"__ignoreMap":320},[436,7941,7942,7944,7946,7948,7951,7953,7956],{"class":438,"line":439},[436,7943,6516],{"class":5167},[436,7945,6520],{"class":6519},[436,7947,6524],{"class":6523},[436,7949,7950],{"class":6519},"Uploader",[436,7952,6524],{"class":6523},[436,7954,7955],{"class":6532},"FileUploader",[436,7957,5816],{"class":5163},[436,7959,7960],{"class":438,"line":1132},[436,7961,5212],{"emptyLinePlaceholder":5211},[436,7963,7964,7966,7969,7971,7973,7976,7978,7981],{"class":438,"line":1158},[436,7965,5761],{"class":5163},[436,7967,7968],{"class":1151},"uploader ",[436,7970,3168],{"class":1144},[436,7972,6551],{"class":5167},[436,7974,7975],{"class":5233}," FileUploader",[436,7977,5778],{"class":5163},[436,7979,7980],{"class":1151},"storage",[436,7982,5295],{"class":5163},[436,7984,7985,7987,7990,7992,7994,7997,7999,8002,8004,8006,8008,8010,8013,8015],{"class":438,"line":5196},[436,7986,5761],{"class":5163},[436,7988,7989],{"class":1151},"result ",[436,7991,3168],{"class":1144},[436,7993,5171],{"class":5163},[436,7995,7996],{"class":1151},"uploader",[436,7998,5269],{"class":1144},[436,8000,8001],{"class":5159},"uploadMedia",[436,8003,5778],{"class":5163},[436,8005,7171],{"class":1151},[436,8007,5177],{"class":5163},[436,8009,6064],{"class":5281},[436,8011,8012],{"class":446},"media/images",[436,8014,5282],{"class":5281},[436,8016,5295],{"class":5163},[436,8018,8019],{"class":438,"line":5202},[436,8020,5212],{"emptyLinePlaceholder":5211},[436,8022,8023],{"class":438,"line":5208},[436,8024,8025],{"class":1168},"// Result includes file info, thumbnail URL, and metadata\n",[436,8027,8028,8030,8033,8035,8037,8040,8043,8045,8048,8050],{"class":438,"line":5215},[436,8029,5761],{"class":5163},[436,8031,8032],{"class":1151},"metadata ",[436,8034,3168],{"class":1144},[436,8036,5171],{"class":5163},[436,8038,8039],{"class":1151},"result",[436,8041,8042],{"class":5163},"[",[436,8044,5282],{"class":5281},[436,8046,8047],{"class":446},"metadata",[436,8049,5282],{"class":5281},[436,8051,6968],{"class":5163},[436,8053,8054,8056,8058,8060,8062,8065,8068],{"class":438,"line":5221},[436,8055,5789],{"class":5788},[436,8057,5792],{"class":5163},[436,8059,8047],{"class":1151},[436,8061,5269],{"class":1144},[436,8063,8064],{"class":5159},"isImage",[436,8066,8067],{"class":5163},"())",[436,8069,5803],{"class":5163},[436,8071,8072,8075,8077,8080,8082,8084,8086,8088,8090,8092,8095,8097,8099,8101,8103,8105,8108],{"class":438,"line":5249},[436,8073,8074],{"class":6921},"    echo",[436,8076,7179],{"class":5281},[436,8078,8079],{"class":446},"Image: ",[436,8081,7230],{"class":5281},[436,8083,5761],{"class":5163},[436,8085,8047],{"class":1151},[436,8087,5269],{"class":1144},[436,8089,7826],{"class":1151},[436,8091,7235],{"class":5281},[436,8093,8094],{"class":446},"x",[436,8096,7230],{"class":5281},[436,8098,5761],{"class":5163},[436,8100,8047],{"class":1151},[436,8102,5269],{"class":1144},[436,8104,7829],{"class":1151},[436,8106,8107],{"class":5281},"}\"",[436,8109,5816],{"class":5163},[436,8111,8112,8114,8117,8119,8121,8123,8126,8128],{"class":438,"line":5254},[436,8113,7235],{"class":5163},[436,8115,8116],{"class":5788}," elseif",[436,8118,5792],{"class":5163},[436,8120,8047],{"class":1151},[436,8122,5269],{"class":1144},[436,8124,8125],{"class":5159},"isVideo",[436,8127,8067],{"class":5163},[436,8129,5803],{"class":5163},[436,8131,8132,8134,8136,8139,8141,8144,8146,8148,8150,8153],{"class":438,"line":5298},[436,8133,8074],{"class":6921},[436,8135,7179],{"class":5281},[436,8137,8138],{"class":446},"Video duration: ",[436,8140,7174],{"class":5281},[436,8142,8143],{"class":1144}," .",[436,8145,5171],{"class":5163},[436,8147,8047],{"class":1151},[436,8149,5269],{"class":1144},[436,8151,8152],{"class":5159},"getFormattedDuration",[436,8154,5321],{"class":5163},[436,8156,8157],{"class":438,"line":5324},[436,8158,5205],{"class":5163},[293,8160,8161],{},[308,8162,8163],{},"Configuration (.env):",[428,8165,8169],{"className":8166,"code":8167,"language":8168,"meta":320,"style":320},"language-env shiki shiki-themes material-theme-lighter github-light github-dark monokai","THUMBNAIL_ENABLED=true\nTHUMBNAIL_WIDTH=400\nTHUMBNAIL_HEIGHT=400\nTHUMBNAIL_QUALITY=80\nTHUMBNAIL_SUBDIRECTORY=thumbs\n","env",[325,8170,8171,8176,8181,8186,8191],{"__ignoreMap":320},[436,8172,8173],{"class":438,"line":439},[436,8174,8175],{},"THUMBNAIL_ENABLED=true\n",[436,8177,8178],{"class":438,"line":1132},[436,8179,8180],{},"THUMBNAIL_WIDTH=400\n",[436,8182,8183],{"class":438,"line":1158},[436,8184,8185],{},"THUMBNAIL_HEIGHT=400\n",[436,8187,8188],{"class":438,"line":5196},[436,8189,8190],{},"THUMBNAIL_QUALITY=80\n",[436,8192,8193],{"class":438,"line":5202},[436,8194,8195],{},"THUMBNAIL_SUBDIRECTORY=thumbs\n",[347,8197,8199],{"id":8198},"migration","Migration",[293,8201,8202,8203,299],{},"No breaking changes. The new classes are used internally by ",[325,8204,7955],{},[293,8206,8207,8210,8211,8214],{},[308,8208,8209],{},"New dependency:"," Add ",[325,8212,8213],{},"james-heinrich/getid3"," if not already installed:",[428,8216,8218],{"className":430,"code":8217,"language":432,"meta":320,"style":320},"composer require james-heinrich/getid3\n",[325,8219,8220],{"__ignoreMap":320},[436,8221,8222,8224,8227],{"class":438,"line":439},[436,8223,443],{"class":442},[436,8225,8226],{"class":446}," require",[436,8228,8229],{"class":446}," james-heinrich/getid3\n",[452,8231],{},[301,8233,8235],{"id":8234},"v1200-regulus-minor","v1.20.0 - Regulus (Minor)",[293,8237,8238],{},[308,8239,7752],{},[312,8241,8243],{"color":314,"icon":8242,"variant":316},"i-tabler-leaf",[318,8244,8245],{"v-slot:description":320},[293,8246,8247],{},"Minor release focusing on framework simplification by removing unused subsystems and improving API URL structure for better separation of concerns.",[347,8249,350],{"id":8250},"key-highlights-30",[352,8252,8253,8258],{},[293,8254,8255],{},[308,8256,8257],{},"Resource Routes URL Structure",[415,8259,8260,8266,8275,8278],{},[418,8261,5000,8262,8265],{},[325,8263,8264],{},"/data"," prefix to all generic CRUD resource routes",[418,8267,8268,8269,3677,8272],{},"Routes changed from ",[325,8270,8271],{},"/api/v1/{table}",[325,8273,8274],{},"/api/v1/data/{table}",[418,8276,8277],{},"Prevents conflicts with custom application routes using same table names",[418,8279,8280],{},"Clearer separation between generic data API and custom endpoints",[352,8282,8283,8288],{},[293,8284,8285],{},[308,8286,8287],{},"Async/Fiber System Removed",[415,8289,8290,8293,8296,8306],{},[418,8291,8292],{},"Removed entire Fiber-based async concurrency subsystem (~30 files)",[418,8294,8295],{},"System was unused in practice — Queue system handles background jobs",[418,8297,8298,8299,332,8302,8305],{},"Removed ",[325,8300,8301],{},"AsyncProvider",[325,8303,8304],{},"config/async.php",", and all async helpers",[418,8307,8308],{},"Simplifies codebase and reduces maintenance surface",[352,8310,8311,8316],{},[293,8312,8313],{},[308,8314,8315],{},"Rate Limiting Consolidated",[415,8317,8318,8321,8324,8330],{},[418,8319,8320],{},"Removed basic rate limiting system (6 files)",[418,8322,8323],{},"Enhanced rate limiting system retained with all advanced features",[418,8325,8326,8329],{},[325,8327,8328],{},"EnhancedRateLimiterMiddleware"," provides tiered limits, multiple algorithms",[418,8331,8332,8333,8335],{},"Per-route rate limiting via ",[325,8334,2313],{}," attribute still fully supported",[352,8337,8338,8343],{},[293,8339,8340],{},[308,8341,8342],{},"Configuration Cleanup",[415,8344,8345,8352,8355],{},[418,8346,8347,8348,8351],{},"Removed unused ",[325,8349,8350],{},"ENABLE_AUDIT"," environment variable",[418,8353,8354],{},"Removed duplicate pagination settings from security config",[418,8356,8357],{},"Cleaner configuration with less unused options",[347,8359,8199],{"id":8360},"migration-1",[293,8362,8363],{},[308,8364,8365],{},"Resource Routes (Breaking Change):",[293,8367,8368],{},"If your application calls generic resource endpoints, update the URLs:",[428,8370,8374],{"className":8371,"code":8372,"language":8373,"meta":320,"style":320},"language-diff shiki shiki-themes material-theme-lighter github-light github-dark monokai","- GET /api/v1/users\n+ GET /api/v1/data/users\n\n- POST /api/v1/products\n+ POST /api/v1/data/products\n\n- PUT /api/v1/orders/abc-123\n+ PUT /api/v1/data/orders/abc-123\n","diff",[325,8375,8376,8381,8386,8390,8395,8400,8404,8409],{"__ignoreMap":320},[436,8377,8378],{"class":438,"line":439},[436,8379,8380],{},"- GET /api/v1/users\n",[436,8382,8383],{"class":438,"line":1132},[436,8384,8385],{},"+ GET /api/v1/data/users\n",[436,8387,8388],{"class":438,"line":1158},[436,8389,5212],{"emptyLinePlaceholder":5211},[436,8391,8392],{"class":438,"line":5196},[436,8393,8394],{},"- POST /api/v1/products\n",[436,8396,8397],{"class":438,"line":5202},[436,8398,8399],{},"+ POST /api/v1/data/products\n",[436,8401,8402],{"class":438,"line":5208},[436,8403,5212],{"emptyLinePlaceholder":5211},[436,8405,8406],{"class":438,"line":5215},[436,8407,8408],{},"- PUT /api/v1/orders/abc-123\n",[436,8410,8411],{"class":438,"line":5221},[436,8412,8413],{},"+ PUT /api/v1/data/orders/abc-123\n",[293,8415,8416],{},[308,8417,8418],{},"Async System (if used):",[293,8420,8421],{},"If you were using the Fiber-based async system (rare), migrate to the Queue system:",[428,8423,8425],{"className":8371,"code":8424,"language":8373,"meta":320,"style":320},"- use function Glueful\\async;\n- use function Glueful\\await_all;\n-\n- $results = await_all([\n-     async(fn() => $this->fetchUsers()),\n-     async(fn() => $this->fetchProducts()),\n- ]);\n+ // Use queue jobs for background processing\n+ $queue = service(\\Glueful\\Queue\\QueueManager::class);\n+ $queue->push(FetchUsersJob::class, ['callback' => $callbackUrl]);\n",[325,8426,8427,8432,8437,8442,8447,8452,8457,8462,8467,8472],{"__ignoreMap":320},[436,8428,8429],{"class":438,"line":439},[436,8430,8431],{},"- use function Glueful\\async;\n",[436,8433,8434],{"class":438,"line":1132},[436,8435,8436],{},"- use function Glueful\\await_all;\n",[436,8438,8439],{"class":438,"line":1158},[436,8440,8441],{},"-\n",[436,8443,8444],{"class":438,"line":5196},[436,8445,8446],{},"- $results = await_all([\n",[436,8448,8449],{"class":438,"line":5202},[436,8450,8451],{},"-     async(fn() => $this->fetchUsers()),\n",[436,8453,8454],{"class":438,"line":5208},[436,8455,8456],{},"-     async(fn() => $this->fetchProducts()),\n",[436,8458,8459],{"class":438,"line":5215},[436,8460,8461],{},"- ]);\n",[436,8463,8464],{"class":438,"line":5221},[436,8465,8466],{},"+ // Use queue jobs for background processing\n",[436,8468,8469],{"class":438,"line":5249},[436,8470,8471],{},"+ $queue = service(\\Glueful\\Queue\\QueueManager::class);\n",[436,8473,8474],{"class":438,"line":5254},[436,8475,8476],{},"+ $queue->push(FetchUsersJob::class, ['callback' => $callbackUrl]);\n",[293,8478,8479],{},[308,8480,8481],{},"Rate Limiting:",[293,8483,8484,8485,8488,8489,8491,8492,8494],{},"No migration needed. If using ",[325,8486,8487],{},"RateLimiterMiddleware"," alias, it now points to ",[325,8490,8328],{},". All existing ",[325,8493,2313],{}," attributes and route middleware continue to work.",[452,8496],{},[301,8498,8500],{"id":8499},"v1192-canopus-patch","v1.19.2 - Canopus (Patch)",[293,8502,8503],{},[308,8504,7752],{},[312,8506,8508],{"color":3075,"icon":8507,"variant":316},"i-tabler-code",[318,8509,8510],{"v-slot:description":320},[293,8511,8512],{},"Patch release consolidating ValidationException classes, improving SQL query building, and enhancing cross-database compatibility.",[347,8514,350],{"id":8515},"key-highlights-31",[352,8517,8518,8523],{},[293,8519,8520],{},[308,8521,8522],{},"ValidationException Consolidation",[415,8524,8525,8528,8534,8540,8546],{},[418,8526,8527],{},"Unified from 3 exception classes to 1 canonical class",[418,8529,8530,8531],{},"Removed legacy ",[325,8532,8533],{},"Glueful\\Exceptions\\ValidationException",[418,8535,8536,8537],{},"Removed empty ",[325,8538,8539],{},"Glueful\\Uploader\\ValidationException",[418,8541,8542,8543],{},"All code now uses ",[325,8544,8545],{},"Glueful\\Validation\\ValidationException",[418,8547,8548,8549,332,8552,332,8555],{},"Static factory methods: ",[325,8550,8551],{},"forField()",[325,8553,8554],{},"forFields()",[325,8556,8557],{},"withErrors()",[352,8559,8560,8565],{},[293,8561,8562],{},[308,8563,8564],{},"Database Query Building Improvements",[415,8566,8567,8573,8583,8586],{},[418,8568,8569,8572],{},[325,8570,8571],{},"PaginationBuilder"," improved regex for ORDER BY and LIMIT removal",[418,8574,8575,8576,8579,8580,4887],{},"Handles MySQL offset syntax (",[325,8577,8578],{},"LIMIT 10, 20",") and placeholders (",[325,8581,8582],{},"LIMIT ?",[418,8584,8585],{},"Added detection for UNION, INTERSECT, EXCEPT, CTEs, and window functions",[418,8587,8588,3336,8590,8593],{},[325,8589,327],{},[325,8591,8592],{},"schema.table"," format",[352,8595,8596,8601],{},[293,8597,8598],{},[308,8599,8600],{},"WhereClause Enhancements",[415,8602,8603,8627,8630],{},[418,8604,8605,8606,332,8609,332,8612,332,8615,332,8618,332,8621,332,8624],{},"Expanded valid operators: ",[325,8607,8608],{},"IS",[325,8610,8611],{},"IS NOT",[325,8613,8614],{},"BETWEEN",[325,8616,8617],{},"NOT BETWEEN",[325,8619,8620],{},"REGEXP",[325,8622,8623],{},"RLIKE",[325,8625,8626],{},"ILIKE",[418,8628,8629],{},"Added operator injection protection",[418,8631,8632],{},"Invalid NULL comparisons now throw clear exceptions",[347,8634,8199],{"id":8635},"migration-2",[293,8637,8638],{},"If using the legacy ValidationException directly:",[428,8640,8642],{"className":8371,"code":8641,"language":8373,"meta":320,"style":320},"- use Glueful\\Exceptions\\ValidationException;\n+ use Glueful\\Validation\\ValidationException;\n\n- throw new ValidationException('Error message');\n+ throw ValidationException::forField('field', 'Error message');\n\n- throw new ValidationException(['field' => 'error']);\n+ throw ValidationException::withErrors(['field' => 'error']);\n",[325,8643,8644,8649,8654,8658,8663,8668,8672,8677],{"__ignoreMap":320},[436,8645,8646],{"class":438,"line":439},[436,8647,8648],{},"- use Glueful\\Exceptions\\ValidationException;\n",[436,8650,8651],{"class":438,"line":1132},[436,8652,8653],{},"+ use Glueful\\Validation\\ValidationException;\n",[436,8655,8656],{"class":438,"line":1158},[436,8657,5212],{"emptyLinePlaceholder":5211},[436,8659,8660],{"class":438,"line":5196},[436,8661,8662],{},"- throw new ValidationException('Error message');\n",[436,8664,8665],{"class":438,"line":5202},[436,8666,8667],{},"+ throw ValidationException::forField('field', 'Error message');\n",[436,8669,8670],{"class":438,"line":5208},[436,8671,5212],{"emptyLinePlaceholder":5211},[436,8673,8674],{"class":438,"line":5215},[436,8675,8676],{},"- throw new ValidationException(['field' => 'error']);\n",[436,8678,8679],{"class":438,"line":5221},[436,8680,8681],{},"+ throw ValidationException::withErrors(['field' => 'error']);\n",[452,8683],{},[301,8685,8687],{"id":8686},"v1191-canopus-patch","v1.19.1 - Canopus (Patch)",[293,8689,8690],{},[308,8691,8692],{},"Released: January 22, 2026",[312,8694,8695],{"color":3075,"icon":2890,"variant":316},[318,8696,8697],{"v-slot:description":320},[293,8698,8699],{},"Patch release simplifying API configuration by consolidating URL and version environment variables for cleaner deployment setup.",[347,8701,8703],{"id":8702},"key-changes","Key Changes",[352,8705,8706,8711],{},[293,8707,8708],{},[308,8709,8710],{},"Simplified URL Configuration",[415,8712,8713,8720,8726],{},[418,8714,8715,8716,8719],{},"All URLs now derive from single ",[325,8717,8718],{},"BASE_URL"," variable",[418,8721,8298,8722,8725],{},[325,8723,8724],{},"API_BASE_URL"," — no longer needed",[418,8727,8728,8729,8731,8732,4887],{},"Set ",[325,8730,8718],{}," to your deployment URL (e.g., ",[325,8733,8734],{},"https://api.example.com",[352,8736,8737,8742],{},[293,8738,8739],{},[308,8740,8741],{},"Simplified Version Configuration",[415,8743,8744,8751,8757,8765],{},[418,8745,8746,8747,8750],{},"Consolidated to single ",[325,8748,8749],{},"API_VERSION"," variable (integer format)",[418,8752,8298,8753,8756],{},[325,8754,8755],{},"API_VERSION_FULL"," — docs version derived automatically",[418,8758,8298,8759,8762,8763,4659],{},[325,8760,8761],{},"API_DEFAULT_VERSION"," — use ",[325,8764,8749],{},[418,8766,8767,8768,3677,8771],{},"Changed from ",[325,8769,8770],{},"API_VERSION=v1",[325,8772,8773],{},"API_VERSION=1",[347,8775,8199],{"id":8776},"migration-3",[293,8778,8779,8780,8782],{},"Update your ",[325,8781,2865],{}," file:",[428,8784,8786],{"className":8371,"code":8785,"language":8373,"meta":320,"style":320},"- BASE_URL=http://localhost:8000\n- API_BASE_URL=http://localhost:8000\n- API_VERSION=v1\n- API_VERSION_FULL=1.0.0\n- API_DEFAULT_VERSION=1\n+ BASE_URL=http://localhost:8000\n+ API_VERSION=1\n",[325,8787,8788,8793,8798,8803,8808,8813,8818],{"__ignoreMap":320},[436,8789,8790],{"class":438,"line":439},[436,8791,8792],{},"- BASE_URL=http://localhost:8000\n",[436,8794,8795],{"class":438,"line":1132},[436,8796,8797],{},"- API_BASE_URL=http://localhost:8000\n",[436,8799,8800],{"class":438,"line":1158},[436,8801,8802],{},"- API_VERSION=v1\n",[436,8804,8805],{"class":438,"line":5196},[436,8806,8807],{},"- API_VERSION_FULL=1.0.0\n",[436,8809,8810],{"class":438,"line":5202},[436,8811,8812],{},"- API_DEFAULT_VERSION=1\n",[436,8814,8815],{"class":438,"line":5208},[436,8816,8817],{},"+ BASE_URL=http://localhost:8000\n",[436,8819,8820],{"class":438,"line":5215},[436,8821,8822],{},"+ API_VERSION=1\n",[293,8824,8825],{},[308,8826,8827],{},"Deployment examples:",[5285,8829,8830,8842],{},[8831,8832,8833],"thead",{},[8834,8835,8836,8840],"tr",{},[8837,8838,8839],"th",{},"Scenario",[8837,8841,8718],{},[8843,8844,8845,8856,8865],"tbody",{},[8834,8846,8847,8851],{},[8848,8849,8850],"td",{},"Local development",[8848,8852,8853],{},[325,8854,8855],{},"http://localhost:8000",[8834,8857,8858,8861],{},[8848,8859,8860],{},"API on subdomain",[8848,8862,8863],{},[325,8864,8734],{},[8834,8866,8867,8870],{},[8848,8868,8869],{},"API on main domain",[8848,8871,8872],{},[325,8873,8874],{},"https://example.com",[452,8876],{},[301,8878,8880],{"id":8879},"v1190-canopus-minor","v1.19.0 - Canopus (Minor)",[293,8882,8883],{},[308,8884,8692],{},[312,8886,8888],{"color":314,"icon":8887,"variant":316},"i-tabler-filter",[318,8889,8890],{"v-slot:description":320},[293,8891,8892],{},"Feature release introducing a powerful Search & Filtering DSL with multiple search engine adapters, QueryFilter classes, and comprehensive filtering operators for building flexible API queries.",[347,8894,350],{"id":8895},"key-highlights-32",[352,8897,8898,8903],{},[293,8899,8900],{},[308,8901,8902],{},"Search Engine Adapters",[415,8904,8905,8908,8914,8917],{},[418,8906,8907],{},"Pluggable search backends: Database (LIKE), Elasticsearch, Meilisearch",[418,8909,2572,8910,8913],{},[325,8911,8912],{},"SearchAdapterInterface"," for consistent API",[418,8915,8916],{},"Auto-migration for search index tracking table",[418,8918,8919],{},"Optional dependency support (no extra packages required for basic usage)",[352,8921,8922,8927],{},[293,8923,8924],{},[308,8925,8926],{},"QueryFilter Classes",[415,8928,8929,8932,8935,8938],{},[418,8930,8931],{},"Reusable filter classes for API resources",[418,8933,8934],{},"Support for 20+ operators (eq, ne, gt, lt, in, between, like, etc.)",[418,8936,8937],{},"Automatic query building with secure parameter binding",[418,8939,8940],{},"Field whitelisting for security",[352,8942,8943,8948],{},[293,8944,8945],{},[308,8946,8947],{},"Searchable ORM Trait",[415,8949,8950,8953,8956,8959],{},[418,8951,8952],{},"Add search functionality to any ORM model",[418,8954,8955],{},"Automatic index synchronization on model changes",[418,8957,8958],{},"Custom searchable fields configuration",[418,8960,8961],{},"Batch indexing support",[352,8963,8964,8969],{},[293,8965,8966],{},[308,8967,8968],{},"scaffold:filter Command",[415,8970,8971,8974,8977],{},[418,8972,8973],{},"Generate QueryFilter classes from CLI",[418,8975,8976],{},"Automatic field detection from models",[418,8978,8979],{},"Customizable operator sets per field",[347,8981,8902],{"id":8982},"search-engine-adapters",[293,8984,8985],{},[308,8986,8987],{},"Core Classes:",[5285,8989,8990,9000],{},[8831,8991,8992],{},[8834,8993,8994,8997],{},[8837,8995,8996],{},"Class",[8837,8998,8999],{},"Purpose",[8843,9001,9002,9011,9021,9031,9041,9051],{},[8834,9003,9004,9008],{},[8848,9005,9006],{},[325,9007,8912],{},[8848,9009,9010],{},"Contract for search adapters",[8834,9012,9013,9018],{},[8848,9014,9015],{},[325,9016,9017],{},"SearchAdapter",[8848,9019,9020],{},"Base class with auto-migration",[8834,9022,9023,9028],{},[8848,9024,9025],{},[325,9026,9027],{},"SearchResult",[8848,9029,9030],{},"Value object for search results",[8834,9032,9033,9038],{},[8848,9034,9035],{},[325,9036,9037],{},"DatabaseAdapter",[8848,9039,9040],{},"SQL LIKE search (default)",[8834,9042,9043,9048],{},[8848,9044,9045],{},[325,9046,9047],{},"ElasticsearchAdapter",[8848,9049,9050],{},"Elasticsearch integration",[8834,9052,9053,9058],{},[8848,9054,9055],{},[325,9056,9057],{},"MeilisearchAdapter",[8848,9059,9060],{},"Meilisearch integration",[293,9062,9063],{},[308,9064,9065],{},"Optional Packages:",[428,9067,9069],{"className":430,"code":9068,"language":432,"meta":320,"style":320},"# For Elasticsearch support\ncomposer require elasticsearch/elasticsearch:^8.0\n\n# For Meilisearch support\ncomposer require meilisearch/meilisearch-php:^1.0\n",[325,9070,9071,9076,9085,9089,9094],{"__ignoreMap":320},[436,9072,9073],{"class":438,"line":439},[436,9074,9075],{"class":1168},"# For Elasticsearch support\n",[436,9077,9078,9080,9082],{"class":438,"line":1132},[436,9079,443],{"class":442},[436,9081,8226],{"class":446},[436,9083,9084],{"class":446}," elasticsearch/elasticsearch:^8.0\n",[436,9086,9087],{"class":438,"line":1158},[436,9088,5212],{"emptyLinePlaceholder":5211},[436,9090,9091],{"class":438,"line":5196},[436,9092,9093],{"class":1168},"# For Meilisearch support\n",[436,9095,9096,9098,9100],{"class":438,"line":5202},[436,9097,443],{"class":442},[436,9099,8226],{"class":446},[436,9101,9102],{"class":446}," meilisearch/meilisearch-php:^1.0\n",[347,9104,9106],{"id":9105},"filtering-operators","Filtering Operators",[5285,9108,9109,9125],{},[8831,9110,9111],{},[8834,9112,9113,9116,9119,9122],{},[8837,9114,9115],{},"Operator",[8837,9117,9118],{},"Aliases",[8837,9120,9121],{},"Description",[8837,9123,9124],{},"Example",[8843,9126,9127,9146,9168,9187,9206,9225,9244,9261,9281,9301,9318,9335,9352,9371],{},[8834,9128,9129,9134,9138,9141],{},[8848,9130,9131],{},[325,9132,9133],{},"eq",[8848,9135,9136],{},[325,9137,3168],{},[8848,9139,9140],{},"Equal to",[8848,9142,9143],{},[325,9144,9145],{},"filter[status]=active",[8834,9147,9148,9153,9160,9163],{},[8848,9149,9150],{},[325,9151,9152],{},"ne",[8848,9154,9155,332,9157],{},[325,9156,3152],{},[325,9158,9159],{},"\u003C>",[8848,9161,9162],{},"Not equal",[8848,9164,9165],{},[325,9166,9167],{},"filter[status][ne]=deleted",[8834,9169,9170,9175,9179,9182],{},[8848,9171,9172],{},[325,9173,9174],{},"gt",[8848,9176,9177],{},[325,9178,3146],{},[8848,9180,9181],{},"Greater than",[8848,9183,9184],{},[325,9185,9186],{},"filter[age][gt]=18",[8834,9188,9189,9194,9198,9201],{},[8848,9190,9191],{},[325,9192,9193],{},"gte",[8848,9195,9196],{},[325,9197,3149],{},[8848,9199,9200],{},"Greater or equal",[8848,9202,9203],{},[325,9204,9205],{},"filter[price][gte]=100",[8834,9207,9208,9213,9217,9220],{},[8848,9209,9210],{},[325,9211,9212],{},"lt",[8848,9214,9215],{},[325,9216,3140],{},[8848,9218,9219],{},"Less than",[8848,9221,9222],{},[325,9223,9224],{},"filter[stock][lt]=10",[8834,9226,9227,9232,9236,9239],{},[8848,9228,9229],{},[325,9230,9231],{},"lte",[8848,9233,9234],{},[325,9235,3143],{},[8848,9237,9238],{},"Less or equal",[8848,9240,9241],{},[325,9242,9243],{},"filter[rating][lte]=5",[8834,9245,9246,9251,9253,9256],{},[8848,9247,9248],{},[325,9249,9250],{},"in",[8848,9252],{},[8848,9254,9255],{},"In array",[8848,9257,9258],{},[325,9259,9260],{},"filter[status][in]=active,pending",[8834,9262,9263,9268,9273,9276],{},[8848,9264,9265],{},[325,9266,9267],{},"nin",[8848,9269,9270],{},[325,9271,9272],{},"not_in",[8848,9274,9275],{},"Not in array",[8848,9277,9278],{},[325,9279,9280],{},"filter[type][nin]=draft,archived",[8834,9282,9283,9288,9293,9296],{},[8848,9284,9285],{},[325,9286,9287],{},"like",[8848,9289,9290],{},[325,9291,9292],{},"contains",[8848,9294,9295],{},"Contains substring",[8848,9297,9298],{},[325,9299,9300],{},"filter[name][like]=john",[8834,9302,9303,9308,9310,9313],{},[8848,9304,9305],{},[325,9306,9307],{},"starts",[8848,9309],{},[8848,9311,9312],{},"Starts with",[8848,9314,9315],{},[325,9316,9317],{},"filter[email][starts]=admin",[8834,9319,9320,9325,9327,9330],{},[8848,9321,9322],{},[325,9323,9324],{},"ends",[8848,9326],{},[8848,9328,9329],{},"Ends with",[8848,9331,9332],{},[325,9333,9334],{},"filter[domain][ends]=.com",[8834,9336,9337,9342,9344,9347],{},[8848,9338,9339],{},[325,9340,9341],{},"between",[8848,9343],{},[8848,9345,9346],{},"Range (inclusive)",[8848,9348,9349],{},[325,9350,9351],{},"filter[price][between]=10,100",[8834,9353,9354,9358,9363,9366],{},[8848,9355,9356],{},[325,9357,2982],{},[8848,9359,9360],{},[325,9361,9362],{},"is_null",[8848,9364,9365],{},"Is null",[8848,9367,9368],{},[325,9369,9370],{},"filter[deleted_at][null]=1",[8834,9372,9373,9378,9380,9383],{},[8848,9374,9375],{},[325,9376,9377],{},"not_null",[8848,9379],{},[8848,9381,9382],{},"Is not null",[8848,9384,9385],{},[325,9386,9387],{},"filter[verified_at][not_null]=1",[347,9389,9391],{"id":9390},"quick-usage","Quick Usage",[428,9393,9395],{"className":5139,"code":9394,"language":1135,"meta":320,"style":320},"use Glueful\\Api\\Filtering\\QueryFilter;\nuse Glueful\\Api\\Filtering\\Adapters\\DatabaseAdapter;\nuse Glueful\\Api\\Filtering\\Concerns\\Searchable;\n\n// Create a QueryFilter\nclass UserFilter extends QueryFilter\n{\n    protected array $filterable = [\n        'name' => ['eq', 'like', 'starts'],\n        'email' => ['eq', 'like'],\n        'status' => ['eq', 'in', 'nin'],\n        'created_at' => ['gt', 'gte', 'lt', 'lte', 'between'],\n    ];\n\n    protected array $sortable = ['name', 'email', 'created_at'];\n}\n\n// Apply filter to query\n$filter = new UserFilter($request);\n$users = $filter->apply(QueryBuilder::table('users'))->get();\n\n// Use Searchable trait in models\nclass User extends Model\n{\n    use Searchable;\n\n    protected array $searchableFields = ['name', 'email', 'bio'];\n}\n\n// Search users\n$results = User::search('john doe', [\n    'fields' => ['name', 'email'],\n    'limit' => 20,\n]);\n\n// Use search adapter directly\n$adapter = new DatabaseAdapter('users');\n$results = $adapter->search('john', [\n    'fields' => ['name', 'email'],\n    'limit' => 10,\n]);\n",[325,9396,9397,9420,9445,9471,9475,9480,9495,9499,9515,9554,9582,9619,9672,9677,9681,9720,9724,9728,9733,9752,9799,9804,9810,9823,9828,9839,9844,9885,9890,9895,9901,9931,9961,9977,9982,9987,9993,10018,10049,10078,10094],{"__ignoreMap":320},[436,9398,9399,9401,9403,9405,9408,9410,9413,9415,9418],{"class":438,"line":439},[436,9400,6516],{"class":5167},[436,9402,6520],{"class":6519},[436,9404,6524],{"class":6523},[436,9406,9407],{"class":6519},"Api",[436,9409,6524],{"class":6523},[436,9411,9412],{"class":6519},"Filtering",[436,9414,6524],{"class":6523},[436,9416,9417],{"class":6532},"QueryFilter",[436,9419,5816],{"class":5163},[436,9421,9422,9424,9426,9428,9430,9432,9434,9436,9439,9441,9443],{"class":438,"line":1132},[436,9423,6516],{"class":5167},[436,9425,6520],{"class":6519},[436,9427,6524],{"class":6523},[436,9429,9407],{"class":6519},[436,9431,6524],{"class":6523},[436,9433,9412],{"class":6519},[436,9435,6524],{"class":6523},[436,9437,9438],{"class":6519},"Adapters",[436,9440,6524],{"class":6523},[436,9442,9037],{"class":6532},[436,9444,5816],{"class":5163},[436,9446,9447,9449,9451,9453,9455,9457,9459,9461,9464,9466,9469],{"class":438,"line":1158},[436,9448,6516],{"class":5167},[436,9450,6520],{"class":6519},[436,9452,6524],{"class":6523},[436,9454,9407],{"class":6519},[436,9456,6524],{"class":6523},[436,9458,9412],{"class":6519},[436,9460,6524],{"class":6523},[436,9462,9463],{"class":6519},"Concerns",[436,9465,6524],{"class":6523},[436,9467,9468],{"class":6532},"Searchable",[436,9470,5816],{"class":5163},[436,9472,9473],{"class":438,"line":5196},[436,9474,5212],{"emptyLinePlaceholder":5211},[436,9476,9477],{"class":438,"line":5202},[436,9478,9479],{"class":1168},"// Create a QueryFilter\n",[436,9481,9482,9484,9488,9491],{"class":438,"line":5208},[436,9483,6059],{"class":5155},[436,9485,9487],{"class":9486},"sKvfc"," UserFilter",[436,9489,9490],{"class":5152}," extends",[436,9492,9494],{"class":9493},"sW3Pz"," QueryFilter\n",[436,9496,9497],{"class":438,"line":5215},[436,9498,5193],{"class":5163},[436,9500,9501,9504,9506,9508,9511,9513],{"class":438,"line":5221},[436,9502,9503],{"class":5152},"    protected",[436,9505,5180],{"class":5167},[436,9507,5171],{"class":5163},[436,9509,9510],{"class":1151},"filterable ",[436,9512,3168],{"class":1144},[436,9514,6857],{"class":5163},[436,9516,9517,9520,9523,9525,9527,9529,9531,9533,9535,9537,9539,9541,9543,9545,9547,9549,9551],{"class":438,"line":5249},[436,9518,9519],{"class":5281},"        '",[436,9521,9522],{"class":446},"name",[436,9524,5282],{"class":5281},[436,9526,6000],{"class":1144},[436,9528,6050],{"class":5163},[436,9530,5282],{"class":5281},[436,9532,9133],{"class":446},[436,9534,5282],{"class":5281},[436,9536,5177],{"class":5163},[436,9538,6064],{"class":5281},[436,9540,9287],{"class":446},[436,9542,5282],{"class":5281},[436,9544,5177],{"class":5163},[436,9546,6064],{"class":5281},[436,9548,9307],{"class":446},[436,9550,5282],{"class":5281},[436,9552,9553],{"class":5163},"],\n",[436,9555,9556,9558,9560,9562,9564,9566,9568,9570,9572,9574,9576,9578,9580],{"class":438,"line":5254},[436,9557,9519],{"class":5281},[436,9559,2688],{"class":446},[436,9561,5282],{"class":5281},[436,9563,6000],{"class":1144},[436,9565,6050],{"class":5163},[436,9567,5282],{"class":5281},[436,9569,9133],{"class":446},[436,9571,5282],{"class":5281},[436,9573,5177],{"class":5163},[436,9575,6064],{"class":5281},[436,9577,9287],{"class":446},[436,9579,5282],{"class":5281},[436,9581,9553],{"class":5163},[436,9583,9584,9586,9589,9591,9593,9595,9597,9599,9601,9603,9605,9607,9609,9611,9613,9615,9617],{"class":438,"line":5298},[436,9585,9519],{"class":5281},[436,9587,9588],{"class":446},"status",[436,9590,5282],{"class":5281},[436,9592,6000],{"class":1144},[436,9594,6050],{"class":5163},[436,9596,5282],{"class":5281},[436,9598,9133],{"class":446},[436,9600,5282],{"class":5281},[436,9602,5177],{"class":5163},[436,9604,6064],{"class":5281},[436,9606,9250],{"class":446},[436,9608,5282],{"class":5281},[436,9610,5177],{"class":5163},[436,9612,6064],{"class":5281},[436,9614,9267],{"class":446},[436,9616,5282],{"class":5281},[436,9618,9553],{"class":5163},[436,9620,9621,9623,9626,9628,9630,9632,9634,9636,9638,9640,9642,9644,9646,9648,9650,9652,9654,9656,9658,9660,9662,9664,9666,9668,9670],{"class":438,"line":5324},[436,9622,9519],{"class":5281},[436,9624,9625],{"class":446},"created_at",[436,9627,5282],{"class":5281},[436,9629,6000],{"class":1144},[436,9631,6050],{"class":5163},[436,9633,5282],{"class":5281},[436,9635,9174],{"class":446},[436,9637,5282],{"class":5281},[436,9639,5177],{"class":5163},[436,9641,6064],{"class":5281},[436,9643,9193],{"class":446},[436,9645,5282],{"class":5281},[436,9647,5177],{"class":5163},[436,9649,6064],{"class":5281},[436,9651,9212],{"class":446},[436,9653,5282],{"class":5281},[436,9655,5177],{"class":5163},[436,9657,6064],{"class":5281},[436,9659,9231],{"class":446},[436,9661,5282],{"class":5281},[436,9663,5177],{"class":5163},[436,9665,6064],{"class":5281},[436,9667,9341],{"class":446},[436,9669,5282],{"class":5281},[436,9671,9553],{"class":5163},[436,9673,9674],{"class":438,"line":5329},[436,9675,9676],{"class":5163},"    ];\n",[436,9678,9679],{"class":438,"line":6717},[436,9680,5212],{"emptyLinePlaceholder":5211},[436,9682,9683,9685,9687,9689,9692,9694,9696,9698,9700,9702,9704,9706,9708,9710,9712,9714,9716,9718],{"class":438,"line":6742},[436,9684,9503],{"class":5152},[436,9686,5180],{"class":5167},[436,9688,5171],{"class":5163},[436,9690,9691],{"class":1151},"sortable ",[436,9693,3168],{"class":1144},[436,9695,6050],{"class":5163},[436,9697,5282],{"class":5281},[436,9699,9522],{"class":446},[436,9701,5282],{"class":5281},[436,9703,5177],{"class":5163},[436,9705,6064],{"class":5281},[436,9707,2688],{"class":446},[436,9709,5282],{"class":5281},[436,9711,5177],{"class":5163},[436,9713,6064],{"class":5281},[436,9715,9625],{"class":446},[436,9717,5282],{"class":5281},[436,9719,6968],{"class":5163},[436,9721,9722],{"class":438,"line":6767},[436,9723,5205],{"class":5163},[436,9725,9726],{"class":438,"line":6772},[436,9727,5212],{"emptyLinePlaceholder":5211},[436,9729,9730],{"class":438,"line":6778},[436,9731,9732],{"class":1168},"// Apply filter to query\n",[436,9734,9735,9737,9740,9742,9744,9746,9748,9750],{"class":438,"line":6810},[436,9736,5761],{"class":5163},[436,9738,9739],{"class":1151},"filter ",[436,9741,3168],{"class":1144},[436,9743,6551],{"class":5167},[436,9745,9487],{"class":5233},[436,9747,5778],{"class":5163},[436,9749,5238],{"class":1151},[436,9751,5295],{"class":5163},[436,9753,9755,9757,9760,9762,9764,9767,9769,9772,9774,9777,9779,9781,9783,9785,9788,9790,9793,9795,9797],{"class":438,"line":9754},20,[436,9756,5761],{"class":5163},[436,9758,9759],{"class":1151},"users ",[436,9761,3168],{"class":1144},[436,9763,5171],{"class":5163},[436,9765,9766],{"class":1151},"filter",[436,9768,5269],{"class":1144},[436,9770,9771],{"class":5159},"apply",[436,9773,5164],{"class":5163},[436,9775,9776],{"class":5233},"QueryBuilder",[436,9778,6056],{"class":1144},[436,9780,5285],{"class":5159},[436,9782,5164],{"class":5163},[436,9784,5282],{"class":5281},[436,9786,9787],{"class":446},"users",[436,9789,5282],{"class":5281},[436,9791,9792],{"class":5163},"))",[436,9794,5269],{"class":1144},[436,9796,715],{"class":5159},[436,9798,5321],{"class":5163},[436,9800,9802],{"class":438,"line":9801},21,[436,9803,5212],{"emptyLinePlaceholder":5211},[436,9805,9807],{"class":438,"line":9806},22,[436,9808,9809],{"class":1168},"// Use Searchable trait in models\n",[436,9811,9813,9815,9818,9820],{"class":438,"line":9812},23,[436,9814,6059],{"class":5155},[436,9816,9817],{"class":9486}," User",[436,9819,9490],{"class":5152},[436,9821,9822],{"class":9493}," Model\n",[436,9824,9826],{"class":438,"line":9825},24,[436,9827,5193],{"class":5163},[436,9829,9831,9834,9837],{"class":438,"line":9830},25,[436,9832,9833],{"class":5167},"    use",[436,9835,9836],{"class":6532}," Searchable",[436,9838,5816],{"class":5163},[436,9840,9842],{"class":438,"line":9841},26,[436,9843,5212],{"emptyLinePlaceholder":5211},[436,9845,9847,9849,9851,9853,9856,9858,9860,9862,9864,9866,9868,9870,9872,9874,9876,9878,9881,9883],{"class":438,"line":9846},27,[436,9848,9503],{"class":5152},[436,9850,5180],{"class":5167},[436,9852,5171],{"class":5163},[436,9854,9855],{"class":1151},"searchableFields ",[436,9857,3168],{"class":1144},[436,9859,6050],{"class":5163},[436,9861,5282],{"class":5281},[436,9863,9522],{"class":446},[436,9865,5282],{"class":5281},[436,9867,5177],{"class":5163},[436,9869,6064],{"class":5281},[436,9871,2688],{"class":446},[436,9873,5282],{"class":5281},[436,9875,5177],{"class":5163},[436,9877,6064],{"class":5281},[436,9879,9880],{"class":446},"bio",[436,9882,5282],{"class":5281},[436,9884,6968],{"class":5163},[436,9886,9888],{"class":438,"line":9887},28,[436,9889,5205],{"class":5163},[436,9891,9893],{"class":438,"line":9892},29,[436,9894,5212],{"emptyLinePlaceholder":5211},[436,9896,9898],{"class":438,"line":9897},30,[436,9899,9900],{"class":1168},"// Search users\n",[436,9902,9904,9906,9909,9911,9913,9915,9918,9920,9922,9925,9927,9929],{"class":438,"line":9903},31,[436,9905,5761],{"class":5163},[436,9907,9908],{"class":1151},"results ",[436,9910,3168],{"class":1144},[436,9912,9817],{"class":5233},[436,9914,6056],{"class":1144},[436,9916,9917],{"class":5159},"search",[436,9919,5164],{"class":5163},[436,9921,5282],{"class":5281},[436,9923,9924],{"class":446},"john doe",[436,9926,5282],{"class":5281},[436,9928,5177],{"class":5163},[436,9930,6857],{"class":5163},[436,9932,9934,9936,9939,9941,9943,9945,9947,9949,9951,9953,9955,9957,9959],{"class":438,"line":9933},32,[436,9935,6862],{"class":5281},[436,9937,9938],{"class":446},"fields",[436,9940,5282],{"class":5281},[436,9942,6000],{"class":1144},[436,9944,6050],{"class":5163},[436,9946,5282],{"class":5281},[436,9948,9522],{"class":446},[436,9950,5282],{"class":5281},[436,9952,5177],{"class":5163},[436,9954,6064],{"class":5281},[436,9956,2688],{"class":446},[436,9958,5282],{"class":5281},[436,9960,9553],{"class":5163},[436,9962,9964,9966,9968,9970,9972,9975],{"class":438,"line":9963},33,[436,9965,6862],{"class":5281},[436,9967,1803],{"class":446},[436,9969,5282],{"class":5281},[436,9971,6000],{"class":1144},[436,9973,9974],{"class":7256}," 20",[436,9976,6907],{"class":5163},[436,9978,9980],{"class":438,"line":9979},34,[436,9981,6072],{"class":5163},[436,9983,9985],{"class":438,"line":9984},35,[436,9986,5212],{"emptyLinePlaceholder":5211},[436,9988,9990],{"class":438,"line":9989},36,[436,9991,9992],{"class":1168},"// Use search adapter directly\n",[436,9994,9996,9998,10001,10003,10005,10008,10010,10012,10014,10016],{"class":438,"line":9995},37,[436,9997,5761],{"class":5163},[436,9999,10000],{"class":1151},"adapter ",[436,10002,3168],{"class":1144},[436,10004,6551],{"class":5167},[436,10006,10007],{"class":5233}," DatabaseAdapter",[436,10009,5164],{"class":5163},[436,10011,5282],{"class":5281},[436,10013,9787],{"class":446},[436,10015,5282],{"class":5281},[436,10017,5295],{"class":5163},[436,10019,10021,10023,10025,10027,10029,10032,10034,10036,10038,10040,10043,10045,10047],{"class":438,"line":10020},38,[436,10022,5761],{"class":5163},[436,10024,9908],{"class":1151},[436,10026,3168],{"class":1144},[436,10028,5171],{"class":5163},[436,10030,10031],{"class":1151},"adapter",[436,10033,5269],{"class":1144},[436,10035,9917],{"class":5159},[436,10037,5164],{"class":5163},[436,10039,5282],{"class":5281},[436,10041,10042],{"class":446},"john",[436,10044,5282],{"class":5281},[436,10046,5177],{"class":5163},[436,10048,6857],{"class":5163},[436,10050,10052,10054,10056,10058,10060,10062,10064,10066,10068,10070,10072,10074,10076],{"class":438,"line":10051},39,[436,10053,6862],{"class":5281},[436,10055,9938],{"class":446},[436,10057,5282],{"class":5281},[436,10059,6000],{"class":1144},[436,10061,6050],{"class":5163},[436,10063,5282],{"class":5281},[436,10065,9522],{"class":446},[436,10067,5282],{"class":5281},[436,10069,5177],{"class":5163},[436,10071,6064],{"class":5281},[436,10073,2688],{"class":446},[436,10075,5282],{"class":5281},[436,10077,9553],{"class":5163},[436,10079,10081,10083,10085,10087,10089,10092],{"class":438,"line":10080},40,[436,10082,6862],{"class":5281},[436,10084,1803],{"class":446},[436,10086,5282],{"class":5281},[436,10088,6000],{"class":1144},[436,10090,10091],{"class":7256}," 10",[436,10093,6907],{"class":5163},[436,10095,10097],{"class":438,"line":10096},41,[436,10098,6072],{"class":5163},[347,10100,121],{"id":10101},"configuration-1",[428,10103,10105],{"className":5139,"code":10104,"language":1135,"meta":320,"style":320},"// config/api.php\n'filtering' => [\n    'default_limit' => 25,\n    'max_limit' => 100,\n    'allow_all_fields' => false,\n    'strict_mode' => true,\n\n    // Search engine configuration\n    'search' => [\n        // Options: 'database', 'elasticsearch', 'meilisearch'\n        'driver' => env('API_SEARCH_DRIVER', 'database'),\n        'index_prefix' => env('SEARCH_INDEX_PREFIX', ''),\n        'auto_index' => env('SEARCH_AUTO_INDEX', false),\n\n        // Elasticsearch (requires: elasticsearch/elasticsearch:^8.0)\n        'elasticsearch' => [\n            'hosts' => [env('ELASTICSEARCH_HOST', 'localhost:9200')],\n        ],\n\n        // Meilisearch (requires: meilisearch/meilisearch-php:^1.0)\n        'meilisearch' => [\n            'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),\n            'key' => env('MEILISEARCH_KEY'),\n        ],\n    ],\n],\n",[325,10106,10107,10112,10125,10141,10157,10174,10190,10194,10199,10211,10216,10249,10277,10305,10309,10314,10327,10364,10369,10373,10378,10391,10424,10447,10451,10456],{"__ignoreMap":320},[436,10108,10109],{"class":438,"line":439},[436,10110,10111],{"class":1168},"// config/api.php\n",[436,10113,10114,10116,10119,10121,10123],{"class":438,"line":1132},[436,10115,5282],{"class":5281},[436,10117,10118],{"class":446},"filtering",[436,10120,5282],{"class":5281},[436,10122,6000],{"class":1144},[436,10124,6857],{"class":5163},[436,10126,10127,10129,10132,10134,10136,10139],{"class":438,"line":1158},[436,10128,6862],{"class":5281},[436,10130,10131],{"class":446},"default_limit",[436,10133,5282],{"class":5281},[436,10135,6000],{"class":1144},[436,10137,10138],{"class":7256}," 25",[436,10140,6907],{"class":5163},[436,10142,10143,10145,10148,10150,10152,10155],{"class":438,"line":5196},[436,10144,6862],{"class":5281},[436,10146,10147],{"class":446},"max_limit",[436,10149,5282],{"class":5281},[436,10151,6000],{"class":1144},[436,10153,10154],{"class":7256}," 100",[436,10156,6907],{"class":5163},[436,10158,10159,10161,10164,10166,10168,10172],{"class":438,"line":5202},[436,10160,6862],{"class":5281},[436,10162,10163],{"class":446},"allow_all_fields",[436,10165,5282],{"class":5281},[436,10167,6000],{"class":1144},[436,10169,10171],{"class":10170},"sMTiH"," false",[436,10173,6907],{"class":5163},[436,10175,10176,10178,10181,10183,10185,10188],{"class":438,"line":5208},[436,10177,6862],{"class":5281},[436,10179,10180],{"class":446},"strict_mode",[436,10182,5282],{"class":5281},[436,10184,6000],{"class":1144},[436,10186,10187],{"class":10170}," true",[436,10189,6907],{"class":5163},[436,10191,10192],{"class":438,"line":5215},[436,10193,5212],{"emptyLinePlaceholder":5211},[436,10195,10196],{"class":438,"line":5221},[436,10197,10198],{"class":1168},"    // Search engine configuration\n",[436,10200,10201,10203,10205,10207,10209],{"class":438,"line":5249},[436,10202,6862],{"class":5281},[436,10204,9917],{"class":446},[436,10206,5282],{"class":5281},[436,10208,6000],{"class":1144},[436,10210,6857],{"class":5163},[436,10212,10213],{"class":438,"line":5254},[436,10214,10215],{"class":1168},"        // Options: 'database', 'elasticsearch', 'meilisearch'\n",[436,10217,10218,10220,10223,10225,10227,10229,10231,10233,10236,10238,10240,10242,10244,10246],{"class":438,"line":5298},[436,10219,9519],{"class":5281},[436,10221,10222],{"class":446},"driver",[436,10224,5282],{"class":5281},[436,10226,6000],{"class":1144},[436,10228,6871],{"class":5159},[436,10230,5164],{"class":5163},[436,10232,5282],{"class":5281},[436,10234,10235],{"class":446},"API_SEARCH_DRIVER",[436,10237,5282],{"class":5281},[436,10239,5177],{"class":5163},[436,10241,6064],{"class":5281},[436,10243,4357],{"class":446},[436,10245,5282],{"class":5281},[436,10247,10248],{"class":5163},"),\n",[436,10250,10251,10253,10256,10258,10260,10262,10264,10266,10269,10271,10273,10275],{"class":438,"line":5324},[436,10252,9519],{"class":5281},[436,10254,10255],{"class":446},"index_prefix",[436,10257,5282],{"class":5281},[436,10259,6000],{"class":1144},[436,10261,6871],{"class":5159},[436,10263,5164],{"class":5163},[436,10265,5282],{"class":5281},[436,10267,10268],{"class":446},"SEARCH_INDEX_PREFIX",[436,10270,5282],{"class":5281},[436,10272,5177],{"class":5163},[436,10274,5292],{"class":5281},[436,10276,10248],{"class":5163},[436,10278,10279,10281,10284,10286,10288,10290,10292,10294,10297,10299,10301,10303],{"class":438,"line":5329},[436,10280,9519],{"class":5281},[436,10282,10283],{"class":446},"auto_index",[436,10285,5282],{"class":5281},[436,10287,6000],{"class":1144},[436,10289,6871],{"class":5159},[436,10291,5164],{"class":5163},[436,10293,5282],{"class":5281},[436,10295,10296],{"class":446},"SEARCH_AUTO_INDEX",[436,10298,5282],{"class":5281},[436,10300,5177],{"class":5163},[436,10302,10171],{"class":10170},[436,10304,10248],{"class":5163},[436,10306,10307],{"class":438,"line":6717},[436,10308,5212],{"emptyLinePlaceholder":5211},[436,10310,10311],{"class":438,"line":6742},[436,10312,10313],{"class":1168},"        // Elasticsearch (requires: elasticsearch/elasticsearch:^8.0)\n",[436,10315,10316,10318,10321,10323,10325],{"class":438,"line":6767},[436,10317,9519],{"class":5281},[436,10319,10320],{"class":446},"elasticsearch",[436,10322,5282],{"class":5281},[436,10324,6000],{"class":1144},[436,10326,6857],{"class":5163},[436,10328,10329,10332,10335,10337,10339,10341,10343,10345,10347,10350,10352,10354,10356,10359,10361],{"class":438,"line":6772},[436,10330,10331],{"class":5281},"            '",[436,10333,10334],{"class":446},"hosts",[436,10336,5282],{"class":5281},[436,10338,6000],{"class":1144},[436,10340,6050],{"class":5163},[436,10342,8168],{"class":5159},[436,10344,5164],{"class":5163},[436,10346,5282],{"class":5281},[436,10348,10349],{"class":446},"ELASTICSEARCH_HOST",[436,10351,5282],{"class":5281},[436,10353,5177],{"class":5163},[436,10355,6064],{"class":5281},[436,10357,10358],{"class":446},"localhost:9200",[436,10360,5282],{"class":5281},[436,10362,10363],{"class":5163},")],\n",[436,10365,10366],{"class":438,"line":6778},[436,10367,10368],{"class":5163},"        ],\n",[436,10370,10371],{"class":438,"line":6810},[436,10372,5212],{"emptyLinePlaceholder":5211},[436,10374,10375],{"class":438,"line":9754},[436,10376,10377],{"class":1168},"        // Meilisearch (requires: meilisearch/meilisearch-php:^1.0)\n",[436,10379,10380,10382,10385,10387,10389],{"class":438,"line":9801},[436,10381,9519],{"class":5281},[436,10383,10384],{"class":446},"meilisearch",[436,10386,5282],{"class":5281},[436,10388,6000],{"class":1144},[436,10390,6857],{"class":5163},[436,10392,10393,10395,10398,10400,10402,10404,10406,10408,10411,10413,10415,10417,10420,10422],{"class":438,"line":9806},[436,10394,10331],{"class":5281},[436,10396,10397],{"class":446},"host",[436,10399,5282],{"class":5281},[436,10401,6000],{"class":1144},[436,10403,6871],{"class":5159},[436,10405,5164],{"class":5163},[436,10407,5282],{"class":5281},[436,10409,10410],{"class":446},"MEILISEARCH_HOST",[436,10412,5282],{"class":5281},[436,10414,5177],{"class":5163},[436,10416,6064],{"class":5281},[436,10418,10419],{"class":446},"http://localhost:7700",[436,10421,5282],{"class":5281},[436,10423,10248],{"class":5163},[436,10425,10426,10428,10430,10432,10434,10436,10438,10440,10443,10445],{"class":438,"line":9812},[436,10427,10331],{"class":5281},[436,10429,341],{"class":446},[436,10431,5282],{"class":5281},[436,10433,6000],{"class":1144},[436,10435,6871],{"class":5159},[436,10437,5164],{"class":5163},[436,10439,5282],{"class":5281},[436,10441,10442],{"class":446},"MEILISEARCH_KEY",[436,10444,5282],{"class":5281},[436,10446,10248],{"class":5163},[436,10448,10449],{"class":438,"line":9825},[436,10450,10368],{"class":5163},[436,10452,10453],{"class":438,"line":9830},[436,10454,10455],{"class":5163},"    ],\n",[436,10457,10458],{"class":438,"line":9841},[436,10459,9553],{"class":5163},[347,10461,6453],{"id":10462},"cli-commands",[428,10464,10466],{"className":430,"code":10465,"language":432,"meta":320,"style":320},"# Generate a filter class\nphp glueful scaffold:filter UserFilter\n\n# Generate with specific model\nphp glueful scaffold:filter UserFilter --model=User\n\n# Generate with custom fields\nphp glueful scaffold:filter ProductFilter --fields=name,price,category,status\n",[325,10467,10468,10473,10485,10489,10494,10507,10511,10516],{"__ignoreMap":320},[436,10469,10470],{"class":438,"line":439},[436,10471,10472],{"class":1168},"# Generate a filter class\n",[436,10474,10475,10477,10479,10482],{"class":438,"line":1132},[436,10476,1135],{"class":442},[436,10478,1138],{"class":446},[436,10480,10481],{"class":446}," scaffold:filter",[436,10483,10484],{"class":446}," UserFilter\n",[436,10486,10487],{"class":438,"line":1158},[436,10488,5212],{"emptyLinePlaceholder":5211},[436,10490,10491],{"class":438,"line":5196},[436,10492,10493],{"class":1168},"# Generate with specific model\n",[436,10495,10496,10498,10500,10502,10504],{"class":438,"line":5202},[436,10497,1135],{"class":442},[436,10499,1138],{"class":446},[436,10501,10481],{"class":446},[436,10503,9487],{"class":446},[436,10505,10506],{"class":5565}," --model=User\n",[436,10508,10509],{"class":438,"line":5208},[436,10510,5212],{"emptyLinePlaceholder":5211},[436,10512,10513],{"class":438,"line":5215},[436,10514,10515],{"class":1168},"# Generate with custom fields\n",[436,10517,10518,10520,10522,10524,10527],{"class":438,"line":5221},[436,10519,1135],{"class":442},[436,10521,1138],{"class":446},[436,10523,10481],{"class":446},[436,10525,10526],{"class":446}," ProductFilter",[436,10528,10529],{"class":5565}," --fields=name,price,category,status\n",[452,10531],{},[301,10533,10535],{"id":10534},"v1180-hadar-minor","v1.18.0 - Hadar (Minor)",[293,10537,10538],{},[308,10539,8692],{},[312,10541,10543],{"color":314,"icon":10542,"variant":316},"i-tabler-webhook",[318,10544,10545],{"v-slot:description":320},[293,10546,10547],{},"Feature release introducing a comprehensive Webhooks System with event-driven integrations, subscription management, HMAC signature verification, and reliable delivery with exponential backoff retry.",[347,10549,350],{"id":10550},"key-highlights-33",[352,10552,10553,10558],{},[293,10554,10555],{},[308,10556,10557],{},"Event-Based Subscriptions",[415,10559,10560,10569,10572],{},[418,10561,10562,10563,332,10566,4887],{},"Subscribe to specific events or wildcard patterns (",[325,10564,10565],{},"user.*",[325,10567,10568],{},"*",[418,10570,10571],{},"Multiple event patterns per subscription",[418,10573,10574,10577,10578,10581],{},[325,10575,10576],{},"WebhookSubscription"," ORM model with ",[325,10579,10580],{},"listensTo()"," wildcard matching",[352,10583,10584,10589],{},[293,10585,10586],{},[308,10587,10588],{},"HMAC-SHA256 Signatures",[415,10590,10591,10597,10600,10603],{},[418,10592,10593,10594,4887],{},"Stripe-style signature format (",[325,10595,10596],{},"t=timestamp,v1=signature",[418,10598,10599],{},"Timing-safe comparison to prevent timing attacks",[418,10601,10602],{},"Timestamp validation to prevent replay attacks",[418,10604,10605],{},"Configurable tolerance for signature expiration",[352,10607,10608,10613],{},[293,10609,10610],{},[308,10611,10612],{},"Reliable Delivery System",[415,10614,10615,10621,10624,10627],{},[418,10616,10617,10618],{},"Queue-based delivery via ",[325,10619,10620],{},"DeliverWebhookJob",[418,10622,10623],{},"Exponential backoff retry: 1m, 5m, 30m, 2h, 12h",[418,10625,10626],{},"Maximum 5 retry attempts (configurable)",[418,10628,10629,10632],{},[325,10630,10631],{},"WebhookDelivery"," ORM model for tracking",[352,10634,10635,10640],{},[293,10636,10637],{},[308,10638,10639],{},"Auto-Migration",[415,10641,10642,10645,10652],{},[418,10643,10644],{},"Database tables created automatically on first use",[418,10646,10647,10648,10651],{},"Follows ",[325,10649,10650],{},"DatabaseLogHandler"," pattern",[418,10653,10654],{},"Zero configuration required",[347,10656,10658],{"id":10657},"webhooks-components","Webhooks Components",[293,10660,10661],{},[308,10662,8987],{},[5285,10664,10665,10673],{},[8831,10666,10667],{},[8834,10668,10669,10671],{},[8837,10670,8996],{},[8837,10672,8999],{},[8843,10674,10675,10685,10694,10703,10713,10723],{},[8834,10676,10677,10682],{},[8848,10678,10679],{},[325,10680,10681],{},"WebhookDispatcher",[8848,10683,10684],{},"Central dispatcher with auto-migration",[8834,10686,10687,10691],{},[8848,10688,10689],{},[325,10690,10576],{},[8848,10692,10693],{},"ORM model for subscriptions",[8834,10695,10696,10700],{},[8848,10697,10698],{},[325,10699,10631],{},[8848,10701,10702],{},"ORM model for delivery tracking",[8834,10704,10705,10710],{},[8848,10706,10707],{},[325,10708,10709],{},"WebhookSignature",[8848,10711,10712],{},"HMAC signature generation/verification",[8834,10714,10715,10720],{},[8848,10716,10717],{},[325,10718,10719],{},"WebhookPayload",[8848,10721,10722],{},"Standardized payload builder",[8834,10724,10725,10729],{},[8848,10726,10727],{},[325,10728,4228],{},[8848,10730,10731],{},"Static facade for easy access",[293,10733,10734],{},[308,10735,10736],{},"Event Integration:",[5285,10738,10739,10747],{},[8831,10740,10741],{},[8834,10742,10743,10745],{},[8837,10744,8996],{},[8837,10746,8999],{},[8843,10748,10749,10759,10769,10779],{},[8834,10750,10751,10756],{},[8848,10752,10753],{},[325,10754,10755],{},"DispatchesWebhooks",[8848,10757,10758],{},"Trait for webhookable events",[8834,10760,10761,10766],{},[8848,10762,10763],{},[325,10764,10765],{},"#[Webhookable]",[8848,10767,10768],{},"PHP 8 attribute for marking events",[8834,10770,10771,10776],{},[8848,10772,10773],{},[325,10774,10775],{},"WebhookEventListener",[8848,10777,10778],{},"Bridge app events to webhooks",[8834,10780,10781,10786],{},[8848,10782,10783],{},[325,10784,10785],{},"WebhookDispatchedEvent",[8848,10787,10788],{},"Event fired when webhooks queued",[293,10790,10791],{},[308,10792,10793],{},"CLI Commands:",[5285,10795,10796,10805],{},[8831,10797,10798],{},[8834,10799,10800,10803],{},[8837,10801,10802],{},"Command",[8837,10804,8999],{},[8843,10806,10807,10817,10827],{},[8834,10808,10809,10814],{},[8848,10810,10811],{},[325,10812,10813],{},"webhook:list",[8848,10815,10816],{},"List all webhook subscriptions",[8834,10818,10819,10824],{},[8848,10820,10821],{},[325,10822,10823],{},"webhook:test",[8848,10825,10826],{},"Test a webhook endpoint",[8834,10828,10829,10834],{},[8848,10830,10831],{},[325,10832,10833],{},"webhook:retry",[8848,10835,10836],{},"Retry failed webhook deliveries",[347,10838,10840],{"id":10839},"rest-api-endpoints","REST API Endpoints",[5285,10842,10843,10855],{},[8831,10844,10845],{},[8834,10846,10847,10850,10853],{},[8837,10848,10849],{},"Method",[8837,10851,10852],{},"Endpoint",[8837,10854,8999],{},[8843,10856,10857,10871,10885,10899,10912,10926,10940,10954],{},[8834,10858,10859,10863,10868],{},[8848,10860,10861],{},[325,10862,7153],{},[8848,10864,10865],{},[325,10866,10867],{},"/api/webhooks/subscriptions",[8848,10869,10870],{},"Create subscription",[8834,10872,10873,10878,10882],{},[8848,10874,10875],{},[325,10876,10877],{},"GET",[8848,10879,10880],{},[325,10881,10867],{},[8848,10883,10884],{},"List subscriptions",[8834,10886,10887,10891,10896],{},[8848,10888,10889],{},[325,10890,10877],{},[8848,10892,10893],{},[325,10894,10895],{},"/api/webhooks/subscriptions/{id}",[8848,10897,10898],{},"Get subscription",[8834,10900,10901,10905,10909],{},[8848,10902,10903],{},[325,10904,683],{},[8848,10906,10907],{},[325,10908,10895],{},[8848,10910,10911],{},"Update subscription",[8834,10913,10914,10919,10923],{},[8848,10915,10916],{},[325,10917,10918],{},"DELETE",[8848,10920,10921],{},[325,10922,10895],{},[8848,10924,10925],{},"Delete subscription",[8834,10927,10928,10932,10937],{},[8848,10929,10930],{},[325,10931,7153],{},[8848,10933,10934],{},[325,10935,10936],{},"/api/webhooks/subscriptions/{id}/test",[8848,10938,10939],{},"Send test webhook",[8834,10941,10942,10946,10951],{},[8848,10943,10944],{},[325,10945,10877],{},[8848,10947,10948],{},[325,10949,10950],{},"/api/webhooks/deliveries",[8848,10952,10953],{},"List deliveries",[8834,10955,10956,10960,10965],{},[8848,10957,10958],{},[325,10959,7153],{},[8848,10961,10962],{},[325,10963,10964],{},"/api/webhooks/deliveries/{id}/retry",[8848,10966,10967],{},"Retry delivery",[347,10969,9391],{"id":10970},"quick-usage-1",[428,10972,10974],{"className":5139,"code":10973,"language":1135,"meta":320,"style":320},"use Glueful\\Api\\Webhooks\\Webhook;\nuse Glueful\\Api\\Webhooks\\WebhookSignature;\n\n// Dispatch a webhook\nWebhook::dispatch('user.created', ['user' => $userData]);\n\n// Create a subscription\n$subscription = Webhook::subscribe(\n    ['user.*', 'order.completed'],\n    'https://example.com/webhooks'\n);\n\n// Make an event webhookable\nclass UserCreated extends BaseEvent\n{\n    use DispatchesWebhooks;\n\n    public function webhookEventName(): string\n    {\n        return 'user.created';\n    }\n\n    public function webhookPayload(): array\n    {\n        return ['user' => $this->user];\n    }\n}\n\n// Verify webhook signature (for receiving webhooks)\n$isValid = WebhookSignature::verify(\n    $payload,\n    $request->headers->get('X-Webhook-Signature'),\n    $secret\n);\n",[325,10975,10976,10997,11017,11021,11026,11064,11068,11073,11092,11114,11124,11128,11132,11137,11149,11153,11162,11166,11183,11188,11201,11206,11210,11226,11230,11252,11256,11260,11264,11269,11288,11297,11323,11330],{"__ignoreMap":320},[436,10977,10978,10980,10982,10984,10986,10988,10991,10993,10995],{"class":438,"line":439},[436,10979,6516],{"class":5167},[436,10981,6520],{"class":6519},[436,10983,6524],{"class":6523},[436,10985,9407],{"class":6519},[436,10987,6524],{"class":6523},[436,10989,10990],{"class":6519},"Webhooks",[436,10992,6524],{"class":6523},[436,10994,4228],{"class":6532},[436,10996,5816],{"class":5163},[436,10998,10999,11001,11003,11005,11007,11009,11011,11013,11015],{"class":438,"line":1132},[436,11000,6516],{"class":5167},[436,11002,6520],{"class":6519},[436,11004,6524],{"class":6523},[436,11006,9407],{"class":6519},[436,11008,6524],{"class":6523},[436,11010,10990],{"class":6519},[436,11012,6524],{"class":6523},[436,11014,10709],{"class":6532},[436,11016,5816],{"class":5163},[436,11018,11019],{"class":438,"line":1158},[436,11020,5212],{"emptyLinePlaceholder":5211},[436,11022,11023],{"class":438,"line":5196},[436,11024,11025],{"class":1168},"// Dispatch a webhook\n",[436,11027,11028,11030,11032,11035,11037,11039,11042,11044,11046,11048,11050,11053,11055,11057,11059,11062],{"class":438,"line":5202},[436,11029,4228],{"class":5233},[436,11031,6056],{"class":1144},[436,11033,11034],{"class":5159},"dispatch",[436,11036,5164],{"class":5163},[436,11038,5282],{"class":5281},[436,11040,11041],{"class":446},"user.created",[436,11043,5282],{"class":5281},[436,11045,5177],{"class":5163},[436,11047,6050],{"class":5163},[436,11049,5282],{"class":5281},[436,11051,11052],{"class":446},"user",[436,11054,5282],{"class":5281},[436,11056,6000],{"class":1144},[436,11058,5171],{"class":5163},[436,11060,11061],{"class":1151},"userData",[436,11063,6072],{"class":5163},[436,11065,11066],{"class":438,"line":5208},[436,11067,5212],{"emptyLinePlaceholder":5211},[436,11069,11070],{"class":438,"line":5215},[436,11071,11072],{"class":1168},"// Create a subscription\n",[436,11074,11075,11077,11080,11082,11085,11087,11090],{"class":438,"line":5221},[436,11076,5761],{"class":5163},[436,11078,11079],{"class":1151},"subscription ",[436,11081,3168],{"class":1144},[436,11083,11084],{"class":5233}," Webhook",[436,11086,6056],{"class":1144},[436,11088,11089],{"class":5159},"subscribe",[436,11091,6925],{"class":5163},[436,11093,11094,11097,11099,11101,11103,11105,11107,11110,11112],{"class":438,"line":5249},[436,11095,11096],{"class":5163},"    [",[436,11098,5282],{"class":5281},[436,11100,10565],{"class":446},[436,11102,5282],{"class":5281},[436,11104,5177],{"class":5163},[436,11106,6064],{"class":5281},[436,11108,11109],{"class":446},"order.completed",[436,11111,5282],{"class":5281},[436,11113,9553],{"class":5163},[436,11115,11116,11118,11121],{"class":438,"line":5254},[436,11117,6862],{"class":5281},[436,11119,11120],{"class":446},"https://example.com/webhooks",[436,11122,11123],{"class":5281},"'\n",[436,11125,11126],{"class":438,"line":5298},[436,11127,5295],{"class":5163},[436,11129,11130],{"class":438,"line":5324},[436,11131,5212],{"emptyLinePlaceholder":5211},[436,11133,11134],{"class":438,"line":5329},[436,11135,11136],{"class":1168},"// Make an event webhookable\n",[436,11138,11139,11141,11144,11146],{"class":438,"line":6717},[436,11140,6059],{"class":5155},[436,11142,11143],{"class":9486}," UserCreated",[436,11145,9490],{"class":5152},[436,11147,11148],{"class":9493}," BaseEvent\n",[436,11150,11151],{"class":438,"line":6742},[436,11152,5193],{"class":5163},[436,11154,11155,11157,11160],{"class":438,"line":6767},[436,11156,9833],{"class":5167},[436,11158,11159],{"class":6532}," DispatchesWebhooks",[436,11161,5816],{"class":5163},[436,11163,11164],{"class":438,"line":6772},[436,11165,5212],{"emptyLinePlaceholder":5211},[436,11167,11168,11171,11173,11176,11178,11180],{"class":438,"line":6778},[436,11169,11170],{"class":5152},"    public",[436,11172,5156],{"class":5155},[436,11174,11175],{"class":5159}," webhookEventName",[436,11177,7677],{"class":5163},[436,11179,5243],{"class":1144},[436,11181,11182],{"class":5167}," string\n",[436,11184,11185],{"class":438,"line":6810},[436,11186,11187],{"class":5163},"    {\n",[436,11189,11190,11193,11195,11197,11199],{"class":438,"line":9754},[436,11191,11192],{"class":5788},"        return",[436,11194,6064],{"class":5281},[436,11196,11041],{"class":446},[436,11198,5282],{"class":5281},[436,11200,5816],{"class":5163},[436,11202,11203],{"class":438,"line":9801},[436,11204,11205],{"class":5163},"    }\n",[436,11207,11208],{"class":438,"line":9806},[436,11209,5212],{"emptyLinePlaceholder":5211},[436,11211,11212,11214,11216,11219,11221,11223],{"class":438,"line":9812},[436,11213,11170],{"class":5152},[436,11215,5156],{"class":5155},[436,11217,11218],{"class":5159}," webhookPayload",[436,11220,7677],{"class":5163},[436,11222,5243],{"class":1144},[436,11224,11225],{"class":5167}," array\n",[436,11227,11228],{"class":438,"line":9825},[436,11229,11187],{"class":5163},[436,11231,11232,11234,11236,11238,11240,11242,11244,11246,11248,11250],{"class":438,"line":9830},[436,11233,11192],{"class":5788},[436,11235,6050],{"class":5163},[436,11237,5282],{"class":5281},[436,11239,11052],{"class":446},[436,11241,5282],{"class":5281},[436,11243,6000],{"class":1144},[436,11245,5770],{"class":5769},[436,11247,5269],{"class":1144},[436,11249,11052],{"class":1151},[436,11251,6968],{"class":5163},[436,11253,11254],{"class":438,"line":9841},[436,11255,11205],{"class":5163},[436,11257,11258],{"class":438,"line":9846},[436,11259,5205],{"class":5163},[436,11261,11262],{"class":438,"line":9887},[436,11263,5212],{"emptyLinePlaceholder":5211},[436,11265,11266],{"class":438,"line":9892},[436,11267,11268],{"class":1168},"// Verify webhook signature (for receiving webhooks)\n",[436,11270,11271,11273,11276,11278,11281,11283,11286],{"class":438,"line":9897},[436,11272,5761],{"class":5163},[436,11274,11275],{"class":1151},"isValid ",[436,11277,3168],{"class":1144},[436,11279,11280],{"class":5233}," WebhookSignature",[436,11282,6056],{"class":1144},[436,11284,11285],{"class":5159},"verify",[436,11287,6925],{"class":5163},[436,11289,11290,11292,11295],{"class":438,"line":9903},[436,11291,5257],{"class":5163},[436,11293,11294],{"class":1151},"payload",[436,11296,6907],{"class":5163},[436,11298,11299,11301,11303,11305,11308,11310,11312,11314,11316,11319,11321],{"class":438,"line":9933},[436,11300,5257],{"class":5163},[436,11302,5238],{"class":1151},[436,11304,5269],{"class":1144},[436,11306,11307],{"class":1151},"headers",[436,11309,5269],{"class":1144},[436,11311,715],{"class":5159},[436,11313,5164],{"class":5163},[436,11315,5282],{"class":5281},[436,11317,11318],{"class":446},"X-Webhook-Signature",[436,11320,5282],{"class":5281},[436,11322,10248],{"class":5163},[436,11324,11325,11327],{"class":438,"line":9963},[436,11326,5257],{"class":5163},[436,11328,11329],{"class":1151},"secret\n",[436,11331,11332],{"class":438,"line":9979},[436,11333,5295],{"class":5163},[347,11335,11337],{"id":11336},"webhook-payload-structure","Webhook Payload Structure",[428,11339,11342],{"className":11340,"code":11341,"language":2013,"meta":320,"style":320},"language-json shiki shiki-themes material-theme-lighter github-light github-dark monokai","{\n    \"id\": \"wh_evt_01HXYZ123456789ABCDEF\",\n    \"event\": \"user.created\",\n    \"created_at\": \"2026-01-22T12:00:00+00:00\",\n    \"data\": {\n        \"user\": {\n            \"id\": \"usr_01HXYZ987654321FEDCBA\",\n            \"email\": \"john@example.com\",\n            \"name\": \"John Doe\"\n        }\n    }\n}\n",[325,11343,11344,11348,11371,11390,11409,11422,11435,11456,11475,11492,11497,11501],{"__ignoreMap":320},[436,11345,11346],{"class":438,"line":439},[436,11347,5193],{"class":5163},[436,11349,11350,11353,11356,11358,11360,11363,11367,11369],{"class":438,"line":1132},[436,11351,7168],{"class":11352},"saDeg",[436,11354,1822],{"class":11355},"sEff5",[436,11357,7174],{"class":11352},[436,11359,5243],{"class":5163},[436,11361,7179],{"class":11362},"sh1VR",[436,11364,11366],{"class":11365},"sINAO","wh_evt_01HXYZ123456789ABCDEF",[436,11368,7174],{"class":11362},[436,11370,6907],{"class":5163},[436,11372,11373,11375,11378,11380,11382,11384,11386,11388],{"class":438,"line":1158},[436,11374,7168],{"class":11352},[436,11376,11377],{"class":11355},"event",[436,11379,7174],{"class":11352},[436,11381,5243],{"class":5163},[436,11383,7179],{"class":11362},[436,11385,11041],{"class":11365},[436,11387,7174],{"class":11362},[436,11389,6907],{"class":5163},[436,11391,11392,11394,11396,11398,11400,11402,11405,11407],{"class":438,"line":5196},[436,11393,7168],{"class":11352},[436,11395,9625],{"class":11355},[436,11397,7174],{"class":11352},[436,11399,5243],{"class":5163},[436,11401,7179],{"class":11362},[436,11403,11404],{"class":11365},"2026-01-22T12:00:00+00:00",[436,11406,7174],{"class":11362},[436,11408,6907],{"class":5163},[436,11410,11411,11413,11416,11418,11420],{"class":438,"line":5202},[436,11412,7168],{"class":11352},[436,11414,11415],{"class":11355},"data",[436,11417,7174],{"class":11352},[436,11419,5243],{"class":5163},[436,11421,5803],{"class":5163},[436,11423,11424,11427,11429,11431,11433],{"class":438,"line":5208},[436,11425,11426],{"class":11352},"        \"",[436,11428,11052],{"class":5233},[436,11430,7174],{"class":11352},[436,11432,5243],{"class":5163},[436,11434,5803],{"class":5163},[436,11436,11437,11440,11443,11445,11447,11449,11452,11454],{"class":438,"line":5215},[436,11438,11439],{"class":11352},"            \"",[436,11441,1822],{"class":11442},"sTC9v",[436,11444,7174],{"class":11352},[436,11446,5243],{"class":5163},[436,11448,7179],{"class":11362},[436,11450,11451],{"class":11365},"usr_01HXYZ987654321FEDCBA",[436,11453,7174],{"class":11362},[436,11455,6907],{"class":5163},[436,11457,11458,11460,11462,11464,11466,11468,11471,11473],{"class":438,"line":5221},[436,11459,11439],{"class":11352},[436,11461,2688],{"class":11442},[436,11463,7174],{"class":11352},[436,11465,5243],{"class":5163},[436,11467,7179],{"class":11362},[436,11469,11470],{"class":11365},"john@example.com",[436,11472,7174],{"class":11362},[436,11474,6907],{"class":5163},[436,11476,11477,11479,11481,11483,11485,11487,11490],{"class":438,"line":5249},[436,11478,11439],{"class":11352},[436,11480,9522],{"class":11442},[436,11482,7174],{"class":11352},[436,11484,5243],{"class":5163},[436,11486,7179],{"class":11362},[436,11488,11489],{"class":11365},"John Doe",[436,11491,7203],{"class":11362},[436,11493,11494],{"class":438,"line":5254},[436,11495,11496],{"class":5163},"        }\n",[436,11498,11499],{"class":438,"line":5298},[436,11500,11205],{"class":5163},[436,11502,11503],{"class":438,"line":5324},[436,11504,5205],{"class":5163},[347,11506,11508],{"id":11507},"webhook-headers","Webhook Headers",[5285,11510,11511,11522],{},[8831,11512,11513],{},[8834,11514,11515,11518,11520],{},[8837,11516,11517],{},"Header",[8837,11519,9121],{},[8837,11521,9124],{},[8843,11523,11524,11539,11553,11568,11582,11597],{},[8834,11525,11526,11531,11534],{},[8848,11527,11528],{},[325,11529,11530],{},"X-Webhook-ID",[8848,11532,11533],{},"Unique delivery ID",[8848,11535,11536],{},[325,11537,11538],{},"wh_del_01HXYZ...",[8834,11540,11541,11546,11549],{},[8848,11542,11543],{},[325,11544,11545],{},"X-Webhook-Event",[8848,11547,11548],{},"Event name",[8848,11550,11551],{},[325,11552,11041],{},[8834,11554,11555,11560,11563],{},[8848,11556,11557],{},[325,11558,11559],{},"X-Webhook-Timestamp",[8848,11561,11562],{},"Unix timestamp",[8848,11564,11565],{},[325,11566,11567],{},"1706011200",[8834,11569,11570,11574,11577],{},[8848,11571,11572],{},[325,11573,11318],{},[8848,11575,11576],{},"HMAC signature",[8848,11578,11579],{},[325,11580,11581],{},"t=1706011200,v1=abc...",[8834,11583,11584,11589,11592],{},[8848,11585,11586],{},[325,11587,11588],{},"Content-Type",[8848,11590,11591],{},"Always JSON",[8848,11593,11594],{},[325,11595,11596],{},"application/json",[8834,11598,11599,11604,11607],{},[8848,11600,11601],{},[325,11602,11603],{},"User-Agent",[8848,11605,11606],{},"Glueful identifier",[8848,11608,11609],{},[325,11610,11611],{},"Glueful-Webhooks/1.0",[347,11613,121],{"id":11614},"configuration-2",[428,11616,11618],{"className":5139,"code":11617,"language":1135,"meta":320,"style":320},"// config/api.php\n'webhooks' => [\n    'enabled' => true,\n    'queue' => 'webhooks',\n    'connection' => null,\n    'signature_header' => 'X-Webhook-Signature',\n    'signature_algorithm' => 'sha256',\n    'timeout' => 30,\n    'user_agent' => 'Glueful-Webhooks/1.0',\n    'retry' => [\n        'max_attempts' => 5,\n        'backoff' => [60, 300, 1800, 7200, 43200],\n    ],\n    'require_https' => true,\n    'cleanup' => [\n        'keep_successful_days' => 7,\n        'keep_failed_days' => 30,\n    ],\n]\n",[325,11619,11620,11624,11636,11650,11669,11685,11704,11724,11740,11759,11772,11788,11825,11829,11844,11857,11873,11888,11892],{"__ignoreMap":320},[436,11621,11622],{"class":438,"line":439},[436,11623,10111],{"class":1168},[436,11625,11626,11628,11630,11632,11634],{"class":438,"line":1132},[436,11627,5282],{"class":5281},[436,11629,2733],{"class":446},[436,11631,5282],{"class":5281},[436,11633,6000],{"class":1144},[436,11635,6857],{"class":5163},[436,11637,11638,11640,11642,11644,11646,11648],{"class":438,"line":1158},[436,11639,6862],{"class":5281},[436,11641,883],{"class":446},[436,11643,5282],{"class":5281},[436,11645,6000],{"class":1144},[436,11647,10187],{"class":10170},[436,11649,6907],{"class":5163},[436,11651,11652,11654,11657,11659,11661,11663,11665,11667],{"class":438,"line":5196},[436,11653,6862],{"class":5281},[436,11655,11656],{"class":446},"queue",[436,11658,5282],{"class":5281},[436,11660,6000],{"class":1144},[436,11662,6064],{"class":5281},[436,11664,2733],{"class":446},[436,11666,5282],{"class":5281},[436,11668,6907],{"class":5163},[436,11670,11671,11673,11676,11678,11680,11683],{"class":438,"line":5202},[436,11672,6862],{"class":5281},[436,11674,11675],{"class":446},"connection",[436,11677,5282],{"class":5281},[436,11679,6000],{"class":1144},[436,11681,11682],{"class":10170}," null",[436,11684,6907],{"class":5163},[436,11686,11687,11689,11692,11694,11696,11698,11700,11702],{"class":438,"line":5208},[436,11688,6862],{"class":5281},[436,11690,11691],{"class":446},"signature_header",[436,11693,5282],{"class":5281},[436,11695,6000],{"class":1144},[436,11697,6064],{"class":5281},[436,11699,11318],{"class":446},[436,11701,5282],{"class":5281},[436,11703,6907],{"class":5163},[436,11705,11706,11708,11711,11713,11715,11717,11720,11722],{"class":438,"line":5215},[436,11707,6862],{"class":5281},[436,11709,11710],{"class":446},"signature_algorithm",[436,11712,5282],{"class":5281},[436,11714,6000],{"class":1144},[436,11716,6064],{"class":5281},[436,11718,11719],{"class":446},"sha256",[436,11721,5282],{"class":5281},[436,11723,6907],{"class":5163},[436,11725,11726,11728,11731,11733,11735,11738],{"class":438,"line":5221},[436,11727,6862],{"class":5281},[436,11729,11730],{"class":446},"timeout",[436,11732,5282],{"class":5281},[436,11734,6000],{"class":1144},[436,11736,11737],{"class":7256}," 30",[436,11739,6907],{"class":5163},[436,11741,11742,11744,11747,11749,11751,11753,11755,11757],{"class":438,"line":5249},[436,11743,6862],{"class":5281},[436,11745,11746],{"class":446},"user_agent",[436,11748,5282],{"class":5281},[436,11750,6000],{"class":1144},[436,11752,6064],{"class":5281},[436,11754,11611],{"class":446},[436,11756,5282],{"class":5281},[436,11758,6907],{"class":5163},[436,11760,11761,11763,11766,11768,11770],{"class":438,"line":5254},[436,11762,6862],{"class":5281},[436,11764,11765],{"class":446},"retry",[436,11767,5282],{"class":5281},[436,11769,6000],{"class":1144},[436,11771,6857],{"class":5163},[436,11773,11774,11776,11779,11781,11783,11786],{"class":438,"line":5298},[436,11775,9519],{"class":5281},[436,11777,11778],{"class":446},"max_attempts",[436,11780,5282],{"class":5281},[436,11782,6000],{"class":1144},[436,11784,11785],{"class":7256}," 5",[436,11787,6907],{"class":5163},[436,11789,11790,11792,11795,11797,11799,11801,11804,11806,11809,11811,11814,11816,11818,11820,11823],{"class":438,"line":5324},[436,11791,9519],{"class":5281},[436,11793,11794],{"class":446},"backoff",[436,11796,5282],{"class":5281},[436,11798,6000],{"class":1144},[436,11800,6050],{"class":5163},[436,11802,11803],{"class":7256},"60",[436,11805,5177],{"class":5163},[436,11807,11808],{"class":7256}," 300",[436,11810,5177],{"class":5163},[436,11812,11813],{"class":7256}," 1800",[436,11815,5177],{"class":5163},[436,11817,7323],{"class":7256},[436,11819,5177],{"class":5163},[436,11821,11822],{"class":7256}," 43200",[436,11824,9553],{"class":5163},[436,11826,11827],{"class":438,"line":5329},[436,11828,10455],{"class":5163},[436,11830,11831,11833,11836,11838,11840,11842],{"class":438,"line":6717},[436,11832,6862],{"class":5281},[436,11834,11835],{"class":446},"require_https",[436,11837,5282],{"class":5281},[436,11839,6000],{"class":1144},[436,11841,10187],{"class":10170},[436,11843,6907],{"class":5163},[436,11845,11846,11848,11851,11853,11855],{"class":438,"line":6742},[436,11847,6862],{"class":5281},[436,11849,11850],{"class":446},"cleanup",[436,11852,5282],{"class":5281},[436,11854,6000],{"class":1144},[436,11856,6857],{"class":5163},[436,11858,11859,11861,11864,11866,11868,11871],{"class":438,"line":6767},[436,11860,9519],{"class":5281},[436,11862,11863],{"class":446},"keep_successful_days",[436,11865,5282],{"class":5281},[436,11867,6000],{"class":1144},[436,11869,11870],{"class":7256}," 7",[436,11872,6907],{"class":5163},[436,11874,11875,11877,11880,11882,11884,11886],{"class":438,"line":6772},[436,11876,9519],{"class":5281},[436,11878,11879],{"class":446},"keep_failed_days",[436,11881,5282],{"class":5281},[436,11883,6000],{"class":1144},[436,11885,11737],{"class":7256},[436,11887,6907],{"class":5163},[436,11889,11890],{"class":438,"line":6778},[436,11891,10455],{"class":5163},[436,11893,11894],{"class":438,"line":6810},[436,11895,11896],{"class":5163},"]\n",[347,11898,413],{"id":11899},"migration-notes-23",[312,11901,11903],{"color":3075,"icon":11902,"variant":316},"i-tabler-info-circle",[318,11904,11905],{"v-slot:description":320},[293,11906,11907],{},"No breaking changes. The Webhooks System is opt-in and additive. Database tables are created automatically on first use.",[415,11909,11910,11920,11923],{},[418,11911,11912,11913,542,11916,11919],{},"Auto-migration creates ",[325,11914,11915],{},"webhook_subscriptions",[325,11917,11918],{},"webhook_deliveries"," tables",[418,11921,11922],{},"Webhooks are delivered asynchronously via the queue system",[418,11924,11925,11926,542,11929],{},"Integrates with existing ",[325,11927,11928],{},"WebhookDeliveredEvent",[325,11930,11931],{},"WebhookFailedEvent",[452,11933],{},[301,11935,11937],{"id":11936},"v1170-alnitak-minor","v1.17.0 - Alnitak (Minor)",[293,11939,11940],{},[308,11941,8692],{},[312,11943,11944],{"color":314,"icon":1697,"variant":316},[318,11945,11946],{"v-slot:description":320},[293,11947,11948],{},"Feature release introducing comprehensive Rate Limiting Enhancements with per-route limits, tiered access, cost-based limiting, and multiple algorithms.",[347,11950,350],{"id":11951},"key-highlights-34",[352,11953,11954,11959],{},[293,11955,11956],{},[308,11957,11958],{},"Per-Route Rate Limiting",[415,11960,11961,11966,11969],{},[418,11962,11963,11965],{},[325,11964,2313],{}," attribute for declarative rate limiting on controllers and methods",[418,11967,11968],{},"IS_REPEATABLE for defining multiple time windows (e.g., per-minute AND per-hour limits)",[418,11970,11971],{},"Configurable by tier, key pattern, algorithm, and identifier (IP, user, custom)",[352,11973,11974,11979],{},[293,11975,11976],{},[308,11977,11978],{},"Tiered Rate Limiting",[415,11980,11981,11996,11999,12005],{},[418,11982,11983,11984,332,11987,332,11990,332,11993],{},"Built-in tiers: ",[325,11985,11986],{},"anonymous",[325,11988,11989],{},"free",[325,11991,11992],{},"pro",[325,11994,11995],{},"enterprise",[418,11997,11998],{},"Per-tier limits for minute, hour, and day windows",[418,12000,12001,12004],{},[325,12002,12003],{},"TierResolver"," for automatic tier detection from request user data",[418,12006,12007],{},"Unlimited tier support for enterprise users",[352,12009,12010,12015],{},[293,12011,12012],{},[308,12013,12014],{},"Multiple Algorithms",[415,12016,12017,12020,12023],{},[418,12018,12019],{},"Fixed Window - Simple time-window counting",[418,12021,12022],{},"Sliding Window - More accurate request distribution using sorted sets",[418,12024,12025],{},"Token Bucket - Burst-friendly with refill rate calculation",[352,12027,12028,12033],{},[293,12029,12030],{},[308,12031,12032],{},"Cost-Based Limiting",[415,12034,12035,12041,12044],{},[418,12036,12037,12040],{},[325,12038,12039],{},"#[RateLimitCost]"," attribute for expensive operations",[418,12042,12043],{},"Consume multiple units per request (e.g., exports cost 100 units)",[418,12045,12046],{},"Reason tracking for cost documentation",[347,12048,12050],{"id":12049},"rate-limiting-components","Rate Limiting Components",[293,12052,12053],{},[308,12054,8987],{},[5285,12056,12057,12065],{},[8831,12058,12059],{},[8834,12060,12061,12063],{},[8837,12062,8996],{},[8837,12064,8999],{},[8843,12066,12067,12077,12087,12096,12106],{},[8834,12068,12069,12074],{},[8848,12070,12071],{},[325,12072,12073],{},"RateLimitManager",[8848,12075,12076],{},"Central orchestrator for rate limiting operations",[8834,12078,12079,12084],{},[8848,12080,12081],{},[325,12082,12083],{},"TierManager",[8848,12085,12086],{},"Tier configuration and limit lookup",[8834,12088,12089,12093],{},[8848,12090,12091],{},[325,12092,12003],{},[8848,12094,12095],{},"Resolve user tier from request",[8834,12097,12098,12103],{},[8848,12099,12100],{},[325,12101,12102],{},"RateLimitHeaders",[8848,12104,12105],{},"IETF-compliant header generation",[8834,12107,12108,12113],{},[8848,12109,12110],{},[325,12111,12112],{},"RateLimitResult",[8848,12114,12115],{},"Immutable result value object",[293,12117,12118],{},[308,12119,12120],{},"Limiters:",[5285,12122,12123,12132],{},[8831,12124,12125],{},[8834,12126,12127,12129],{},[8837,12128,8996],{},[8837,12130,12131],{},"Algorithm",[8843,12133,12134,12144,12154],{},[8834,12135,12136,12141],{},[8848,12137,12138],{},[325,12139,12140],{},"FixedWindowLimiter",[8848,12142,12143],{},"Simple fixed time window",[8834,12145,12146,12151],{},[8848,12147,12148],{},[325,12149,12150],{},"SlidingWindowLimiter",[8848,12152,12153],{},"Sliding window using sorted sets",[8834,12155,12156,12161],{},[8848,12157,12158],{},[325,12159,12160],{},"TokenBucketLimiter",[8848,12162,12163],{},"Token bucket with burst support",[293,12165,12166],{},[308,12167,12168],{},"Storage Backends:",[5285,12170,12171,12179],{},[8831,12172,12173],{},[8834,12174,12175,12177],{},[8837,12176,8996],{},[8837,12178,8999],{},[8843,12180,12181,12194],{},[8834,12182,12183,12188],{},[8848,12184,12185],{},[325,12186,12187],{},"CacheStorage",[8848,12189,12190,12191],{},"Production storage using ",[325,12192,12193],{},"CacheStore",[8834,12195,12196,12201],{},[8848,12197,12198],{},[325,12199,12200],{},"MemoryStorage",[8848,12202,12203],{},"In-memory storage for testing",[347,12205,12206],{"id":5272},"Attributes",[293,12208,12209],{},[308,12210,12211],{},"RateLimit Attribute:",[428,12213,12215],{"className":5139,"code":12214,"language":1135,"meta":320,"style":320},"#[RateLimit(\n    attempts: 60,           // Max requests\n    perMinutes: 1,          // Time window (or perHours, perDays)\n    tier: 'free',           // Optional tier restriction\n    key: 'custom:{ip}',     // Custom key pattern\n    algorithm: 'sliding',   // fixed, sliding, or bucket\n    by: 'ip'                // Identifier: ip, user, or custom\n)]\n",[325,12216,12217,12227,12242,12257,12275,12294,12313,12330],{"__ignoreMap":320},[436,12218,12219,12222,12225],{"class":438,"line":439},[436,12220,12221],{"class":1151},"#[",[436,12223,12224],{"class":6519},"RateLimit",[436,12226,6925],{"class":5163},[436,12228,12229,12232,12234,12237,12239],{"class":438,"line":1132},[436,12230,12231],{"class":6659},"    attempts",[436,12233,5243],{"class":5163},[436,12235,12236],{"class":7256}," 60",[436,12238,5177],{"class":5163},[436,12240,12241],{"class":1168},"           // Max requests\n",[436,12243,12244,12247,12249,12252,12254],{"class":438,"line":1158},[436,12245,12246],{"class":6659},"    perMinutes",[436,12248,5243],{"class":5163},[436,12250,12251],{"class":7256}," 1",[436,12253,5177],{"class":5163},[436,12255,12256],{"class":1168},"          // Time window (or perHours, perDays)\n",[436,12258,12259,12262,12264,12266,12268,12270,12272],{"class":438,"line":5196},[436,12260,12261],{"class":6659},"    tier",[436,12263,5243],{"class":5163},[436,12265,6064],{"class":5281},[436,12267,11989],{"class":446},[436,12269,5282],{"class":5281},[436,12271,5177],{"class":5163},[436,12273,12274],{"class":1168},"           // Optional tier restriction\n",[436,12276,12277,12280,12282,12284,12287,12289,12291],{"class":438,"line":5202},[436,12278,12279],{"class":6659},"    key",[436,12281,5243],{"class":5163},[436,12283,6064],{"class":5281},[436,12285,12286],{"class":446},"custom:{ip}",[436,12288,5282],{"class":5281},[436,12290,5177],{"class":5163},[436,12292,12293],{"class":1168},"     // Custom key pattern\n",[436,12295,12296,12299,12301,12303,12306,12308,12310],{"class":438,"line":5208},[436,12297,12298],{"class":6659},"    algorithm",[436,12300,5243],{"class":5163},[436,12302,6064],{"class":5281},[436,12304,12305],{"class":446},"sliding",[436,12307,5282],{"class":5281},[436,12309,5177],{"class":5163},[436,12311,12312],{"class":1168},"   // fixed, sliding, or bucket\n",[436,12314,12315,12318,12320,12322,12325,12327],{"class":438,"line":5215},[436,12316,12317],{"class":6659},"    by",[436,12319,5243],{"class":5163},[436,12321,6064],{"class":5281},[436,12323,12324],{"class":446},"ip",[436,12326,5282],{"class":5281},[436,12328,12329],{"class":1168},"                // Identifier: ip, user, or custom\n",[436,12331,12332,12334],{"class":438,"line":5221},[436,12333,4887],{"class":5163},[436,12335,11896],{"class":1151},[293,12337,12338],{},[308,12339,12340],{},"RateLimitCost Attribute:",[428,12342,12344],{"className":5139,"code":12343,"language":1135,"meta":320,"style":320},"#[RateLimitCost(\n    cost: 100,\n    reason: 'Full data export operation'\n)]\n",[325,12345,12346,12355,12366,12380],{"__ignoreMap":320},[436,12347,12348,12350,12353],{"class":438,"line":439},[436,12349,12221],{"class":1151},[436,12351,12352],{"class":6519},"RateLimitCost",[436,12354,6925],{"class":5163},[436,12356,12357,12360,12362,12364],{"class":438,"line":1132},[436,12358,12359],{"class":6659},"    cost",[436,12361,5243],{"class":5163},[436,12363,10154],{"class":7256},[436,12365,6907],{"class":5163},[436,12367,12368,12371,12373,12375,12378],{"class":438,"line":1158},[436,12369,12370],{"class":6659},"    reason",[436,12372,5243],{"class":5163},[436,12374,6064],{"class":5281},[436,12376,12377],{"class":446},"Full data export operation",[436,12379,11123],{"class":5281},[436,12381,12382,12384],{"class":438,"line":5196},[436,12383,4887],{"class":5163},[436,12385,11896],{"class":1151},[347,12387,12389],{"id":12388},"ietf-compliant-headers","IETF-Compliant Headers",[293,12391,12392],{},"The middleware adds standardized rate limit headers:",[428,12394,12397],{"className":12395,"code":12396,"language":2016},[5959],"X-RateLimit-Limit: 60\nX-RateLimit-Remaining: 45\nX-RateLimit-Reset: 1706011260\nRateLimit-Limit: 60\nRateLimit-Remaining: 45\nRateLimit-Reset: 1706011260\nRateLimit-Policy: 60;w=60\nRetry-After: 30  (when rate limited)\n",[325,12398,12396],{"__ignoreMap":320},[347,12400,9391],{"id":12401},"quick-usage-2",[428,12403,12405],{"className":5139,"code":12404,"language":1135,"meta":320,"style":320},"use Glueful\\Api\\RateLimiting\\Attributes\\{RateLimit, RateLimitCost};\n\nclass UserController\n{\n    // 60 requests per minute, 1000 per hour\n    #[RateLimit(attempts: 60, perMinutes: 1)]\n    #[RateLimit(attempts: 1000, perHours: 1)]\n    public function index(): Response { }\n\n    // Tiered limits - different limits per subscription tier\n    #[RateLimit(tier: 'free', attempts: 100, perDays: 1)]\n    #[RateLimit(tier: 'pro', attempts: 10000, perDays: 1)]\n    public function search(): Response { }\n\n    // Cost-based limiting - expensive operations\n    #[RateLimit(attempts: 1000, perDays: 1)]\n    #[RateLimitCost(cost: 100, reason: 'Full data export')]\n    public function export(): Response { }\n}\n\n// Route-level configuration\n$router->get('/api/users', [UserController::class, 'index'])\n    ->middleware(['enhanced_rate_limit']);\n",[325,12406,12407,12440,12444,12451,12455,12460,12489,12517,12536,12540,12545,12586,12625,12644,12648,12653,12679,12712,12731,12735,12739,12744,12785],{"__ignoreMap":320},[436,12408,12409,12411,12413,12415,12417,12419,12422,12424,12426,12428,12430,12432,12434,12437],{"class":438,"line":439},[436,12410,6516],{"class":5167},[436,12412,6520],{"class":6519},[436,12414,6524],{"class":6523},[436,12416,9407],{"class":6519},[436,12418,6524],{"class":6523},[436,12420,12421],{"class":6519},"RateLimiting",[436,12423,6524],{"class":6523},[436,12425,12206],{"class":6519},[436,12427,6524],{"class":6523},[436,12429,7230],{"class":5163},[436,12431,12224],{"class":6532},[436,12433,5177],{"class":5163},[436,12435,12436],{"class":6532}," RateLimitCost",[436,12438,12439],{"class":5163},"};\n",[436,12441,12442],{"class":438,"line":1132},[436,12443,5212],{"emptyLinePlaceholder":5211},[436,12445,12446,12448],{"class":438,"line":1158},[436,12447,6059],{"class":5155},[436,12449,12450],{"class":9486}," UserController\n",[436,12452,12453],{"class":438,"line":5196},[436,12454,5193],{"class":5163},[436,12456,12457],{"class":438,"line":5202},[436,12458,12459],{"class":1168},"    // 60 requests per minute, 1000 per hour\n",[436,12461,12462,12465,12467,12469,12472,12474,12476,12478,12481,12483,12485,12487],{"class":438,"line":5208},[436,12463,12464],{"class":1151},"    #[",[436,12466,12224],{"class":6519},[436,12468,5164],{"class":5163},[436,12470,12471],{"class":6659},"attempts",[436,12473,5243],{"class":5163},[436,12475,12236],{"class":7256},[436,12477,5177],{"class":5163},[436,12479,12480],{"class":6659}," perMinutes",[436,12482,5243],{"class":5163},[436,12484,12251],{"class":7256},[436,12486,4887],{"class":5163},[436,12488,11896],{"class":1151},[436,12490,12491,12493,12495,12497,12499,12501,12504,12506,12509,12511,12513,12515],{"class":438,"line":5215},[436,12492,12464],{"class":1151},[436,12494,12224],{"class":6519},[436,12496,5164],{"class":5163},[436,12498,12471],{"class":6659},[436,12500,5243],{"class":5163},[436,12502,12503],{"class":7256}," 1000",[436,12505,5177],{"class":5163},[436,12507,12508],{"class":6659}," perHours",[436,12510,5243],{"class":5163},[436,12512,12251],{"class":7256},[436,12514,4887],{"class":5163},[436,12516,11896],{"class":1151},[436,12518,12519,12521,12523,12525,12527,12529,12532,12534],{"class":438,"line":5221},[436,12520,11170],{"class":5152},[436,12522,5156],{"class":5155},[436,12524,5228],{"class":5159},[436,12526,7677],{"class":5163},[436,12528,5243],{"class":1144},[436,12530,12531],{"class":5233}," Response",[436,12533,7685],{"class":5163},[436,12535,7688],{"class":5163},[436,12537,12538],{"class":438,"line":5249},[436,12539,5212],{"emptyLinePlaceholder":5211},[436,12541,12542],{"class":438,"line":5254},[436,12543,12544],{"class":1168},"    // Tiered limits - different limits per subscription tier\n",[436,12546,12547,12549,12551,12553,12556,12558,12560,12562,12564,12566,12569,12571,12573,12575,12578,12580,12582,12584],{"class":438,"line":5298},[436,12548,12464],{"class":1151},[436,12550,12224],{"class":6519},[436,12552,5164],{"class":5163},[436,12554,12555],{"class":6659},"tier",[436,12557,5243],{"class":5163},[436,12559,6064],{"class":5281},[436,12561,11989],{"class":446},[436,12563,5282],{"class":5281},[436,12565,5177],{"class":5163},[436,12567,12568],{"class":6659}," attempts",[436,12570,5243],{"class":5163},[436,12572,10154],{"class":7256},[436,12574,5177],{"class":5163},[436,12576,12577],{"class":6659}," perDays",[436,12579,5243],{"class":5163},[436,12581,12251],{"class":7256},[436,12583,4887],{"class":5163},[436,12585,11896],{"class":1151},[436,12587,12588,12590,12592,12594,12596,12598,12600,12602,12604,12606,12608,12610,12613,12615,12617,12619,12621,12623],{"class":438,"line":5324},[436,12589,12464],{"class":1151},[436,12591,12224],{"class":6519},[436,12593,5164],{"class":5163},[436,12595,12555],{"class":6659},[436,12597,5243],{"class":5163},[436,12599,6064],{"class":5281},[436,12601,11992],{"class":446},[436,12603,5282],{"class":5281},[436,12605,5177],{"class":5163},[436,12607,12568],{"class":6659},[436,12609,5243],{"class":5163},[436,12611,12612],{"class":7256}," 10000",[436,12614,5177],{"class":5163},[436,12616,12577],{"class":6659},[436,12618,5243],{"class":5163},[436,12620,12251],{"class":7256},[436,12622,4887],{"class":5163},[436,12624,11896],{"class":1151},[436,12626,12627,12629,12631,12634,12636,12638,12640,12642],{"class":438,"line":5329},[436,12628,11170],{"class":5152},[436,12630,5156],{"class":5155},[436,12632,12633],{"class":5159}," search",[436,12635,7677],{"class":5163},[436,12637,5243],{"class":1144},[436,12639,12531],{"class":5233},[436,12641,7685],{"class":5163},[436,12643,7688],{"class":5163},[436,12645,12646],{"class":438,"line":6717},[436,12647,5212],{"emptyLinePlaceholder":5211},[436,12649,12650],{"class":438,"line":6742},[436,12651,12652],{"class":1168},"    // Cost-based limiting - expensive operations\n",[436,12654,12655,12657,12659,12661,12663,12665,12667,12669,12671,12673,12675,12677],{"class":438,"line":6767},[436,12656,12464],{"class":1151},[436,12658,12224],{"class":6519},[436,12660,5164],{"class":5163},[436,12662,12471],{"class":6659},[436,12664,5243],{"class":5163},[436,12666,12503],{"class":7256},[436,12668,5177],{"class":5163},[436,12670,12577],{"class":6659},[436,12672,5243],{"class":5163},[436,12674,12251],{"class":7256},[436,12676,4887],{"class":5163},[436,12678,11896],{"class":1151},[436,12680,12681,12683,12685,12687,12690,12692,12694,12696,12699,12701,12703,12706,12708,12710],{"class":438,"line":6772},[436,12682,12464],{"class":1151},[436,12684,12352],{"class":6519},[436,12686,5164],{"class":5163},[436,12688,12689],{"class":6659},"cost",[436,12691,5243],{"class":5163},[436,12693,10154],{"class":7256},[436,12695,5177],{"class":5163},[436,12697,12698],{"class":6659}," reason",[436,12700,5243],{"class":5163},[436,12702,6064],{"class":5281},[436,12704,12705],{"class":446},"Full data export",[436,12707,5282],{"class":5281},[436,12709,4887],{"class":5163},[436,12711,11896],{"class":1151},[436,12713,12714,12716,12718,12721,12723,12725,12727,12729],{"class":438,"line":6778},[436,12715,11170],{"class":5152},[436,12717,5156],{"class":5155},[436,12719,12720],{"class":5159}," export",[436,12722,7677],{"class":5163},[436,12724,5243],{"class":1144},[436,12726,12531],{"class":5233},[436,12728,7685],{"class":5163},[436,12730,7688],{"class":5163},[436,12732,12733],{"class":438,"line":6810},[436,12734,5205],{"class":5163},[436,12736,12737],{"class":438,"line":9754},[436,12738,5212],{"emptyLinePlaceholder":5211},[436,12740,12741],{"class":438,"line":9801},[436,12742,12743],{"class":1168},"// Route-level configuration\n",[436,12745,12746,12748,12750,12752,12754,12756,12758,12761,12763,12765,12767,12770,12772,12774,12776,12778,12780,12782],{"class":438,"line":9806},[436,12747,5761],{"class":5163},[436,12749,5983],{"class":1151},[436,12751,5269],{"class":1144},[436,12753,715],{"class":5159},[436,12755,5164],{"class":5163},[436,12757,5282],{"class":5281},[436,12759,12760],{"class":446},"/api/users",[436,12762,5282],{"class":5281},[436,12764,5177],{"class":5163},[436,12766,6050],{"class":5163},[436,12768,12769],{"class":5233},"UserController",[436,12771,6056],{"class":1144},[436,12773,6059],{"class":5167},[436,12775,5177],{"class":5163},[436,12777,6064],{"class":5281},[436,12779,4985],{"class":446},[436,12781,5282],{"class":5281},[436,12783,12784],{"class":5163},"])\n",[436,12786,12787,12790,12793,12795,12797,12800,12802],{"class":438,"line":9812},[436,12788,12789],{"class":1144},"    ->",[436,12791,12792],{"class":5159},"middleware",[436,12794,5990],{"class":5163},[436,12796,5282],{"class":5281},[436,12798,12799],{"class":446},"enhanced_rate_limit",[436,12801,5282],{"class":5281},[436,12803,6072],{"class":5163},[347,12805,121],{"id":12806},"configuration-3",[428,12808,12810],{"className":5139,"code":12809,"language":1135,"meta":320,"style":320},"// config/api.php\n'rate_limiting' => [\n    'enabled' => true,\n    'algorithm' => 'sliding',\n    'default_tier' => 'anonymous',\n    'tiers' => [\n        'anonymous' => [\n            'requests_per_minute' => 30,\n            'requests_per_hour' => 500,\n            'requests_per_day' => 5000,\n        ],\n        'free' => [\n            'requests_per_minute' => 60,\n            'requests_per_hour' => 1000,\n            'requests_per_day' => 10000,\n        ],\n        'pro' => [\n            'requests_per_minute' => 300,\n            'requests_per_hour' => 10000,\n            'requests_per_day' => 100000,\n        ],\n        'enterprise' => [\n            'requests_per_minute' => null,  // unlimited\n            'requests_per_hour' => null,\n            'requests_per_day' => null,\n        ],\n    ],\n    'headers' => [\n        'enabled' => true,\n        'include_legacy' => true,  // X-RateLimit-* headers\n        'include_ietf' => true,    // RateLimit-* headers\n    ],\n    'bypass_ips' => '127.0.0.1,::1',\n],\n",[325,12811,12812,12816,12829,12843,12862,12881,12894,12906,12921,12937,12953,12957,12969,12983,12997,13011,13015,13027,13041,13055,13070,13074,13086,13103,13117,13131,13135,13139,13151,13165,13183,13201,13205,13225],{"__ignoreMap":320},[436,12813,12814],{"class":438,"line":439},[436,12815,10111],{"class":1168},[436,12817,12818,12820,12823,12825,12827],{"class":438,"line":1132},[436,12819,5282],{"class":5281},[436,12821,12822],{"class":446},"rate_limiting",[436,12824,5282],{"class":5281},[436,12826,6000],{"class":1144},[436,12828,6857],{"class":5163},[436,12830,12831,12833,12835,12837,12839,12841],{"class":438,"line":1158},[436,12832,6862],{"class":5281},[436,12834,883],{"class":446},[436,12836,5282],{"class":5281},[436,12838,6000],{"class":1144},[436,12840,10187],{"class":10170},[436,12842,6907],{"class":5163},[436,12844,12845,12847,12850,12852,12854,12856,12858,12860],{"class":438,"line":5196},[436,12846,6862],{"class":5281},[436,12848,12849],{"class":446},"algorithm",[436,12851,5282],{"class":5281},[436,12853,6000],{"class":1144},[436,12855,6064],{"class":5281},[436,12857,12305],{"class":446},[436,12859,5282],{"class":5281},[436,12861,6907],{"class":5163},[436,12863,12864,12866,12869,12871,12873,12875,12877,12879],{"class":438,"line":5202},[436,12865,6862],{"class":5281},[436,12867,12868],{"class":446},"default_tier",[436,12870,5282],{"class":5281},[436,12872,6000],{"class":1144},[436,12874,6064],{"class":5281},[436,12876,11986],{"class":446},[436,12878,5282],{"class":5281},[436,12880,6907],{"class":5163},[436,12882,12883,12885,12888,12890,12892],{"class":438,"line":5208},[436,12884,6862],{"class":5281},[436,12886,12887],{"class":446},"tiers",[436,12889,5282],{"class":5281},[436,12891,6000],{"class":1144},[436,12893,6857],{"class":5163},[436,12895,12896,12898,12900,12902,12904],{"class":438,"line":5215},[436,12897,9519],{"class":5281},[436,12899,11986],{"class":446},[436,12901,5282],{"class":5281},[436,12903,6000],{"class":1144},[436,12905,6857],{"class":5163},[436,12907,12908,12910,12913,12915,12917,12919],{"class":438,"line":5221},[436,12909,10331],{"class":5281},[436,12911,12912],{"class":446},"requests_per_minute",[436,12914,5282],{"class":5281},[436,12916,6000],{"class":1144},[436,12918,11737],{"class":7256},[436,12920,6907],{"class":5163},[436,12922,12923,12925,12928,12930,12932,12935],{"class":438,"line":5249},[436,12924,10331],{"class":5281},[436,12926,12927],{"class":446},"requests_per_hour",[436,12929,5282],{"class":5281},[436,12931,6000],{"class":1144},[436,12933,12934],{"class":7256}," 500",[436,12936,6907],{"class":5163},[436,12938,12939,12941,12944,12946,12948,12951],{"class":438,"line":5254},[436,12940,10331],{"class":5281},[436,12942,12943],{"class":446},"requests_per_day",[436,12945,5282],{"class":5281},[436,12947,6000],{"class":1144},[436,12949,12950],{"class":7256}," 5000",[436,12952,6907],{"class":5163},[436,12954,12955],{"class":438,"line":5298},[436,12956,10368],{"class":5163},[436,12958,12959,12961,12963,12965,12967],{"class":438,"line":5324},[436,12960,9519],{"class":5281},[436,12962,11989],{"class":446},[436,12964,5282],{"class":5281},[436,12966,6000],{"class":1144},[436,12968,6857],{"class":5163},[436,12970,12971,12973,12975,12977,12979,12981],{"class":438,"line":5329},[436,12972,10331],{"class":5281},[436,12974,12912],{"class":446},[436,12976,5282],{"class":5281},[436,12978,6000],{"class":1144},[436,12980,12236],{"class":7256},[436,12982,6907],{"class":5163},[436,12984,12985,12987,12989,12991,12993,12995],{"class":438,"line":6717},[436,12986,10331],{"class":5281},[436,12988,12927],{"class":446},[436,12990,5282],{"class":5281},[436,12992,6000],{"class":1144},[436,12994,12503],{"class":7256},[436,12996,6907],{"class":5163},[436,12998,12999,13001,13003,13005,13007,13009],{"class":438,"line":6742},[436,13000,10331],{"class":5281},[436,13002,12943],{"class":446},[436,13004,5282],{"class":5281},[436,13006,6000],{"class":1144},[436,13008,12612],{"class":7256},[436,13010,6907],{"class":5163},[436,13012,13013],{"class":438,"line":6767},[436,13014,10368],{"class":5163},[436,13016,13017,13019,13021,13023,13025],{"class":438,"line":6772},[436,13018,9519],{"class":5281},[436,13020,11992],{"class":446},[436,13022,5282],{"class":5281},[436,13024,6000],{"class":1144},[436,13026,6857],{"class":5163},[436,13028,13029,13031,13033,13035,13037,13039],{"class":438,"line":6778},[436,13030,10331],{"class":5281},[436,13032,12912],{"class":446},[436,13034,5282],{"class":5281},[436,13036,6000],{"class":1144},[436,13038,11808],{"class":7256},[436,13040,6907],{"class":5163},[436,13042,13043,13045,13047,13049,13051,13053],{"class":438,"line":6810},[436,13044,10331],{"class":5281},[436,13046,12927],{"class":446},[436,13048,5282],{"class":5281},[436,13050,6000],{"class":1144},[436,13052,12612],{"class":7256},[436,13054,6907],{"class":5163},[436,13056,13057,13059,13061,13063,13065,13068],{"class":438,"line":9754},[436,13058,10331],{"class":5281},[436,13060,12943],{"class":446},[436,13062,5282],{"class":5281},[436,13064,6000],{"class":1144},[436,13066,13067],{"class":7256}," 100000",[436,13069,6907],{"class":5163},[436,13071,13072],{"class":438,"line":9801},[436,13073,10368],{"class":5163},[436,13075,13076,13078,13080,13082,13084],{"class":438,"line":9806},[436,13077,9519],{"class":5281},[436,13079,11995],{"class":446},[436,13081,5282],{"class":5281},[436,13083,6000],{"class":1144},[436,13085,6857],{"class":5163},[436,13087,13088,13090,13092,13094,13096,13098,13100],{"class":438,"line":9812},[436,13089,10331],{"class":5281},[436,13091,12912],{"class":446},[436,13093,5282],{"class":5281},[436,13095,6000],{"class":1144},[436,13097,11682],{"class":10170},[436,13099,5177],{"class":5163},[436,13101,13102],{"class":1168},"  // unlimited\n",[436,13104,13105,13107,13109,13111,13113,13115],{"class":438,"line":9825},[436,13106,10331],{"class":5281},[436,13108,12927],{"class":446},[436,13110,5282],{"class":5281},[436,13112,6000],{"class":1144},[436,13114,11682],{"class":10170},[436,13116,6907],{"class":5163},[436,13118,13119,13121,13123,13125,13127,13129],{"class":438,"line":9830},[436,13120,10331],{"class":5281},[436,13122,12943],{"class":446},[436,13124,5282],{"class":5281},[436,13126,6000],{"class":1144},[436,13128,11682],{"class":10170},[436,13130,6907],{"class":5163},[436,13132,13133],{"class":438,"line":9841},[436,13134,10368],{"class":5163},[436,13136,13137],{"class":438,"line":9846},[436,13138,10455],{"class":5163},[436,13140,13141,13143,13145,13147,13149],{"class":438,"line":9887},[436,13142,6862],{"class":5281},[436,13144,11307],{"class":446},[436,13146,5282],{"class":5281},[436,13148,6000],{"class":1144},[436,13150,6857],{"class":5163},[436,13152,13153,13155,13157,13159,13161,13163],{"class":438,"line":9892},[436,13154,9519],{"class":5281},[436,13156,883],{"class":446},[436,13158,5282],{"class":5281},[436,13160,6000],{"class":1144},[436,13162,10187],{"class":10170},[436,13164,6907],{"class":5163},[436,13166,13167,13169,13172,13174,13176,13178,13180],{"class":438,"line":9897},[436,13168,9519],{"class":5281},[436,13170,13171],{"class":446},"include_legacy",[436,13173,5282],{"class":5281},[436,13175,6000],{"class":1144},[436,13177,10187],{"class":10170},[436,13179,5177],{"class":5163},[436,13181,13182],{"class":1168},"  // X-RateLimit-* headers\n",[436,13184,13185,13187,13190,13192,13194,13196,13198],{"class":438,"line":9903},[436,13186,9519],{"class":5281},[436,13188,13189],{"class":446},"include_ietf",[436,13191,5282],{"class":5281},[436,13193,6000],{"class":1144},[436,13195,10187],{"class":10170},[436,13197,5177],{"class":5163},[436,13199,13200],{"class":1168},"    // RateLimit-* headers\n",[436,13202,13203],{"class":438,"line":9933},[436,13204,10455],{"class":5163},[436,13206,13207,13209,13212,13214,13216,13218,13221,13223],{"class":438,"line":9963},[436,13208,6862],{"class":5281},[436,13210,13211],{"class":446},"bypass_ips",[436,13213,5282],{"class":5281},[436,13215,6000],{"class":1144},[436,13217,6064],{"class":5281},[436,13219,13220],{"class":446},"127.0.0.1,::1",[436,13222,5282],{"class":5281},[436,13224,6907],{"class":5163},[436,13226,13227],{"class":438,"line":9979},[436,13228,9553],{"class":5163},[347,13230,413],{"id":13231},"migration-notes-24",[312,13233,13234],{"color":3075,"icon":11902,"variant":316},[318,13235,13236],{"v-slot:description":320},[293,13237,13238,13239,299],{},"No breaking changes. The new enhanced rate limiting system is opt-in and coexists with the existing ",[325,13240,8487],{},[415,13242,13243,13250,13255],{},[418,13244,13245,13246,13249],{},"Existing ",[325,13247,13248],{},"rate_limit:100,60,ip"," middleware syntax continues to work",[418,13251,705,13252,13254],{},[325,13253,12799],{}," middleware is opt-in for attribute-based limiting",[418,13256,13257],{},"Both systems can coexist in the same application",[452,13259],{},[301,13261,13263],{"id":13262},"v1160-meissa-minor","v1.16.0 - Meissa (Minor)",[293,13265,13266],{},[308,13267,8692],{},[312,13269,13271],{"color":314,"icon":13270,"variant":316},"i-tabler-versions",[318,13272,13273],{"v-slot:description":320},[293,13274,13275],{},"Feature release introducing comprehensive API Versioning with multiple resolution strategies, deprecation system, and sunset headers.",[347,13277,350],{"id":13278},"key-highlights-35",[352,13280,13281,13286],{},[293,13282,13283],{},[308,13284,13285],{},"Multiple Version Strategies",[415,13287,13288,13297,13303,13309],{},[418,13289,13290,13291,332,13294],{},"URL Prefix: ",[325,13292,13293],{},"/v1/users",[325,13295,13296],{},"/v2/users",[418,13298,13299,13300],{},"Header: ",[325,13301,13302],{},"X-API-Version: 2.0",[418,13304,13305,13306],{},"Query Parameter: ",[325,13307,13308],{},"?api_version=2",[418,13310,13311,13312],{},"Accept Header: ",[325,13313,13314],{},"Accept: application/vnd.api+json;version=2",[352,13316,13317,13322],{},[293,13318,13319],{},[308,13320,13321],{},"Version Attributes",[415,13323,13324,13330,13336],{},[418,13325,13326,13329],{},[325,13327,13328],{},"#[Version]"," for declaring version requirements on routes",[418,13331,13332,13335],{},[325,13333,13334],{},"#[Deprecated]"," for marking deprecated endpoints with messages",[418,13337,13338,13341],{},[325,13339,13340],{},"#[Sunset]"," for specifying retirement dates",[352,13343,13344,13349],{},[293,13345,13346],{},[308,13347,13348],{},"Version Negotiation",[415,13350,13351,13354,13357],{},[418,13352,13353],{},"Automatic version detection from request",[418,13355,13356],{},"Fallback to default version when not specified",[418,13358,13359],{},"Version comparison and constraint matching",[347,13361,13363],{"id":13362},"api-versioning-components","API Versioning Components",[293,13365,13366],{},[308,13367,8987],{},[5285,13369,13370,13378],{},[8831,13371,13372],{},[8834,13373,13374,13376],{},[8837,13375,8996],{},[8837,13377,8999],{},[8843,13379,13380,13390,13400],{},[8834,13381,13382,13387],{},[8848,13383,13384],{},[325,13385,13386],{},"VersionManager",[8848,13388,13389],{},"Central manager for version resolution",[8834,13391,13392,13397],{},[8848,13393,13394],{},[325,13395,13396],{},"ApiVersion",[8848,13398,13399],{},"Value object for version representation",[8834,13401,13402,13407],{},[8848,13403,13404],{},[325,13405,13406],{},"VersionNegotiationMiddleware",[8848,13408,13409],{},"Automatic version detection",[293,13411,13412],{},[308,13413,13414],{},"Resolvers:",[5285,13416,13417,13426],{},[8831,13418,13419],{},[8834,13420,13421,13423],{},[8837,13422,8996],{},[8837,13424,13425],{},"Strategy",[8843,13427,13428,13441,13455,13468],{},[8834,13429,13430,13435],{},[8848,13431,13432],{},[325,13433,13434],{},"UrlPrefixResolver",[8848,13436,13437,13438,4887],{},"Extract version from URL path (",[325,13439,13440],{},"/v1/",[8834,13442,13443,13448],{},[8848,13444,13445],{},[325,13446,13447],{},"HeaderResolver",[8848,13449,13450,13451,13454],{},"Read ",[325,13452,13453],{},"X-API-Version"," header",[8834,13456,13457,13462],{},[8848,13458,13459],{},[325,13460,13461],{},"QueryParameterResolver",[8848,13463,13450,13464,13467],{},[325,13465,13466],{},"api_version"," query param",[8834,13469,13470,13475],{},[8848,13471,13472],{},[325,13473,13474],{},"AcceptHeaderResolver",[8848,13476,13477],{},"Parse Accept header media type",[293,13479,13480],{},[308,13481,13482],{},"Attributes:",[5285,13484,13485,13494],{},[8831,13486,13487],{},[8834,13488,13489,13492],{},[8837,13490,13491],{},"Attribute",[8837,13493,8999],{},[8843,13495,13496,13505,13514],{},[8834,13497,13498,13502],{},[8848,13499,13500],{},[325,13501,13328],{},[8848,13503,13504],{},"Declare version requirements",[8834,13506,13507,13511],{},[8848,13508,13509],{},[325,13510,13334],{},[8848,13512,13513],{},"Mark deprecated endpoints",[8834,13515,13516,13520],{},[8848,13517,13518],{},[325,13519,13340],{},[8848,13521,13522],{},"Specify sunset/retirement date",[347,13524,9391],{"id":13525},"quick-usage-3",[428,13527,13529],{"className":5139,"code":13528,"language":1135,"meta":320,"style":320},"use Glueful\\Api\\Versioning\\Attributes\\{Version, Deprecated, Sunset};\n\nclass UserController\n{\n    #[Version('1.0')]\n    public function indexV1(): Response\n    {\n        return $this->json(['users' => $this->legacyFormat()]);\n    }\n\n    #[Version('2.0')]\n    public function indexV2(): Response\n    {\n        return $this->json(['data' => $this->modernFormat()]);\n    }\n\n    #[Version('1.0')]\n    #[Deprecated(message: 'Use v2 endpoint instead', since: '2026-01-01')]\n    #[Sunset(date: '2026-06-01')]\n    public function legacyEndpoint(): Response\n    {\n        // Deprecation warning headers automatically added\n        return $this->json(['legacy' => true]);\n    }\n}\n",[325,13530,13531,13569,13573,13579,13583,13602,13617,13621,13651,13655,13659,13678,13693,13697,13726,13730,13734,13752,13791,13816,13831,13835,13840,13865,13869],{"__ignoreMap":320},[436,13532,13533,13535,13537,13539,13541,13543,13546,13548,13550,13552,13554,13557,13559,13562,13564,13567],{"class":438,"line":439},[436,13534,6516],{"class":5167},[436,13536,6520],{"class":6519},[436,13538,6524],{"class":6523},[436,13540,9407],{"class":6519},[436,13542,6524],{"class":6523},[436,13544,13545],{"class":6519},"Versioning",[436,13547,6524],{"class":6523},[436,13549,12206],{"class":6519},[436,13551,6524],{"class":6523},[436,13553,7230],{"class":5163},[436,13555,13556],{"class":6532},"Version",[436,13558,5177],{"class":5163},[436,13560,13561],{"class":6532}," Deprecated",[436,13563,5177],{"class":5163},[436,13565,13566],{"class":6532}," Sunset",[436,13568,12439],{"class":5163},[436,13570,13571],{"class":438,"line":1132},[436,13572,5212],{"emptyLinePlaceholder":5211},[436,13574,13575,13577],{"class":438,"line":1158},[436,13576,6059],{"class":5155},[436,13578,12450],{"class":9486},[436,13580,13581],{"class":438,"line":5196},[436,13582,5193],{"class":5163},[436,13584,13585,13587,13589,13591,13593,13596,13598,13600],{"class":438,"line":5202},[436,13586,12464],{"class":1151},[436,13588,13556],{"class":6519},[436,13590,5164],{"class":5163},[436,13592,5282],{"class":5281},[436,13594,13595],{"class":446},"1.0",[436,13597,5282],{"class":5281},[436,13599,4887],{"class":5163},[436,13601,11896],{"class":1151},[436,13603,13604,13606,13608,13611,13613,13615],{"class":438,"line":5208},[436,13605,11170],{"class":5152},[436,13607,5156],{"class":5155},[436,13609,13610],{"class":5159}," indexV1",[436,13612,7677],{"class":5163},[436,13614,5243],{"class":1144},[436,13616,5246],{"class":5233},[436,13618,13619],{"class":438,"line":5215},[436,13620,11187],{"class":5163},[436,13622,13623,13625,13627,13629,13631,13633,13635,13637,13639,13641,13643,13645,13648],{"class":438,"line":5221},[436,13624,11192],{"class":5788},[436,13626,5770],{"class":5769},[436,13628,5269],{"class":1144},[436,13630,2013],{"class":5159},[436,13632,5990],{"class":5163},[436,13634,5282],{"class":5281},[436,13636,9787],{"class":446},[436,13638,5282],{"class":5281},[436,13640,6000],{"class":1144},[436,13642,5770],{"class":5769},[436,13644,5269],{"class":1144},[436,13646,13647],{"class":5159},"legacyFormat",[436,13649,13650],{"class":5163},"()]);\n",[436,13652,13653],{"class":438,"line":5249},[436,13654,11205],{"class":5163},[436,13656,13657],{"class":438,"line":5254},[436,13658,5212],{"emptyLinePlaceholder":5211},[436,13660,13661,13663,13665,13667,13669,13672,13674,13676],{"class":438,"line":5298},[436,13662,12464],{"class":1151},[436,13664,13556],{"class":6519},[436,13666,5164],{"class":5163},[436,13668,5282],{"class":5281},[436,13670,13671],{"class":446},"2.0",[436,13673,5282],{"class":5281},[436,13675,4887],{"class":5163},[436,13677,11896],{"class":1151},[436,13679,13680,13682,13684,13687,13689,13691],{"class":438,"line":5324},[436,13681,11170],{"class":5152},[436,13683,5156],{"class":5155},[436,13685,13686],{"class":5159}," indexV2",[436,13688,7677],{"class":5163},[436,13690,5243],{"class":1144},[436,13692,5246],{"class":5233},[436,13694,13695],{"class":438,"line":5329},[436,13696,11187],{"class":5163},[436,13698,13699,13701,13703,13705,13707,13709,13711,13713,13715,13717,13719,13721,13724],{"class":438,"line":6717},[436,13700,11192],{"class":5788},[436,13702,5770],{"class":5769},[436,13704,5269],{"class":1144},[436,13706,2013],{"class":5159},[436,13708,5990],{"class":5163},[436,13710,5282],{"class":5281},[436,13712,11415],{"class":446},[436,13714,5282],{"class":5281},[436,13716,6000],{"class":1144},[436,13718,5770],{"class":5769},[436,13720,5269],{"class":1144},[436,13722,13723],{"class":5159},"modernFormat",[436,13725,13650],{"class":5163},[436,13727,13728],{"class":438,"line":6742},[436,13729,11205],{"class":5163},[436,13731,13732],{"class":438,"line":6767},[436,13733,5212],{"emptyLinePlaceholder":5211},[436,13735,13736,13738,13740,13742,13744,13746,13748,13750],{"class":438,"line":6772},[436,13737,12464],{"class":1151},[436,13739,13556],{"class":6519},[436,13741,5164],{"class":5163},[436,13743,5282],{"class":5281},[436,13745,13595],{"class":446},[436,13747,5282],{"class":5281},[436,13749,4887],{"class":5163},[436,13751,11896],{"class":1151},[436,13753,13754,13756,13759,13761,13764,13766,13768,13771,13773,13775,13778,13780,13782,13785,13787,13789],{"class":438,"line":6778},[436,13755,12464],{"class":1151},[436,13757,13758],{"class":6519},"Deprecated",[436,13760,5164],{"class":5163},[436,13762,13763],{"class":6659},"message",[436,13765,5243],{"class":5163},[436,13767,6064],{"class":5281},[436,13769,13770],{"class":446},"Use v2 endpoint instead",[436,13772,5282],{"class":5281},[436,13774,5177],{"class":5163},[436,13776,13777],{"class":6659}," since",[436,13779,5243],{"class":5163},[436,13781,6064],{"class":5281},[436,13783,13784],{"class":446},"2026-01-01",[436,13786,5282],{"class":5281},[436,13788,4887],{"class":5163},[436,13790,11896],{"class":1151},[436,13792,13793,13795,13798,13800,13803,13805,13807,13810,13812,13814],{"class":438,"line":6810},[436,13794,12464],{"class":1151},[436,13796,13797],{"class":6519},"Sunset",[436,13799,5164],{"class":5163},[436,13801,13802],{"class":6659},"date",[436,13804,5243],{"class":5163},[436,13806,6064],{"class":5281},[436,13808,13809],{"class":446},"2026-06-01",[436,13811,5282],{"class":5281},[436,13813,4887],{"class":5163},[436,13815,11896],{"class":1151},[436,13817,13818,13820,13822,13825,13827,13829],{"class":438,"line":9754},[436,13819,11170],{"class":5152},[436,13821,5156],{"class":5155},[436,13823,13824],{"class":5159}," legacyEndpoint",[436,13826,7677],{"class":5163},[436,13828,5243],{"class":1144},[436,13830,5246],{"class":5233},[436,13832,13833],{"class":438,"line":9801},[436,13834,11187],{"class":5163},[436,13836,13837],{"class":438,"line":9806},[436,13838,13839],{"class":1168},"        // Deprecation warning headers automatically added\n",[436,13841,13842,13844,13846,13848,13850,13852,13854,13857,13859,13861,13863],{"class":438,"line":9812},[436,13843,11192],{"class":5788},[436,13845,5770],{"class":5769},[436,13847,5269],{"class":1144},[436,13849,2013],{"class":5159},[436,13851,5990],{"class":5163},[436,13853,5282],{"class":5281},[436,13855,13856],{"class":446},"legacy",[436,13858,5282],{"class":5281},[436,13860,6000],{"class":1144},[436,13862,10187],{"class":10170},[436,13864,6072],{"class":5163},[436,13866,13867],{"class":438,"line":9825},[436,13868,11205],{"class":5163},[436,13870,13871],{"class":438,"line":9830},[436,13872,5205],{"class":5163},[347,13874,13876],{"id":13875},"response-headers","Response Headers",[293,13878,13879],{},"Deprecation and sunset information is communicated via headers:",[428,13881,13884],{"className":13882,"code":13883,"language":2016},[5959],"Deprecation: true\nSunset: Sat, 01 Jun 2026 00:00:00 GMT\nX-API-Deprecated-Message: Use v2 endpoint instead\nX-API-Version: 1.0\n",[325,13885,13883],{"__ignoreMap":320},[347,13887,121],{"id":13888},"configuration-4",[428,13890,13892],{"className":5139,"code":13891,"language":1135,"meta":320,"style":320},"// config/api.php\n'versioning' => [\n    'enabled' => true,\n    'default' => 'v1',\n    'strategy' => 'url',  // url, header, query, accept\n    'header' => 'X-API-Version',\n    'query_param' => 'api_version',\n    'deprecation' => [\n        'sunset_header' => true,\n        'warning_header' => true,\n    ],\n],\n",[325,13893,13894,13898,13911,13925,13944,13966,13985,14004,14017,14032,14047,14051],{"__ignoreMap":320},[436,13895,13896],{"class":438,"line":439},[436,13897,10111],{"class":1168},[436,13899,13900,13902,13905,13907,13909],{"class":438,"line":1132},[436,13901,5282],{"class":5281},[436,13903,13904],{"class":446},"versioning",[436,13906,5282],{"class":5281},[436,13908,6000],{"class":1144},[436,13910,6857],{"class":5163},[436,13912,13913,13915,13917,13919,13921,13923],{"class":438,"line":1158},[436,13914,6862],{"class":5281},[436,13916,883],{"class":446},[436,13918,5282],{"class":5281},[436,13920,6000],{"class":1144},[436,13922,10187],{"class":10170},[436,13924,6907],{"class":5163},[436,13926,13927,13929,13931,13933,13935,13937,13940,13942],{"class":438,"line":5196},[436,13928,6862],{"class":5281},[436,13930,4515],{"class":446},[436,13932,5282],{"class":5281},[436,13934,6000],{"class":1144},[436,13936,6064],{"class":5281},[436,13938,13939],{"class":446},"v1",[436,13941,5282],{"class":5281},[436,13943,6907],{"class":5163},[436,13945,13946,13948,13951,13953,13955,13957,13959,13961,13963],{"class":438,"line":5202},[436,13947,6862],{"class":5281},[436,13949,13950],{"class":446},"strategy",[436,13952,5282],{"class":5281},[436,13954,6000],{"class":1144},[436,13956,6064],{"class":5281},[436,13958,7246],{"class":446},[436,13960,5282],{"class":5281},[436,13962,5177],{"class":5163},[436,13964,13965],{"class":1168},"  // url, header, query, accept\n",[436,13967,13968,13970,13973,13975,13977,13979,13981,13983],{"class":438,"line":5208},[436,13969,6862],{"class":5281},[436,13971,13972],{"class":446},"header",[436,13974,5282],{"class":5281},[436,13976,6000],{"class":1144},[436,13978,6064],{"class":5281},[436,13980,13453],{"class":446},[436,13982,5282],{"class":5281},[436,13984,6907],{"class":5163},[436,13986,13987,13989,13992,13994,13996,13998,14000,14002],{"class":438,"line":5215},[436,13988,6862],{"class":5281},[436,13990,13991],{"class":446},"query_param",[436,13993,5282],{"class":5281},[436,13995,6000],{"class":1144},[436,13997,6064],{"class":5281},[436,13999,13466],{"class":446},[436,14001,5282],{"class":5281},[436,14003,6907],{"class":5163},[436,14005,14006,14008,14011,14013,14015],{"class":438,"line":5221},[436,14007,6862],{"class":5281},[436,14009,14010],{"class":446},"deprecation",[436,14012,5282],{"class":5281},[436,14014,6000],{"class":1144},[436,14016,6857],{"class":5163},[436,14018,14019,14021,14024,14026,14028,14030],{"class":438,"line":5249},[436,14020,9519],{"class":5281},[436,14022,14023],{"class":446},"sunset_header",[436,14025,5282],{"class":5281},[436,14027,6000],{"class":1144},[436,14029,10187],{"class":10170},[436,14031,6907],{"class":5163},[436,14033,14034,14036,14039,14041,14043,14045],{"class":438,"line":5254},[436,14035,9519],{"class":5281},[436,14037,14038],{"class":446},"warning_header",[436,14040,5282],{"class":5281},[436,14042,6000],{"class":1144},[436,14044,10187],{"class":10170},[436,14046,6907],{"class":5163},[436,14048,14049],{"class":438,"line":5298},[436,14050,10455],{"class":5163},[436,14052,14053],{"class":438,"line":5324},[436,14054,9553],{"class":5163},[347,14056,413],{"id":14057},"migration-notes-25",[312,14059,14060],{"color":3075,"icon":11902,"variant":316},[318,14061,14062],{"v-slot:description":320},[293,14063,14064],{},"No breaking changes. API versioning is opt-in and additive.",[415,14066,14067,14070,14076],{},[418,14068,14069],{},"Versioning is entirely opt-in - existing routes continue to work unchanged",[418,14071,14072,14073,14075],{},"Apply ",[325,14074,13328],{}," attributes only where version-specific behavior is needed",[418,14077,14078,14079,14082],{},"Use middleware ",[325,14080,14081],{},"version_negotiation"," to enable automatic version detection",[452,14084],{},[301,14086,14088],{"id":14087},"v1150-rigel-minor","v1.15.0 - Rigel (Minor)",[293,14090,14091],{},[308,14092,8692],{},[312,14094,14096],{"color":314,"icon":14095,"variant":316},"i-tabler-server",[318,14097,14098],{"v-slot:description":320},[293,14099,14100],{},"Feature release introducing Real-Time Development Server with file watching, integrated services, and enhanced logging.",[347,14102,350],{"id":14103},"key-highlights-36",[352,14105,14106,14111],{},[293,14107,14108],{},[308,14109,14110],{},"File Watching",[415,14112,14113,14116,14122],{},[418,14114,14115],{},"Automatic file change detection with configurable polling",[418,14117,14118,14119,5405],{},"Auto-restart on code changes with ",[325,14120,14121],{},"--watch",[418,14123,14124,14125],{},"Configurable poll interval via ",[325,14126,14127],{},"--poll-interval",[352,14129,14130,14135],{},[293,14131,14132],{},[308,14133,14134],{},"Integrated Services",[415,14136,14137,14142,14145],{},[418,14138,14139,14141],{},[325,14140,4637],{}," option for integrated queue worker",[418,14143,14144],{},"Port auto-selection when preferred port is in use",[418,14146,14147],{},"Graceful shutdown handling",[352,14149,14150,14155],{},[293,14151,14152],{},[308,14153,14154],{},"Enhanced Logging",[415,14156,14157,14160,14163],{},[418,14158,14159],{},"Colorized HTTP request logging",[418,14161,14162],{},"Method and status code highlighting",[418,14164,14165],{},"Request timing information",[347,14167,14169],{"id":14168},"development-server-components","Development Server Components",[293,14171,14172],{},[308,14173,8987],{},[5285,14175,14176,14184],{},[8831,14177,14178],{},[8834,14179,14180,14182],{},[8837,14181,8996],{},[8837,14183,8999],{},[8843,14185,14186,14196,14206],{},[8834,14187,14188,14193],{},[8848,14189,14190],{},[325,14191,14192],{},"FileWatcher",[8848,14194,14195],{},"File change detection with polling",[8834,14197,14198,14203],{},[8848,14199,14200],{},[325,14201,14202],{},"RequestLogger",[8848,14204,14205],{},"Colorized request logging",[8834,14207,14208,14213],{},[8848,14209,14210],{},[325,14211,14212],{},"LogEntry",[8848,14214,14215],{},"Structured request log entries",[347,14217,9391],{"id":14218},"quick-usage-4",[428,14220,14222],{"className":430,"code":14221,"language":432,"meta":320,"style":320},"# Basic development server\nphp glueful serve\n\n# With file watching (auto-restart on changes)\nphp glueful serve --watch\n\n# With integrated queue worker\nphp glueful serve --queue\n\n# Custom port and poll interval\nphp glueful serve --port=8080 --watch --poll-interval=2000\n\n# Full development setup\nphp glueful serve --watch --queue --port=8000\n",[325,14223,14224,14229,14238,14242,14247,14259,14263,14268,14279,14283,14288,14305,14309,14314],{"__ignoreMap":320},[436,14225,14226],{"class":438,"line":439},[436,14227,14228],{"class":1168},"# Basic development server\n",[436,14230,14231,14233,14235],{"class":438,"line":1132},[436,14232,1135],{"class":442},[436,14234,1138],{"class":446},[436,14236,14237],{"class":446}," serve\n",[436,14239,14240],{"class":438,"line":1158},[436,14241,5212],{"emptyLinePlaceholder":5211},[436,14243,14244],{"class":438,"line":5196},[436,14245,14246],{"class":1168},"# With file watching (auto-restart on changes)\n",[436,14248,14249,14251,14253,14256],{"class":438,"line":5202},[436,14250,1135],{"class":442},[436,14252,1138],{"class":446},[436,14254,14255],{"class":446}," serve",[436,14257,14258],{"class":5565}," --watch\n",[436,14260,14261],{"class":438,"line":5208},[436,14262,5212],{"emptyLinePlaceholder":5211},[436,14264,14265],{"class":438,"line":5215},[436,14266,14267],{"class":1168},"# With integrated queue worker\n",[436,14269,14270,14272,14274,14276],{"class":438,"line":5221},[436,14271,1135],{"class":442},[436,14273,1138],{"class":446},[436,14275,14255],{"class":446},[436,14277,14278],{"class":5565}," --queue\n",[436,14280,14281],{"class":438,"line":5249},[436,14282,5212],{"emptyLinePlaceholder":5211},[436,14284,14285],{"class":438,"line":5254},[436,14286,14287],{"class":1168},"# Custom port and poll interval\n",[436,14289,14290,14292,14294,14296,14299,14302],{"class":438,"line":5298},[436,14291,1135],{"class":442},[436,14293,1138],{"class":446},[436,14295,14255],{"class":446},[436,14297,14298],{"class":5565}," --port=8080",[436,14300,14301],{"class":5565}," --watch",[436,14303,14304],{"class":5565}," --poll-interval=2000\n",[436,14306,14307],{"class":438,"line":5324},[436,14308,5212],{"emptyLinePlaceholder":5211},[436,14310,14311],{"class":438,"line":5329},[436,14312,14313],{"class":1168},"# Full development setup\n",[436,14315,14316,14318,14320,14322,14324,14327],{"class":438,"line":6717},[436,14317,1135],{"class":442},[436,14319,1138],{"class":446},[436,14321,14255],{"class":446},[436,14323,14301],{"class":5565},[436,14325,14326],{"class":5565}," --queue",[436,14328,14329],{"class":5565}," --port=8000\n",[347,14331,14333],{"id":14332},"command-options","Command Options",[5285,14335,14336,14345],{},[8831,14337,14338],{},[8834,14339,14340,14343],{},[8837,14341,14342],{},"Option",[8837,14344,9121],{},[8843,14346,14347,14357,14367,14376,14385],{},[8834,14348,14349,14354],{},[8848,14350,14351],{},[325,14352,14353],{},"--port=8000",[8848,14355,14356],{},"Specify the port (default: 8000)",[8834,14358,14359,14364],{},[8848,14360,14361],{},[325,14362,14363],{},"--host=localhost",[8848,14365,14366],{},"Specify the host (default: localhost)",[8834,14368,14369,14373],{},[8848,14370,14371],{},[325,14372,14121],{},[8848,14374,14375],{},"Enable file watching for auto-restart",[8834,14377,14378,14382],{},[8848,14379,14380],{},[325,14381,4637],{},[8848,14383,14384],{},"Start integrated queue worker",[8834,14386,14387,14392],{},[8848,14388,14389],{},[325,14390,14391],{},"--poll-interval=1000",[8848,14393,14394],{},"File watch poll interval in ms",[347,14396,413],{"id":14397},"migration-notes-26",[312,14399,14400],{"color":3075,"icon":11902,"variant":316},[318,14401,14402],{"v-slot:description":320},[293,14403,14404],{},"No breaking changes. All new features are opt-in via command flags.",[415,14406,14407,14413,14421],{},[418,14408,13245,14409,14412],{},[325,14410,14411],{},"php glueful serve"," continues to work unchanged",[418,14414,14415,14416,542,14418,14420],{},"New features activated via ",[325,14417,14121],{},[325,14419,4637],{}," flags",[418,14422,14423],{},"Completes Priority 2 developer experience features",[452,14425],{},[301,14427,14429],{"id":14428},"v1140-bellatrix-minor","v1.14.0 - Bellatrix (Minor)",[293,14431,14432],{},[308,14433,8692],{},[312,14435,14437],{"color":314,"icon":14436,"variant":316},"i-tabler-sparkles",[318,14438,14439],{"v-slot:description":320},[293,14440,14441],{},"Feature release introducing Interactive CLI Wizards for enhanced developer experience with interactive prompts, progress bars, and spinner animations.",[347,14443,350],{"id":14444},"key-highlights-37",[352,14446,14447,14452],{},[293,14448,14449],{},[308,14450,14451],{},"Prompter Class",[415,14453,14454,14457,14466,14472,14478,14487],{},[418,14455,14456],{},"Fluent API for CLI prompts with automatic non-interactive fallback",[418,14458,14459,332,14462,14465],{},[325,14460,14461],{},"ask()",[325,14463,14464],{},"askRequired()"," - Text input with validation",[418,14467,14468,14471],{},[325,14469,14470],{},"secret()"," - Hidden input for passwords/secrets",[418,14473,14474,14477],{},[325,14475,14476],{},"confirm()"," - Yes/no confirmation prompts",[418,14479,14480,332,14483,14486],{},[325,14481,14482],{},"choice()",[325,14484,14485],{},"multiChoice()"," - Single and multiple selection menus",[418,14488,14489,14492],{},[325,14490,14491],{},"suggest()"," - Input with auto-completion suggestions",[352,14494,14495,14500],{},[293,14496,14497],{},[308,14498,14499],{},"Progress Indicators",[415,14501,14502,14509,14515,14521],{},[418,14503,14504,14505,14508],{},"Enhanced ",[325,14506,14507],{},"ProgressBar"," wrapper with predefined formats",[418,14510,14511,14514],{},[325,14512,14513],{},"iterate()"," generator for automatic progress tracking",[418,14516,14517,14520],{},[325,14518,14519],{},"Spinner"," class with multiple animation styles",[418,14522,14523,14524,542,14527,14530],{},"Easy ",[325,14525,14526],{},"withProgress()",[325,14528,14529],{},"withSpinner()"," helpers in BaseCommand",[352,14532,14533,14538],{},[293,14534,14535],{},[308,14536,14537],{},"Interactive Scaffold Commands",[415,14539,14540,14543,14549,14555],{},[418,14541,14542],{},"Scaffold commands now prompt for arguments when not provided",[418,14544,14545,14548],{},[325,14546,14547],{},"scaffold:model"," supports full interactive mode",[418,14550,14551,14552,4903],{},"Maintains CLI compatibility with ",[325,14553,14554],{},"--no-interaction",[418,14556,14557],{},"Graceful fallback to defaults in CI/CD environments",[347,14559,14561],{"id":14560},"interactive-components","Interactive Components",[293,14563,14564],{},[308,14565,14566],{},"Prompter Methods:",[5285,14568,14569,14577],{},[8831,14570,14571],{},[8834,14572,14573,14575],{},[8837,14574,10849],{},[8837,14576,9121],{},[8843,14578,14579,14589,14599,14609,14619,14629,14639],{},[8834,14580,14581,14586],{},[8848,14582,14583],{},[325,14584,14585],{},"ask(question, default, validator)",[8848,14587,14588],{},"Text input with optional validation",[8834,14590,14591,14596],{},[8848,14592,14593],{},[325,14594,14595],{},"askRequired(question, default)",[8848,14597,14598],{},"Required text input",[8834,14600,14601,14606],{},[8848,14602,14603],{},[325,14604,14605],{},"secret(question, validator)",[8848,14607,14608],{},"Hidden input for passwords",[8834,14610,14611,14616],{},[8848,14612,14613],{},[325,14614,14615],{},"confirm(question, default)",[8848,14617,14618],{},"Yes/no confirmation",[8834,14620,14621,14626],{},[8848,14622,14623],{},[325,14624,14625],{},"choice(question, choices, default)",[8848,14627,14628],{},"Single selection from options",[8834,14630,14631,14636],{},[8848,14632,14633],{},[325,14634,14635],{},"multiChoice(question, choices, defaults)",[8848,14637,14638],{},"Multiple selection",[8834,14640,14641,14646],{},[8848,14642,14643],{},[325,14644,14645],{},"suggest(question, suggestions, default)",[8848,14647,14648],{},"Input with auto-completion",[293,14650,14651],{},[308,14652,14653],{},"Progress Formats:",[5285,14655,14656,14665],{},[8831,14657,14658],{},[8834,14659,14660,14663],{},[8837,14661,14662],{},"Format",[8837,14664,9121],{},[8843,14666,14667,14677,14687,14697,14707],{},[8834,14668,14669,14674],{},[8848,14670,14671],{},[325,14672,14673],{},"FORMAT_NORMAL",[8848,14675,14676],{},"Basic progress display",[8834,14678,14679,14684],{},[8848,14680,14681],{},[325,14682,14683],{},"FORMAT_VERBOSE",[8848,14685,14686],{},"Progress with elapsed time",[8834,14688,14689,14694],{},[8848,14690,14691],{},[325,14692,14693],{},"FORMAT_VERY_VERBOSE",[8848,14695,14696],{},"Progress with elapsed and estimated time",[8834,14698,14699,14704],{},[8848,14700,14701],{},[325,14702,14703],{},"FORMAT_DEBUG",[8848,14705,14706],{},"Full progress with memory usage",[8834,14708,14709,14714],{},[8848,14710,14711],{},[325,14712,14713],{},"FORMAT_WITH_MESSAGE",[8848,14715,14716],{},"Progress with custom message",[293,14718,14719],{},[308,14720,14721],{},"Spinner Styles:",[5285,14723,14724,14734],{},[8831,14725,14726],{},[8834,14727,14728,14731],{},[8837,14729,14730],{},"Style",[8837,14732,14733],{},"Animation",[8843,14735,14736,14746,14755,14765,14775,14785,14795,14805,14815],{},[8834,14737,14738,14743],{},[8848,14739,14740],{},[325,14741,14742],{},"dots",[8848,14744,14745],{},"Braille dot animation (default)",[8834,14747,14748,14752],{},[8848,14749,14750],{},[325,14751,438],{},[8848,14753,14754],{},"Classic line spinner",[8834,14756,14757,14762],{},[8848,14758,14759],{},[325,14760,14761],{},"arrows",[8848,14763,14764],{},"Directional arrows",[8834,14766,14767,14772],{},[8848,14768,14769],{},[325,14770,14771],{},"bouncing",[8848,14773,14774],{},"Bouncing dots",[8834,14776,14777,14782],{},[8848,14778,14779],{},[325,14780,14781],{},"growing",[8848,14783,14784],{},"Growing bar",[8834,14786,14787,14792],{},[8848,14788,14789],{},[325,14790,14791],{},"circle",[8848,14793,14794],{},"Circle quadrants",[8834,14796,14797,14802],{},[8848,14798,14799],{},[325,14800,14801],{},"square",[8848,14803,14804],{},"Square quadrants",[8834,14806,14807,14812],{},[8848,14808,14809],{},[325,14810,14811],{},"toggle",[8848,14813,14814],{},"Toggle switch",[8834,14816,14817,14822],{},[8848,14818,14819],{},[325,14820,14821],{},"simple",[8848,14823,14824],{},"Simple dots",[347,14826,14828],{"id":14827},"basecommand-helpers","BaseCommand Helpers",[293,14830,14831],{},[308,14832,14833],{},"New Methods:",[5285,14835,14836,14844],{},[8831,14837,14838],{},[8834,14839,14840,14842],{},[8837,14841,10849],{},[8837,14843,9121],{},[8843,14845,14846,14856,14866,14876,14886,14895,14903,14913,14923,14933,14943],{},[8834,14847,14848,14853],{},[8848,14849,14850],{},[325,14851,14852],{},"getPrompter()",[8848,14854,14855],{},"Get Prompter instance",[8834,14857,14858,14863],{},[8848,14859,14860],{},[325,14861,14862],{},"isInteractive()",[8848,14864,14865],{},"Check if running interactively",[8834,14867,14868,14873],{},[8848,14869,14870],{},[325,14871,14872],{},"prompt()",[8848,14874,14875],{},"Quick text input",[8834,14877,14878,14883],{},[8848,14879,14880],{},[325,14881,14882],{},"promptRequired()",[8848,14884,14885],{},"Quick required text input",[8834,14887,14888,14892],{},[8848,14889,14890],{},[325,14891,14485],{},[8848,14893,14894],{},"Multi-select from options",[8834,14896,14897,14901],{},[8848,14898,14899],{},[325,14900,14491],{},[8848,14902,14648],{},[8834,14904,14905,14910],{},[8848,14906,14907],{},[325,14908,14909],{},"createEnhancedProgressBar()",[8848,14911,14912],{},"Get enhanced progress bar",[8834,14914,14915,14920],{},[8848,14916,14917],{},[325,14918,14919],{},"createSpinner()",[8848,14921,14922],{},"Create spinner instance",[8834,14924,14925,14930],{},[8848,14926,14927],{},[325,14928,14929],{},"withProgress(items, callback)",[8848,14931,14932],{},"Process items with progress",[8834,14934,14935,14940],{},[8848,14936,14937],{},[325,14938,14939],{},"withSpinner(callback, message)",[8848,14941,14942],{},"Run task with spinner",[8834,14944,14945,14950],{},[8848,14946,14947],{},[325,14948,14949],{},"confirmDestructive(message)",[8848,14951,14952],{},"Confirmation for destructive ops",[347,14954,413],{"id":14955},"migration-notes-27",[312,14957,14958],{"color":3075,"icon":11902,"variant":316},[318,14959,14960],{"v-slot:description":320},[293,14961,14962,14963,14965],{},"No breaking changes. All interactive features gracefully fallback to defaults when ",[325,14964,14554],{}," flag is used.",[293,14967,14968],{},[308,14969,14970],{},"Non-Interactive Mode:",[428,14972,14974],{"className":430,"code":14973,"language":432,"meta":320,"style":320},"# All prompts use defaults in CI/CD\nphp glueful scaffold:model User --migration --no-interaction\n",[325,14975,14976,14981],{"__ignoreMap":320},[436,14977,14978],{"class":438,"line":439},[436,14979,14980],{"class":1168},"# All prompts use defaults in CI/CD\n",[436,14982,14983,14985,14987,14990,14992,14995],{"class":438,"line":1132},[436,14984,1135],{"class":442},[436,14986,1138],{"class":446},[436,14988,14989],{"class":446}," scaffold:model",[436,14991,9817],{"class":446},[436,14993,14994],{"class":5565}," --migration",[436,14996,14997],{"class":5565}," --no-interaction\n",[347,14999,15001],{"id":15000},"requirements","Requirements",[415,15003,15004,15007],{},[418,15005,15006],{},"No additional dependencies required",[418,15008,15009],{},"All features built on existing Symfony Console components",[452,15011],{},[301,15013,15015],{"id":15014},"v1130-saiph-minor","v1.13.0 - Saiph (Minor)",[293,15017,15018],{},[308,15019,8692],{},[312,15021,15023],{"color":314,"icon":15022,"variant":316},"i-tabler-tools",[318,15024,15025],{"v-slot:description":320},[293,15026,15027],{},"Feature release introducing Enhanced Scaffold Commands and Database Factories & Seeders, completing Priority 2 developer experience features.",[347,15029,350],{"id":15030},"key-highlights-38",[352,15032,15033,15038],{},[293,15034,15035],{},[308,15036,15037],{},"Enhanced Scaffold Commands",[415,15039,15040,15049,15055,15061],{},[418,15041,15042,15045,15046],{},[325,15043,15044],{},"scaffold:middleware"," - Generate route middleware implementing ",[325,15047,15048],{},"RouteMiddleware",[418,15050,15051,15054],{},[325,15052,15053],{},"scaffold:job"," - Generate queue jobs with configurable retries and timeouts",[418,15056,15057,15060],{},[325,15058,15059],{},"scaffold:rule"," - Generate validation rules with parameter support",[418,15062,15063,15066],{},[325,15064,15065],{},"scaffold:test"," - Generate PHPUnit unit and feature test classes",[352,15068,15069,15074],{},[293,15070,15071],{},[308,15072,15073],{},"Database Factories",[415,15075,15076,15079,15088,15091,15101],{},[418,15077,15078],{},"Factory base class with fluent interface for test data generation",[418,15080,15081,15082,332,15085,4887],{},"Factory states for model variations (e.g., ",[325,15083,15084],{},"->admin()",[325,15086,15087],{},"->unverified()",[418,15089,15090],{},"Sequences for rotating attribute values across created models",[418,15092,15093,15094,542,15097,15100],{},"Relationship support with ",[325,15095,15096],{},"has()",[325,15098,15099],{},"for()"," methods",[418,15102,15103,15106,15107,5030],{},[325,15104,15105],{},"HasFactory"," trait for ORM models enabling ",[325,15108,15109],{},"Model::factory()",[352,15111,15112,15117],{},[293,15113,15114],{},[308,15115,15116],{},"Database Seeders",[415,15118,15119,15122,15125,15131],{},[418,15120,15121],{},"Seeder base class with dependency ordering",[418,15123,15124],{},"Transaction support for atomic seeding operations",[418,15126,15127,15130],{},[325,15128,15129],{},"db:seed"," command with production environment protection",[418,15132,15133,15136],{},[325,15134,15135],{},"scaffold:seeder"," command for generating seeder classes",[347,15138,15140],{"id":15139},"scaffold-commands","Scaffold Commands",[293,15142,15143],{},[308,15144,15145],{},"New Commands:",[5285,15147,15148,15156],{},[8831,15149,15150],{},[8834,15151,15152,15154],{},[8837,15153,10802],{},[8837,15155,8999],{},[8843,15157,15158,15169,15181,15193,15202,15212,15221],{},[8834,15159,15160,15164],{},[8848,15161,15162],{},[325,15163,15044],{},[8848,15165,15166,15167],{},"Generate middleware implementing ",[325,15168,15048],{},[8834,15170,15171,15175],{},[8848,15172,15173],{},[325,15174,15053],{},[8848,15176,15177,15178],{},"Generate queue job classes extending ",[325,15179,15180],{},"Job",[8834,15182,15183,15187],{},[8848,15184,15185],{},[325,15186,15059],{},[8848,15188,15189,15190],{},"Generate validation rule classes implementing ",[325,15191,15192],{},"Rule",[8834,15194,15195,15199],{},[8848,15196,15197],{},[325,15198,15065],{},[8848,15200,15201],{},"Generate PHPUnit test classes (unit/feature)",[8834,15203,15204,15209],{},[8848,15205,15206],{},[325,15207,15208],{},"scaffold:factory",[8848,15210,15211],{},"Generate model factory classes",[8834,15213,15214,15218],{},[8848,15215,15216],{},[325,15217,15135],{},[8848,15219,15220],{},"Generate database seeder classes",[8834,15222,15223,15227],{},[8848,15224,15225],{},[325,15226,15129],{},[8848,15228,15229],{},"Run database seeders",[293,15231,15232],{},[308,15233,15234],{},"Command Options:",[5285,15236,15237,15246],{},[8831,15238,15239],{},[8834,15240,15241,15243],{},[8837,15242,10802],{},[8837,15244,15245],{},"Options",[8843,15247,15248,15260,15282,15296,15316,15331,15345],{},[8834,15249,15250,15254],{},[8848,15251,15252],{},[325,15253,15044],{},[8848,15255,15256,332,15258],{},[325,15257,6470],{},[325,15259,5416],{},[8834,15261,15262,15266],{},[8848,15263,15264],{},[325,15265,15053],{},[8848,15267,15268,332,15270,332,15273,332,15276,332,15279],{},[325,15269,4637],{},[325,15271,15272],{},"--tries",[325,15274,15275],{},"--backoff",[325,15277,15278],{},"--timeout",[325,15280,15281],{},"--unique",[8834,15283,15284,15288],{},[8848,15285,15286],{},[325,15287,15059],{},[8848,15289,15290,332,15293],{},[325,15291,15292],{},"--params",[325,15294,15295],{},"--implicit",[8834,15297,15298,15302],{},[8848,15299,15300],{},[325,15301,15065],{},[8848,15303,15304,332,15307,332,15310,332,15313],{},[325,15305,15306],{},"--unit",[325,15308,15309],{},"--feature",[325,15311,15312],{},"--class",[325,15314,15315],{},"--methods",[8834,15317,15318,15322],{},[8848,15319,15320],{},[325,15321,15208],{},[8848,15323,15324,332,15327,332,15329],{},[325,15325,15326],{},"--model",[325,15328,6470],{},[325,15330,5416],{},[8834,15332,15333,15337],{},[8848,15334,15335],{},[325,15336,15135],{},[8848,15338,15339,332,15341,332,15343],{},[325,15340,15326],{},[325,15342,6470],{},[325,15344,5416],{},[8834,15346,15347,15351],{},[8848,15348,15349],{},[325,15350,15129],{},[8848,15352,15353,15355],{},[325,15354,6470],{}," (required in production)",[347,15357,15359],{"id":15358},"factory-components","Factory Components",[293,15361,15362],{},[308,15363,8987],{},[5285,15365,15366,15374],{},[8831,15367,15368],{},[8834,15369,15370,15372],{},[8837,15371,8996],{},[8837,15373,8999],{},[8843,15375,15376,15386,15396],{},[8834,15377,15378,15383],{},[8848,15379,15380],{},[325,15381,15382],{},"Factory",[8848,15384,15385],{},"Base class for model factories with fluent interface",[8834,15387,15388,15393],{},[8848,15389,15390],{},[325,15391,15392],{},"FakerBridge",[8848,15394,15395],{},"Bridge to optional Faker library with availability checking",[8834,15397,15398,15402],{},[8848,15399,15400],{},[325,15401,15105],{},[8848,15403,15404,15405,5030],{},"Trait for models to enable ",[325,15406,15109],{},[293,15408,15409],{},[308,15410,15411],{},"Factory Methods:",[5285,15413,15414,15422],{},[8831,15415,15416],{},[8834,15417,15418,15420],{},[8837,15419,10849],{},[8837,15421,8999],{},[8843,15423,15424,15434,15444,15454,15464,15477,15487,15497],{},[8834,15425,15426,15431],{},[8848,15427,15428],{},[325,15429,15430],{},"definition()",[8848,15432,15433],{},"Define default model attributes",[8834,15435,15436,15441],{},[8848,15437,15438],{},[325,15439,15440],{},"count(int $n)",[8848,15442,15443],{},"Set number of models to create",[8834,15445,15446,15451],{},[8848,15447,15448],{},[325,15449,15450],{},"state(array|string|callable)",[8848,15452,15453],{},"Apply state transformations",[8834,15455,15456,15461],{},[8848,15457,15458],{},[325,15459,15460],{},"sequence(array...)",[8848,15462,15463],{},"Rotate attribute values",[8834,15465,15466,15474],{},[8848,15467,15468,392,15471],{},[325,15469,15470],{},"make()",[325,15472,15473],{},"create()",[8848,15475,15476],{},"Build models (without/with persistence)",[8834,15478,15479,15484],{},[8848,15480,15481],{},[325,15482,15483],{},"has(string $relation, int|Factory)",[8848,15485,15486],{},"Create with has-many relationships",[8834,15488,15489,15494],{},[8848,15490,15491],{},[325,15492,15493],{},"for(string $relation, Factory|Model)",[8848,15495,15496],{},"Create with belongs-to relationships",[8834,15498,15499,15504],{},[8848,15500,15501],{},[325,15502,15503],{},"recycle(Collection|Model)",[8848,15505,15506],{},"Reuse existing models for relationships",[347,15508,15510],{"id":15509},"seeder-components","Seeder Components",[293,15512,15513],{},[308,15514,8987],{},[5285,15516,15517,15525],{},[8831,15518,15519],{},[8834,15520,15521,15523],{},[8837,15522,8996],{},[8837,15524,8999],{},[8843,15526,15527,15537],{},[8834,15528,15529,15534],{},[8848,15530,15531],{},[325,15532,15533],{},"Seeder",[8848,15535,15536],{},"Base class for database seeders",[8834,15538,15539,15544],{},[8848,15540,15541],{},[325,15542,15543],{},"DatabaseSeeder",[8848,15545,15546],{},"Main orchestrator for all seeders",[293,15548,15549],{},[308,15550,15551],{},"Seeder Methods:",[5285,15553,15554,15562],{},[8831,15555,15556],{},[8834,15557,15558,15560],{},[8837,15559,10849],{},[8837,15561,8999],{},[8843,15563,15564,15574,15584,15594],{},[8834,15565,15566,15571],{},[8848,15567,15568],{},[325,15569,15570],{},"run()",[8848,15572,15573],{},"Abstract method to implement seeding logic",[8834,15575,15576,15581],{},[8848,15577,15578],{},[325,15579,15580],{},"call(string|array $class)",[8848,15582,15583],{},"Call other seeders",[8834,15585,15586,15591],{},[8848,15587,15588],{},[325,15589,15590],{},"withTransaction(callable)",[8848,15592,15593],{},"Wrap operations in database transaction",[8834,15595,15596,15601],{},[8848,15597,15598],{},[325,15599,15600],{},"truncate(string $table)",[8848,15602,15603],{},"Clear table before seeding",[347,15605,9391],{"id":15606},"quick-usage-5",[428,15608,15610],{"className":5139,"code":15609,"language":1135,"meta":320,"style":320},"// Define a factory\nclass UserFactory extends Factory\n{\n    protected string $model = User::class;\n\n    public function definition(): array\n    {\n        return [\n            'name' => $this->faker->name(),\n            'email' => $this->faker->unique()->safeEmail(),\n            'status' => 'active',\n        ];\n    }\n\n    public function admin(): static\n    {\n        return $this->state(['role' => 'admin']);\n    }\n}\n\n// Use the factory\n$user = User::factory()->create();\n$admins = User::factory()->count(5)->admin()->create();\n\n// Create with relationships\n$user = User::factory()\n    ->has('posts', 3)\n    ->create();\n",[325,15611,15612,15617,15629,15633,15655,15659,15674,15678,15684,15708,15738,15757,15762,15766,15770,15786,15790,15821,15825,15829,15833,15838,15863,15903,15907,15912,15929,15952],{"__ignoreMap":320},[436,15613,15614],{"class":438,"line":439},[436,15615,15616],{"class":1168},"// Define a factory\n",[436,15618,15619,15621,15624,15626],{"class":438,"line":1132},[436,15620,6059],{"class":5155},[436,15622,15623],{"class":9486}," UserFactory",[436,15625,9490],{"class":5152},[436,15627,15628],{"class":9493}," Factory\n",[436,15630,15631],{"class":438,"line":1158},[436,15632,5193],{"class":5163},[436,15634,15635,15637,15640,15642,15645,15647,15649,15651,15653],{"class":438,"line":5196},[436,15636,9503],{"class":5152},[436,15638,15639],{"class":5167}," string",[436,15641,5171],{"class":5163},[436,15643,15644],{"class":1151},"model ",[436,15646,3168],{"class":1144},[436,15648,9817],{"class":5233},[436,15650,6056],{"class":1144},[436,15652,6059],{"class":5167},[436,15654,5816],{"class":5163},[436,15656,15657],{"class":438,"line":5202},[436,15658,5212],{"emptyLinePlaceholder":5211},[436,15660,15661,15663,15665,15668,15670,15672],{"class":438,"line":5208},[436,15662,11170],{"class":5152},[436,15664,5156],{"class":5155},[436,15666,15667],{"class":5159}," definition",[436,15669,7677],{"class":5163},[436,15671,5243],{"class":1144},[436,15673,11225],{"class":5167},[436,15675,15676],{"class":438,"line":5215},[436,15677,11187],{"class":5163},[436,15679,15680,15682],{"class":438,"line":5221},[436,15681,11192],{"class":5788},[436,15683,6857],{"class":5163},[436,15685,15686,15688,15690,15692,15694,15696,15698,15701,15703,15705],{"class":438,"line":5249},[436,15687,10331],{"class":5281},[436,15689,9522],{"class":446},[436,15691,5282],{"class":5281},[436,15693,6000],{"class":1144},[436,15695,5770],{"class":5769},[436,15697,5269],{"class":1144},[436,15699,15700],{"class":1151},"faker",[436,15702,5269],{"class":1144},[436,15704,9522],{"class":5159},[436,15706,15707],{"class":5163},"(),\n",[436,15709,15710,15712,15714,15716,15718,15720,15722,15724,15726,15729,15731,15733,15736],{"class":438,"line":5254},[436,15711,10331],{"class":5281},[436,15713,2688],{"class":446},[436,15715,5282],{"class":5281},[436,15717,6000],{"class":1144},[436,15719,5770],{"class":5769},[436,15721,5269],{"class":1144},[436,15723,15700],{"class":1151},[436,15725,5269],{"class":1144},[436,15727,15728],{"class":5159},"unique",[436,15730,7677],{"class":5163},[436,15732,5269],{"class":1144},[436,15734,15735],{"class":5159},"safeEmail",[436,15737,15707],{"class":5163},[436,15739,15740,15742,15744,15746,15748,15750,15753,15755],{"class":438,"line":5298},[436,15741,10331],{"class":5281},[436,15743,9588],{"class":446},[436,15745,5282],{"class":5281},[436,15747,6000],{"class":1144},[436,15749,6064],{"class":5281},[436,15751,15752],{"class":446},"active",[436,15754,5282],{"class":5281},[436,15756,6907],{"class":5163},[436,15758,15759],{"class":438,"line":5324},[436,15760,15761],{"class":5163},"        ];\n",[436,15763,15764],{"class":438,"line":5329},[436,15765,11205],{"class":5163},[436,15767,15768],{"class":438,"line":6717},[436,15769,5212],{"emptyLinePlaceholder":5211},[436,15771,15772,15774,15776,15779,15781,15783],{"class":438,"line":6742},[436,15773,11170],{"class":5152},[436,15775,5156],{"class":5155},[436,15777,15778],{"class":5159}," admin",[436,15780,7677],{"class":5163},[436,15782,5243],{"class":1144},[436,15784,15785],{"class":5155}," static\n",[436,15787,15788],{"class":438,"line":6767},[436,15789,11187],{"class":5163},[436,15791,15792,15794,15796,15798,15801,15803,15805,15808,15810,15812,15814,15817,15819],{"class":438,"line":6772},[436,15793,11192],{"class":5788},[436,15795,5770],{"class":5769},[436,15797,5269],{"class":1144},[436,15799,15800],{"class":5159},"state",[436,15802,5990],{"class":5163},[436,15804,5282],{"class":5281},[436,15806,15807],{"class":446},"role",[436,15809,5282],{"class":5281},[436,15811,6000],{"class":1144},[436,15813,6064],{"class":5281},[436,15815,15816],{"class":446},"admin",[436,15818,5282],{"class":5281},[436,15820,6072],{"class":5163},[436,15822,15823],{"class":438,"line":6778},[436,15824,11205],{"class":5163},[436,15826,15827],{"class":438,"line":6810},[436,15828,5205],{"class":5163},[436,15830,15831],{"class":438,"line":9754},[436,15832,5212],{"emptyLinePlaceholder":5211},[436,15834,15835],{"class":438,"line":9801},[436,15836,15837],{"class":1168},"// Use the factory\n",[436,15839,15840,15842,15845,15847,15849,15851,15854,15856,15858,15861],{"class":438,"line":9806},[436,15841,5761],{"class":5163},[436,15843,15844],{"class":1151},"user ",[436,15846,3168],{"class":1144},[436,15848,9817],{"class":5233},[436,15850,6056],{"class":1144},[436,15852,15853],{"class":5159},"factory",[436,15855,7677],{"class":5163},[436,15857,5269],{"class":1144},[436,15859,15860],{"class":5159},"create",[436,15862,5321],{"class":5163},[436,15864,15865,15867,15870,15872,15874,15876,15878,15880,15882,15884,15886,15889,15891,15893,15895,15897,15899,15901],{"class":438,"line":9812},[436,15866,5761],{"class":5163},[436,15868,15869],{"class":1151},"admins ",[436,15871,3168],{"class":1144},[436,15873,9817],{"class":5233},[436,15875,6056],{"class":1144},[436,15877,15853],{"class":5159},[436,15879,7677],{"class":5163},[436,15881,5269],{"class":1144},[436,15883,1199],{"class":5159},[436,15885,5164],{"class":5163},[436,15887,15888],{"class":7256},"5",[436,15890,4887],{"class":5163},[436,15892,5269],{"class":1144},[436,15894,15816],{"class":5159},[436,15896,7677],{"class":5163},[436,15898,5269],{"class":1144},[436,15900,15860],{"class":5159},[436,15902,5321],{"class":5163},[436,15904,15905],{"class":438,"line":9825},[436,15906,5212],{"emptyLinePlaceholder":5211},[436,15908,15909],{"class":438,"line":9830},[436,15910,15911],{"class":1168},"// Create with relationships\n",[436,15913,15914,15916,15918,15920,15922,15924,15926],{"class":438,"line":9841},[436,15915,5761],{"class":5163},[436,15917,15844],{"class":1151},[436,15919,3168],{"class":1144},[436,15921,9817],{"class":5233},[436,15923,6056],{"class":1144},[436,15925,15853],{"class":5159},[436,15927,15928],{"class":5163},"()\n",[436,15930,15931,15933,15936,15938,15940,15943,15945,15947,15950],{"class":438,"line":9846},[436,15932,12789],{"class":1144},[436,15934,15935],{"class":5159},"has",[436,15937,5164],{"class":5163},[436,15939,5282],{"class":5281},[436,15941,15942],{"class":446},"posts",[436,15944,5282],{"class":5281},[436,15946,5177],{"class":5163},[436,15948,15949],{"class":7256}," 3",[436,15951,5188],{"class":5163},[436,15953,15954,15956,15958],{"class":438,"line":9887},[436,15955,12789],{"class":1144},[436,15957,15860],{"class":5159},[436,15959,5321],{"class":5163},[428,15961,15963],{"className":5139,"code":15962,"language":1135,"meta":320,"style":320},"// Define a seeder\nclass UserSeeder extends Seeder\n{\n    protected array $dependencies = [RoleSeeder::class];\n\n    public function run(): void\n    {\n        User::factory()->admin()->create([\n            'email' => 'admin@example.com',\n        ]);\n\n        User::factory()->count(50)->create();\n    }\n}\n\n// Run seeders\n// php glueful db:seed\n// php glueful db:seed UserSeeder\n// php glueful db:seed --force (production)\n",[325,15964,15965,15970,15982,15986,16010,16014,16030,16034,16058,16077,16082,16086,16113,16117,16121,16125,16130,16135,16140],{"__ignoreMap":320},[436,15966,15967],{"class":438,"line":439},[436,15968,15969],{"class":1168},"// Define a seeder\n",[436,15971,15972,15974,15977,15979],{"class":438,"line":1132},[436,15973,6059],{"class":5155},[436,15975,15976],{"class":9486}," UserSeeder",[436,15978,9490],{"class":5152},[436,15980,15981],{"class":9493}," Seeder\n",[436,15983,15984],{"class":438,"line":1158},[436,15985,5193],{"class":5163},[436,15987,15988,15990,15992,15994,15997,15999,16001,16004,16006,16008],{"class":438,"line":5196},[436,15989,9503],{"class":5152},[436,15991,5180],{"class":5167},[436,15993,5171],{"class":5163},[436,15995,15996],{"class":1151},"dependencies ",[436,15998,3168],{"class":1144},[436,16000,6050],{"class":5163},[436,16002,16003],{"class":5233},"RoleSeeder",[436,16005,6056],{"class":1144},[436,16007,6059],{"class":5167},[436,16009,6968],{"class":5163},[436,16011,16012],{"class":438,"line":5202},[436,16013,5212],{"emptyLinePlaceholder":5211},[436,16015,16016,16018,16020,16023,16025,16027],{"class":438,"line":5208},[436,16017,11170],{"class":5152},[436,16019,5156],{"class":5155},[436,16021,16022],{"class":5159}," run",[436,16024,7677],{"class":5163},[436,16026,5243],{"class":1144},[436,16028,16029],{"class":5167}," void\n",[436,16031,16032],{"class":438,"line":5215},[436,16033,11187],{"class":5163},[436,16035,16036,16039,16041,16043,16045,16047,16049,16051,16053,16055],{"class":438,"line":5221},[436,16037,16038],{"class":5233},"        User",[436,16040,6056],{"class":1144},[436,16042,15853],{"class":5159},[436,16044,7677],{"class":5163},[436,16046,5269],{"class":1144},[436,16048,15816],{"class":5159},[436,16050,7677],{"class":5163},[436,16052,5269],{"class":1144},[436,16054,15860],{"class":5159},[436,16056,16057],{"class":5163},"([\n",[436,16059,16060,16062,16064,16066,16068,16070,16073,16075],{"class":438,"line":5249},[436,16061,10331],{"class":5281},[436,16063,2688],{"class":446},[436,16065,5282],{"class":5281},[436,16067,6000],{"class":1144},[436,16069,6064],{"class":5281},[436,16071,16072],{"class":446},"admin@example.com",[436,16074,5282],{"class":5281},[436,16076,6907],{"class":5163},[436,16078,16079],{"class":438,"line":5254},[436,16080,16081],{"class":5163},"        ]);\n",[436,16083,16084],{"class":438,"line":5298},[436,16085,5212],{"emptyLinePlaceholder":5211},[436,16087,16088,16090,16092,16094,16096,16098,16100,16102,16105,16107,16109,16111],{"class":438,"line":5324},[436,16089,16038],{"class":5233},[436,16091,6056],{"class":1144},[436,16093,15853],{"class":5159},[436,16095,7677],{"class":5163},[436,16097,5269],{"class":1144},[436,16099,1199],{"class":5159},[436,16101,5164],{"class":5163},[436,16103,16104],{"class":7256},"50",[436,16106,4887],{"class":5163},[436,16108,5269],{"class":1144},[436,16110,15860],{"class":5159},[436,16112,5321],{"class":5163},[436,16114,16115],{"class":438,"line":5329},[436,16116,11205],{"class":5163},[436,16118,16119],{"class":438,"line":6717},[436,16120,5205],{"class":5163},[436,16122,16123],{"class":438,"line":6742},[436,16124,5212],{"emptyLinePlaceholder":5211},[436,16126,16127],{"class":438,"line":6767},[436,16128,16129],{"class":1168},"// Run seeders\n",[436,16131,16132],{"class":438,"line":6772},[436,16133,16134],{"class":1168},"// php glueful db:seed\n",[436,16136,16137],{"class":438,"line":6778},[436,16138,16139],{"class":1168},"// php glueful db:seed UserSeeder\n",[436,16141,16142],{"class":438,"line":6810},[436,16143,16144],{"class":1168},"// php glueful db:seed --force (production)\n",[347,16146,16148],{"id":16147},"console-commands","Console Commands",[428,16150,16152],{"className":430,"code":16151,"language":432,"meta":320,"style":320},"# Generate scaffold classes\nphp glueful scaffold:middleware AuthMiddleware\nphp glueful scaffold:job ProcessPaymentJob --queue=payments --tries=3\nphp glueful scaffold:rule PhoneNumber --params=country\nphp glueful scaffold:test UserTest --feature --class=UserController\n\n# Generate factories and seeders\nphp glueful scaffold:factory UserFactory --model=User\nphp glueful scaffold:seeder UserSeeder --model=User\n\n# Run seeders\nphp glueful db:seed\nphp glueful db:seed UserSeeder\nphp glueful db:seed --force  # Required in production\n",[325,16153,16154,16159,16171,16189,16204,16222,16226,16231,16244,16257,16261,16266,16275,16287],{"__ignoreMap":320},[436,16155,16156],{"class":438,"line":439},[436,16157,16158],{"class":1168},"# Generate scaffold classes\n",[436,16160,16161,16163,16165,16168],{"class":438,"line":1132},[436,16162,1135],{"class":442},[436,16164,1138],{"class":446},[436,16166,16167],{"class":446}," scaffold:middleware",[436,16169,16170],{"class":446}," AuthMiddleware\n",[436,16172,16173,16175,16177,16180,16183,16186],{"class":438,"line":1158},[436,16174,1135],{"class":442},[436,16176,1138],{"class":446},[436,16178,16179],{"class":446}," scaffold:job",[436,16181,16182],{"class":446}," ProcessPaymentJob",[436,16184,16185],{"class":5565}," --queue=payments",[436,16187,16188],{"class":5565}," --tries=3\n",[436,16190,16191,16193,16195,16198,16201],{"class":438,"line":5196},[436,16192,1135],{"class":442},[436,16194,1138],{"class":446},[436,16196,16197],{"class":446}," scaffold:rule",[436,16199,16200],{"class":446}," PhoneNumber",[436,16202,16203],{"class":5565}," --params=country\n",[436,16205,16206,16208,16210,16213,16216,16219],{"class":438,"line":5202},[436,16207,1135],{"class":442},[436,16209,1138],{"class":446},[436,16211,16212],{"class":446}," scaffold:test",[436,16214,16215],{"class":446}," UserTest",[436,16217,16218],{"class":5565}," --feature",[436,16220,16221],{"class":5565}," --class=UserController\n",[436,16223,16224],{"class":438,"line":5208},[436,16225,5212],{"emptyLinePlaceholder":5211},[436,16227,16228],{"class":438,"line":5215},[436,16229,16230],{"class":1168},"# Generate factories and seeders\n",[436,16232,16233,16235,16237,16240,16242],{"class":438,"line":5221},[436,16234,1135],{"class":442},[436,16236,1138],{"class":446},[436,16238,16239],{"class":446}," scaffold:factory",[436,16241,15623],{"class":446},[436,16243,10506],{"class":5565},[436,16245,16246,16248,16250,16253,16255],{"class":438,"line":5249},[436,16247,1135],{"class":442},[436,16249,1138],{"class":446},[436,16251,16252],{"class":446}," scaffold:seeder",[436,16254,15976],{"class":446},[436,16256,10506],{"class":5565},[436,16258,16259],{"class":438,"line":5254},[436,16260,5212],{"emptyLinePlaceholder":5211},[436,16262,16263],{"class":438,"line":5298},[436,16264,16265],{"class":1168},"# Run seeders\n",[436,16267,16268,16270,16272],{"class":438,"line":5324},[436,16269,1135],{"class":442},[436,16271,1138],{"class":446},[436,16273,16274],{"class":446}," db:seed\n",[436,16276,16277,16279,16281,16284],{"class":438,"line":5329},[436,16278,1135],{"class":442},[436,16280,1138],{"class":446},[436,16282,16283],{"class":446}," db:seed",[436,16285,16286],{"class":446}," UserSeeder\n",[436,16288,16289,16291,16293,16295,16298],{"class":438,"line":6717},[436,16290,1135],{"class":442},[436,16292,1138],{"class":446},[436,16294,16283],{"class":446},[436,16296,16297],{"class":5565}," --force",[436,16299,16300],{"class":1168},"  # Required in production\n",[347,16302,413],{"id":16303},"migration-notes-28",[415,16305,16306,16309,16319,16328],{},[418,16307,16308],{},"No breaking changes. All features are opt-in and additive.",[418,16310,16311,16312,16315,16316],{},"Factories require ",[325,16313,16314],{},"fakerphp/faker"," as a dev dependency: ",[325,16317,16318],{},"composer require --dev fakerphp/faker",[418,16320,16321,16322,16324,16325,16327],{},"The ",[325,16323,15129],{}," command requires ",[325,16326,6470],{}," flag to run in production environments.",[418,16329,16330,16331,542,16334,299],{},"Generated files are placed in ",[325,16332,16333],{},"database/factories/",[325,16335,16336],{},"database/seeders/",[452,16338],{},[301,16340,16342],{"id":16341},"v1120-mintaka-minor","v1.12.0 - Mintaka (Minor)",[293,16344,16345],{},[308,16346,16347],{},"Released: January 21, 2026",[312,16349,16351],{"color":314,"icon":16350,"variant":316},"i-tabler-transform",[318,16352,16353],{"v-slot:description":320},[293,16354,16355],{},"Feature release introducing API Resource Transformers, completing the Priority 1 features for the framework's output layer.",[347,16357,350],{"id":16358},"key-highlights-39",[352,16360,16361,16366],{},[293,16362,16363],{},[308,16364,16365],{},"JSON Resource Transformation",[415,16367,16368,16371,16386,16389],{},[418,16369,16370],{},"JsonResource base class for transforming any data to JSON",[418,16372,16373,16374,332,16377,332,16380,332,16383],{},"Conditional attributes with ",[325,16375,16376],{},"when()",[325,16378,16379],{},"mergeWhen()",[325,16381,16382],{},"whenHas()",[325,16384,16385],{},"whenNotNull()",[418,16387,16388],{},"Response wrapping with configurable wrapper key",[418,16390,16391,16392,16395],{},"Additional metadata support via ",[325,16393,16394],{},"additional()"," method",[352,16397,16398,16403],{},[293,16399,16400],{},[308,16401,16402],{},"Model Resources",[415,16404,16405,16408,16417,16426],{},[418,16406,16407],{},"ModelResource with ORM-specific helpers",[418,16409,16410,542,16413,16416],{},[325,16411,16412],{},"attribute()",[325,16414,16415],{},"dateAttribute()"," for safe attribute access",[418,16418,16419,542,16422,16425],{},[325,16420,16421],{},"relationshipResource()",[325,16423,16424],{},"relationshipCollection()"," for nested transformations",[418,16427,16428,332,16431,332,16434,16437],{},[325,16429,16430],{},"whenLoaded()",[325,16432,16433],{},"whenCounted()",[325,16435,16436],{},"whenPivotLoaded()"," for relationships",[352,16439,16440,16445],{},[293,16441,16442],{},[308,16443,16444],{},"Collections & Pagination",[415,16446,16447,16450,16453,16456],{},[418,16448,16449],{},"ResourceCollection for multiple items with metadata",[418,16451,16452],{},"PaginatedResourceResponse with link generation",[418,16454,16455],{},"Support for both QueryBuilder and ORM pagination formats",[418,16457,16458,542,16461,16464],{},[325,16459,16460],{},"withPaginationFrom()",[325,16462,16463],{},"withLinks()"," helpers",[347,16466,16468],{"id":16467},"resource-components","Resource Components",[293,16470,16471],{},[308,16472,8987],{},[5285,16474,16475,16483],{},[8831,16476,16477],{},[8834,16478,16479,16481],{},[8837,16480,8996],{},[8837,16482,8999],{},[8843,16484,16485,16495,16505,16515,16524,16534],{},[8834,16486,16487,16492],{},[8848,16488,16489],{},[325,16490,16491],{},"JsonResource",[8848,16493,16494],{},"Base class for transforming arrays/objects to JSON",[8834,16496,16497,16502],{},[8848,16498,16499],{},[325,16500,16501],{},"ModelResource",[8848,16503,16504],{},"Extended resource with ORM-specific helpers",[8834,16506,16507,16512],{},[8848,16508,16509],{},[325,16510,16511],{},"ResourceCollection",[8848,16513,16514],{},"Collection wrapper with metadata support",[8834,16516,16517,16521],{},[8848,16518,16519],{},[325,16520,2655],{},[8848,16522,16523],{},"Pagination handling with link generation",[8834,16525,16526,16531],{},[8848,16527,16528],{},[325,16529,16530],{},"AnonymousResourceCollection",[8848,16532,16533],{},"Collection without dedicated class",[8834,16535,16536,16541],{},[8848,16537,16538],{},[325,16539,16540],{},"MissingValue",[8848,16542,16543],{},"Sentinel for conditional attribute omission",[293,16545,16546],{},[308,16547,16548],{},"Conditional Attribute Methods:",[5285,16550,16551,16559],{},[8831,16552,16553],{},[8834,16554,16555,16557],{},[8837,16556,10849],{},[8837,16558,8999],{},[8843,16560,16561,16571,16581,16591,16601,16611,16621],{},[8834,16562,16563,16568],{},[8848,16564,16565],{},[325,16566,16567],{},"when($condition, $value, $default)",[8848,16569,16570],{},"Include attribute conditionally",[8834,16572,16573,16578],{},[8848,16574,16575],{},[325,16576,16577],{},"mergeWhen($condition, $attributes)",[8848,16579,16580],{},"Merge multiple attributes conditionally",[8834,16582,16583,16588],{},[8848,16584,16585],{},[325,16586,16587],{},"whenHas($key)",[8848,16589,16590],{},"Include if key exists in source",[8834,16592,16593,16598],{},[8848,16594,16595],{},[325,16596,16597],{},"whenNotNull($value)",[8848,16599,16600],{},"Include if value is not null",[8834,16602,16603,16608],{},[8848,16604,16605],{},[325,16606,16607],{},"whenLoaded($relation)",[8848,16609,16610],{},"Include if relationship is loaded",[8834,16612,16613,16618],{},[8848,16614,16615],{},[325,16616,16617],{},"whenCounted($relation)",[8848,16619,16620],{},"Include relationship count if available",[8834,16622,16623,16628],{},[8848,16624,16625],{},[325,16626,16627],{},"whenPivotLoaded($table, $key)",[8848,16629,16630],{},"Include pivot table data",[293,16632,16633],{},[308,16634,16635],{},"ModelResource Helpers:",[5285,16637,16638,16646],{},[8831,16639,16640],{},[8834,16641,16642,16644],{},[8837,16643,10849],{},[8837,16645,8999],{},[8843,16647,16648,16658,16668,16678,16688,16698],{},[8834,16649,16650,16655],{},[8848,16651,16652],{},[325,16653,16654],{},"attribute($key, $default)",[8848,16656,16657],{},"Get model attribute with default",[8834,16659,16660,16665],{},[8848,16661,16662],{},[325,16663,16664],{},"dateAttribute($key)",[8848,16666,16667],{},"Format date as ISO 8601",[8834,16669,16670,16675],{},[8848,16671,16672],{},[325,16673,16674],{},"whenDateNotNull($key)",[8848,16676,16677],{},"Include date only if not null",[8834,16679,16680,16685],{},[8848,16681,16682],{},[325,16683,16684],{},"relationshipResource($relation, $class)",[8848,16686,16687],{},"Transform single relationship",[8834,16689,16690,16695],{},[8848,16691,16692],{},[325,16693,16694],{},"relationshipCollection($relation, $class)",[8848,16696,16697],{},"Transform collection relationship",[8834,16699,16700,16705],{},[8848,16701,16702],{},[325,16703,16704],{},"isRelationLoaded($relation)",[8848,16706,16707],{},"Check if relationship is loaded",[347,16709,9391],{"id":16710},"quick-usage-6",[428,16712,16714],{"className":5139,"code":16713,"language":1135,"meta":320,"style":320},"use Glueful\\Http\\Resources\\JsonResource;\nuse Glueful\\Http\\Resources\\ModelResource;\n\n// Basic resource\nclass UserResource extends JsonResource\n{\n    public function toArray(): array\n    {\n        return [\n            'id' => $this->resource['uuid'],\n            'name' => $this->resource['name'],\n            'email' => $this->when(\n                $this->isAdmin(),\n                $this->resource['email']\n            ),\n        ];\n    }\n}\n\n// Model resource with relationships\nclass PostResource extends ModelResource\n{\n    public function toArray(): array\n    {\n        return [\n            'id' => $this->attribute('uuid'),\n            'title' => $this->attribute('title'),\n            'created_at' => $this->dateAttribute('created_at'),\n            'author' => $this->relationshipResource('author', UserResource::class),\n            'comments_count' => $this->whenCounted('comments'),\n        ];\n    }\n}\n\n// Controller usage\npublic function index(): Response\n{\n    $posts = Post::with('author')->withCount('comments')->paginate(25);\n\n    return PostResource::collection($posts['data'])\n        ->withPaginationFrom($posts)\n        ->withLinks('/api/posts')\n        ->toResponse();\n}\n",[325,16715,16716,16738,16758,16762,16767,16779,16783,16798,16802,16808,16835,16861,16880,16892,16910,16915,16919,16923,16927,16931,16936,16948,16952,16966,16970,16976,17003,17029,17056,17092,17121,17125,17129,17133,17137,17142,17156,17160,17214,17218,17243,17257,17276,17286],{"__ignoreMap":320},[436,16717,16718,16720,16722,16724,16727,16729,16732,16734,16736],{"class":438,"line":439},[436,16719,6516],{"class":5167},[436,16721,6520],{"class":6519},[436,16723,6524],{"class":6523},[436,16725,16726],{"class":6519},"Http",[436,16728,6524],{"class":6523},[436,16730,16731],{"class":6519},"Resources",[436,16733,6524],{"class":6523},[436,16735,16491],{"class":6532},[436,16737,5816],{"class":5163},[436,16739,16740,16742,16744,16746,16748,16750,16752,16754,16756],{"class":438,"line":1132},[436,16741,6516],{"class":5167},[436,16743,6520],{"class":6519},[436,16745,6524],{"class":6523},[436,16747,16726],{"class":6519},[436,16749,6524],{"class":6523},[436,16751,16731],{"class":6519},[436,16753,6524],{"class":6523},[436,16755,16501],{"class":6532},[436,16757,5816],{"class":5163},[436,16759,16760],{"class":438,"line":1158},[436,16761,5212],{"emptyLinePlaceholder":5211},[436,16763,16764],{"class":438,"line":5196},[436,16765,16766],{"class":1168},"// Basic resource\n",[436,16768,16769,16771,16774,16776],{"class":438,"line":5202},[436,16770,6059],{"class":5155},[436,16772,16773],{"class":9486}," UserResource",[436,16775,9490],{"class":5152},[436,16777,16778],{"class":9493}," JsonResource\n",[436,16780,16781],{"class":438,"line":5208},[436,16782,5193],{"class":5163},[436,16784,16785,16787,16789,16792,16794,16796],{"class":438,"line":5215},[436,16786,11170],{"class":5152},[436,16788,5156],{"class":5155},[436,16790,16791],{"class":5159}," toArray",[436,16793,7677],{"class":5163},[436,16795,5243],{"class":1144},[436,16797,11225],{"class":5167},[436,16799,16800],{"class":438,"line":5221},[436,16801,11187],{"class":5163},[436,16803,16804,16806],{"class":438,"line":5249},[436,16805,11192],{"class":5788},[436,16807,6857],{"class":5163},[436,16809,16810,16812,16814,16816,16818,16820,16822,16825,16827,16829,16831,16833],{"class":438,"line":5254},[436,16811,10331],{"class":5281},[436,16813,1822],{"class":446},[436,16815,5282],{"class":5281},[436,16817,6000],{"class":1144},[436,16819,5770],{"class":5769},[436,16821,5269],{"class":1144},[436,16823,16824],{"class":1151},"resource",[436,16826,8042],{"class":5163},[436,16828,5282],{"class":5281},[436,16830,1818],{"class":446},[436,16832,5282],{"class":5281},[436,16834,9553],{"class":5163},[436,16836,16837,16839,16841,16843,16845,16847,16849,16851,16853,16855,16857,16859],{"class":438,"line":5298},[436,16838,10331],{"class":5281},[436,16840,9522],{"class":446},[436,16842,5282],{"class":5281},[436,16844,6000],{"class":1144},[436,16846,5770],{"class":5769},[436,16848,5269],{"class":1144},[436,16850,16824],{"class":1151},[436,16852,8042],{"class":5163},[436,16854,5282],{"class":5281},[436,16856,9522],{"class":446},[436,16858,5282],{"class":5281},[436,16860,9553],{"class":5163},[436,16862,16863,16865,16867,16869,16871,16873,16875,16878],{"class":438,"line":5324},[436,16864,10331],{"class":5281},[436,16866,2688],{"class":446},[436,16868,5282],{"class":5281},[436,16870,6000],{"class":1144},[436,16872,5770],{"class":5769},[436,16874,5269],{"class":1144},[436,16876,16877],{"class":5159},"when",[436,16879,6925],{"class":5163},[436,16881,16882,16885,16887,16890],{"class":438,"line":5329},[436,16883,16884],{"class":5769},"                $this",[436,16886,5269],{"class":1144},[436,16888,16889],{"class":5159},"isAdmin",[436,16891,15707],{"class":5163},[436,16893,16894,16896,16898,16900,16902,16904,16906,16908],{"class":438,"line":6717},[436,16895,16884],{"class":5769},[436,16897,5269],{"class":1144},[436,16899,16824],{"class":1151},[436,16901,8042],{"class":5163},[436,16903,5282],{"class":5281},[436,16905,2688],{"class":446},[436,16907,5282],{"class":5281},[436,16909,11896],{"class":5163},[436,16911,16912],{"class":438,"line":6742},[436,16913,16914],{"class":5163},"            ),\n",[436,16916,16917],{"class":438,"line":6767},[436,16918,15761],{"class":5163},[436,16920,16921],{"class":438,"line":6772},[436,16922,11205],{"class":5163},[436,16924,16925],{"class":438,"line":6778},[436,16926,5205],{"class":5163},[436,16928,16929],{"class":438,"line":6810},[436,16930,5212],{"emptyLinePlaceholder":5211},[436,16932,16933],{"class":438,"line":9754},[436,16934,16935],{"class":1168},"// Model resource with relationships\n",[436,16937,16938,16940,16943,16945],{"class":438,"line":9801},[436,16939,6059],{"class":5155},[436,16941,16942],{"class":9486}," PostResource",[436,16944,9490],{"class":5152},[436,16946,16947],{"class":9493}," ModelResource\n",[436,16949,16950],{"class":438,"line":9806},[436,16951,5193],{"class":5163},[436,16953,16954,16956,16958,16960,16962,16964],{"class":438,"line":9812},[436,16955,11170],{"class":5152},[436,16957,5156],{"class":5155},[436,16959,16791],{"class":5159},[436,16961,7677],{"class":5163},[436,16963,5243],{"class":1144},[436,16965,11225],{"class":5167},[436,16967,16968],{"class":438,"line":9825},[436,16969,11187],{"class":5163},[436,16971,16972,16974],{"class":438,"line":9830},[436,16973,11192],{"class":5788},[436,16975,6857],{"class":5163},[436,16977,16978,16980,16982,16984,16986,16988,16990,16993,16995,16997,16999,17001],{"class":438,"line":9841},[436,16979,10331],{"class":5281},[436,16981,1822],{"class":446},[436,16983,5282],{"class":5281},[436,16985,6000],{"class":1144},[436,16987,5770],{"class":5769},[436,16989,5269],{"class":1144},[436,16991,16992],{"class":5159},"attribute",[436,16994,5164],{"class":5163},[436,16996,5282],{"class":5281},[436,16998,1818],{"class":446},[436,17000,5282],{"class":5281},[436,17002,10248],{"class":5163},[436,17004,17005,17007,17009,17011,17013,17015,17017,17019,17021,17023,17025,17027],{"class":438,"line":9846},[436,17006,10331],{"class":5281},[436,17008,2710],{"class":446},[436,17010,5282],{"class":5281},[436,17012,6000],{"class":1144},[436,17014,5770],{"class":5769},[436,17016,5269],{"class":1144},[436,17018,16992],{"class":5159},[436,17020,5164],{"class":5163},[436,17022,5282],{"class":5281},[436,17024,2710],{"class":446},[436,17026,5282],{"class":5281},[436,17028,10248],{"class":5163},[436,17030,17031,17033,17035,17037,17039,17041,17043,17046,17048,17050,17052,17054],{"class":438,"line":9887},[436,17032,10331],{"class":5281},[436,17034,9625],{"class":446},[436,17036,5282],{"class":5281},[436,17038,6000],{"class":1144},[436,17040,5770],{"class":5769},[436,17042,5269],{"class":1144},[436,17044,17045],{"class":5159},"dateAttribute",[436,17047,5164],{"class":5163},[436,17049,5282],{"class":5281},[436,17051,9625],{"class":446},[436,17053,5282],{"class":5281},[436,17055,10248],{"class":5163},[436,17057,17058,17060,17063,17065,17067,17069,17071,17074,17076,17078,17080,17082,17084,17086,17088,17090],{"class":438,"line":9892},[436,17059,10331],{"class":5281},[436,17061,17062],{"class":446},"author",[436,17064,5282],{"class":5281},[436,17066,6000],{"class":1144},[436,17068,5770],{"class":5769},[436,17070,5269],{"class":1144},[436,17072,17073],{"class":5159},"relationshipResource",[436,17075,5164],{"class":5163},[436,17077,5282],{"class":5281},[436,17079,17062],{"class":446},[436,17081,5282],{"class":5281},[436,17083,5177],{"class":5163},[436,17085,16773],{"class":5233},[436,17087,6056],{"class":1144},[436,17089,6059],{"class":5167},[436,17091,10248],{"class":5163},[436,17093,17094,17096,17099,17101,17103,17105,17107,17110,17112,17114,17117,17119],{"class":438,"line":9897},[436,17095,10331],{"class":5281},[436,17097,17098],{"class":446},"comments_count",[436,17100,5282],{"class":5281},[436,17102,6000],{"class":1144},[436,17104,5770],{"class":5769},[436,17106,5269],{"class":1144},[436,17108,17109],{"class":5159},"whenCounted",[436,17111,5164],{"class":5163},[436,17113,5282],{"class":5281},[436,17115,17116],{"class":446},"comments",[436,17118,5282],{"class":5281},[436,17120,10248],{"class":5163},[436,17122,17123],{"class":438,"line":9903},[436,17124,15761],{"class":5163},[436,17126,17127],{"class":438,"line":9933},[436,17128,11205],{"class":5163},[436,17130,17131],{"class":438,"line":9963},[436,17132,5205],{"class":5163},[436,17134,17135],{"class":438,"line":9979},[436,17136,5212],{"emptyLinePlaceholder":5211},[436,17138,17139],{"class":438,"line":9984},[436,17140,17141],{"class":1168},"// Controller usage\n",[436,17143,17144,17146,17148,17150,17152,17154],{"class":438,"line":9989},[436,17145,4794],{"class":5152},[436,17147,5156],{"class":5155},[436,17149,5228],{"class":5159},[436,17151,7677],{"class":5163},[436,17153,5243],{"class":1144},[436,17155,5246],{"class":5233},[436,17157,17158],{"class":438,"line":9995},[436,17159,5193],{"class":5163},[436,17161,17162,17164,17167,17169,17172,17174,17177,17179,17181,17183,17185,17187,17189,17192,17194,17196,17198,17200,17202,17204,17207,17209,17212],{"class":438,"line":10020},[436,17163,5257],{"class":5163},[436,17165,17166],{"class":1151},"posts ",[436,17168,3168],{"class":1144},[436,17170,17171],{"class":5233}," Post",[436,17173,6056],{"class":1144},[436,17175,17176],{"class":5159},"with",[436,17178,5164],{"class":5163},[436,17180,5282],{"class":5281},[436,17182,17062],{"class":446},[436,17184,5282],{"class":5281},[436,17186,4887],{"class":5163},[436,17188,5269],{"class":1144},[436,17190,17191],{"class":5159},"withCount",[436,17193,5164],{"class":5163},[436,17195,5282],{"class":5281},[436,17197,17116],{"class":446},[436,17199,5282],{"class":5281},[436,17201,4887],{"class":5163},[436,17203,5269],{"class":1144},[436,17205,17206],{"class":5159},"paginate",[436,17208,5164],{"class":5163},[436,17210,17211],{"class":7256},"25",[436,17213,5295],{"class":5163},[436,17215,17216],{"class":438,"line":10051},[436,17217,5212],{"emptyLinePlaceholder":5211},[436,17219,17220,17222,17224,17226,17229,17231,17233,17235,17237,17239,17241],{"class":438,"line":10080},[436,17221,5808],{"class":5788},[436,17223,16942],{"class":5233},[436,17225,6056],{"class":1144},[436,17227,17228],{"class":5159},"collection",[436,17230,5778],{"class":5163},[436,17232,15942],{"class":1151},[436,17234,8042],{"class":5163},[436,17236,5282],{"class":5281},[436,17238,11415],{"class":446},[436,17240,5282],{"class":5281},[436,17242,12784],{"class":5163},[436,17244,17245,17248,17251,17253,17255],{"class":438,"line":10096},[436,17246,17247],{"class":1144},"        ->",[436,17249,17250],{"class":5159},"withPaginationFrom",[436,17252,5778],{"class":5163},[436,17254,15942],{"class":1151},[436,17256,5188],{"class":5163},[436,17258,17260,17262,17265,17267,17269,17272,17274],{"class":438,"line":17259},42,[436,17261,17247],{"class":1144},[436,17263,17264],{"class":5159},"withLinks",[436,17266,5164],{"class":5163},[436,17268,5282],{"class":5281},[436,17270,17271],{"class":446},"/api/posts",[436,17273,5282],{"class":5281},[436,17275,5188],{"class":5163},[436,17277,17279,17281,17284],{"class":438,"line":17278},43,[436,17280,17247],{"class":1144},[436,17282,17283],{"class":5159},"toResponse",[436,17285,5321],{"class":5163},[436,17287,17289],{"class":438,"line":17288},44,[436,17290,5205],{"class":5163},[347,17292,16148],{"id":17293},"console-commands-1",[428,17295,17297],{"className":430,"code":17296,"language":432,"meta":320,"style":320},"# Generate a basic resource\nphp glueful scaffold:resource UserResource\n\n# Generate a model resource\nphp glueful scaffold:resource UserResource --model\n\n# Generate a collection\nphp glueful scaffold:resource UserCollection --collection\n\n# Overwrite existing\nphp glueful scaffold:resource UserResource --force\n",[325,17298,17299,17304,17316,17320,17325,17338,17342,17347,17361,17365,17370],{"__ignoreMap":320},[436,17300,17301],{"class":438,"line":439},[436,17302,17303],{"class":1168},"# Generate a basic resource\n",[436,17305,17306,17308,17310,17313],{"class":438,"line":1132},[436,17307,1135],{"class":442},[436,17309,1138],{"class":446},[436,17311,17312],{"class":446}," scaffold:resource",[436,17314,17315],{"class":446}," UserResource\n",[436,17317,17318],{"class":438,"line":1158},[436,17319,5212],{"emptyLinePlaceholder":5211},[436,17321,17322],{"class":438,"line":5196},[436,17323,17324],{"class":1168},"# Generate a model resource\n",[436,17326,17327,17329,17331,17333,17335],{"class":438,"line":5202},[436,17328,1135],{"class":442},[436,17330,1138],{"class":446},[436,17332,17312],{"class":446},[436,17334,16773],{"class":446},[436,17336,17337],{"class":5565}," --model\n",[436,17339,17340],{"class":438,"line":5208},[436,17341,5212],{"emptyLinePlaceholder":5211},[436,17343,17344],{"class":438,"line":5215},[436,17345,17346],{"class":1168},"# Generate a collection\n",[436,17348,17349,17351,17353,17355,17358],{"class":438,"line":5221},[436,17350,1135],{"class":442},[436,17352,1138],{"class":446},[436,17354,17312],{"class":446},[436,17356,17357],{"class":446}," UserCollection",[436,17359,17360],{"class":5565}," --collection\n",[436,17362,17363],{"class":438,"line":5249},[436,17364,5212],{"emptyLinePlaceholder":5211},[436,17366,17367],{"class":438,"line":5254},[436,17368,17369],{"class":1168},"# Overwrite existing\n",[436,17371,17372,17374,17376,17378,17380],{"class":438,"line":5298},[436,17373,1135],{"class":442},[436,17375,1138],{"class":446},[436,17377,17312],{"class":446},[436,17379,16773],{"class":446},[436,17381,17382],{"class":5565}," --force\n",[347,17384,413],{"id":17385},"migration-notes-29",[415,17387,17388,17391,17394],{},[418,17389,17390],{},"No breaking changes. API Resources are opt-in and additive.",[418,17392,17393],{},"Existing controllers and responses continue to work unchanged.",[418,17395,17396],{},"Resources provide a transformation layer; use them when you need consistent JSON structures.",[452,17398],{},[301,17400,17402],{"id":17401},"v1110-alnilam-minor","v1.11.0 - Alnilam (Minor)",[293,17404,17405],{},[308,17406,16347],{},[312,17408,17409],{"color":314,"icon":1183,"variant":316},[318,17410,17411],{"v-slot:description":320},[293,17412,17413],{},"Feature release introducing the ORM/Active Record system, completing the data layer of Priority 1 features.",[347,17415,350],{"id":17416},"key-highlights-40",[352,17418,17419,17424],{},[293,17420,17421],{},[308,17422,17423],{},"Active Record ORM",[415,17425,17426,17429,17432,17435],{},[418,17427,17428],{},"Complete Active Record pattern implementation built on QueryBuilder",[418,17430,17431],{},"Model base class with CRUD operations and mass assignment protection",[418,17433,17434],{},"Builder class with eager loading and global scope support",[418,17436,17437],{},"Rich Collection class for model results",[352,17439,17440,17445],{},[293,17441,17442],{},[308,17443,17444],{},"Relationships",[415,17446,17447,17450,17453,17456],{},[418,17448,17449],{},"HasOne, HasMany, BelongsTo for basic relationships",[418,17451,17452],{},"BelongsToMany with pivot table support",[418,17454,17455],{},"HasOneThrough and HasManyThrough for indirect relationships",[418,17457,17458],{},"Eager loading to prevent N+1 query problems",[352,17460,17461,17466],{},[293,17462,17463],{},[308,17464,17465],{},"Model Features",[415,17467,17468,17471,17474,17477],{},[418,17469,17470],{},"Attribute casting with custom cast classes",[418,17472,17473],{},"SoftDeletes trait for recoverable deletion",[418,17475,17476],{},"HasTimestamps for automatic date management",[418,17478,17479],{},"Model lifecycle events integrated with framework events",[347,17481,17483],{"id":17482},"orm-components","ORM Components",[293,17485,17486],{},[308,17487,8987],{},[5285,17489,17490,17498],{},[8831,17491,17492],{},[8834,17493,17494,17496],{},[8837,17495,8996],{},[8837,17497,8999],{},[8843,17499,17500,17509,17519,17529],{},[8834,17501,17502,17506],{},[8848,17503,17504],{},[325,17505,2121],{},[8848,17507,17508],{},"Base class for all models with CRUD, attributes, and relations",[8834,17510,17511,17516],{},[8848,17512,17513],{},[325,17514,17515],{},"Builder",[8848,17517,17518],{},"Query builder wrapper with model-aware functionality",[8834,17520,17521,17526],{},[8848,17522,17523],{},[325,17524,17525],{},"Collection",[8848,17527,17528],{},"Rich collection class for model results",[8834,17530,17531,17536],{},[8848,17532,17533],{},[325,17534,17535],{},"Pivot",[8848,17537,17538],{},"Pivot model for many-to-many relationships",[293,17540,17541],{},[308,17542,17543],{},"Relationships:",[5285,17545,17546,17556],{},[8831,17547,17548],{},[8834,17549,17550,17553],{},[8837,17551,17552],{},"Relationship",[8837,17554,17555],{},"Use Case",[8843,17557,17558,17568,17578,17588,17598,17608],{},[8834,17559,17560,17565],{},[8848,17561,17562],{},[325,17563,17564],{},"HasOne",[8848,17566,17567],{},"One-to-one (owning side)",[8834,17569,17570,17575],{},[8848,17571,17572],{},[325,17573,17574],{},"HasMany",[8848,17576,17577],{},"One-to-many",[8834,17579,17580,17585],{},[8848,17581,17582],{},[325,17583,17584],{},"BelongsTo",[8848,17586,17587],{},"Inverse of HasOne/HasMany",[8834,17589,17590,17595],{},[8848,17591,17592],{},[325,17593,17594],{},"BelongsToMany",[8848,17596,17597],{},"Many-to-many with pivot table",[8834,17599,17600,17605],{},[8848,17601,17602],{},[325,17603,17604],{},"HasOneThrough",[8848,17606,17607],{},"One-to-one through intermediate model",[8834,17609,17610,17615],{},[8848,17611,17612],{},[325,17613,17614],{},"HasManyThrough",[8848,17616,17617],{},"One-to-many through intermediate model",[293,17619,17620],{},[308,17621,17622],{},"Traits:",[5285,17624,17625,17634],{},[8831,17626,17627],{},[8834,17628,17629,17632],{},[8837,17630,17631],{},"Trait",[8837,17633,8999],{},[8843,17635,17636,17646,17656,17671,17681,17691],{},[8834,17637,17638,17643],{},[8848,17639,17640],{},[325,17641,17642],{},"HasAttributes",[8848,17644,17645],{},"Attribute get/set, casting, dirty tracking",[8834,17647,17648,17653],{},[8848,17649,17650],{},[325,17651,17652],{},"HasRelationships",[8848,17654,17655],{},"Relationship definition and eager loading",[8834,17657,17658,17663],{},[8848,17659,17660],{},[325,17661,17662],{},"HasTimestamps",[8848,17664,17665,17666,380,17668],{},"Automatic ",[325,17667,9625],{},[325,17669,17670],{},"updated_at",[8834,17672,17673,17678],{},[8848,17674,17675],{},[325,17676,17677],{},"HasEvents",[8848,17679,17680],{},"Model lifecycle event integration",[8834,17682,17683,17688],{},[8848,17684,17685],{},[325,17686,17687],{},"HasGlobalScopes",[8848,17689,17690],{},"Global query scope management",[8834,17692,17693,17698],{},[8848,17694,17695],{},[325,17696,17697],{},"SoftDeletes",[8848,17699,17700,17701,17704],{},"Soft delete with ",[325,17702,17703],{},"deleted_at"," column",[293,17706,17707],{},[308,17708,17709],{},"Custom Casts:",[5285,17711,17712,17721],{},[8831,17713,17714],{},[8834,17715,17716,17719],{},[8837,17717,17718],{},"Cast",[8837,17720,8999],{},[8843,17722,17723,17733,17743,17753,17763,17773,17783],{},[8834,17724,17725,17730],{},[8848,17726,17727],{},[325,17728,17729],{},"AsJson",[8848,17731,17732],{},"JSON encode/decode",[8834,17734,17735,17740],{},[8848,17736,17737],{},[325,17738,17739],{},"AsArrayObject",[8848,17741,17742],{},"JSON to ArrayObject",[8834,17744,17745,17750],{},[8848,17746,17747],{},[325,17748,17749],{},"AsCollection",[8848,17751,17752],{},"JSON to Collection",[8834,17754,17755,17760],{},[8848,17756,17757],{},[325,17758,17759],{},"AsDateTime",[8848,17761,17762],{},"String to DateTimeImmutable",[8834,17764,17765,17770],{},[8848,17766,17767],{},[325,17768,17769],{},"AsEncryptedString",[8848,17771,17772],{},"Transparent encryption",[8834,17774,17775,17780],{},[8848,17776,17777],{},[325,17778,17779],{},"AsEnum",[8848,17781,17782],{},"Backed enum casting",[8834,17784,17785,17789],{},[8848,17786,17787],{},[325,17788,13491],{},[8848,17790,17791],{},"Custom getter/setter accessors",[347,17793,9391],{"id":17794},"quick-usage-7",[428,17796,17798],{"className":5139,"code":17797,"language":1135,"meta":320,"style":320},"use Glueful\\Database\\ORM\\Model;\nuse Glueful\\Database\\ORM\\Concerns\\{HasTimestamps, SoftDeletes};\n\nclass User extends Model\n{\n    use HasTimestamps, SoftDeletes;\n\n    protected string $table = 'users';\n    protected array $fillable = ['name', 'email'];\n    protected array $casts = [\n        'settings' => 'array',\n        'email_verified_at' => 'datetime',\n    ];\n\n    public function posts(): HasMany\n    {\n        return $this->hasMany(Post::class);\n    }\n}\n\n// CRUD operations\n$user = User::find(1);\n$user = User::create(['name' => 'John', 'email' => 'john@example.com']);\n$user->update(['name' => 'Jane']);\n$user->delete(); // Soft delete\n\n// Eager loading\n$users = User::with('posts')->get();\n\n// Query scopes\n$active = User::where('status', 'active')->get();\n",[325,17799,17800,17821,17852,17856,17866,17870,17883,17887,17907,17938,17953,17972,17992,17996,18000,18016,18020,18042,18046,18050,18054,18059,18080,18129,18158,18174,18178,18183,18213,18217,18222],{"__ignoreMap":320},[436,17801,17802,17804,17806,17808,17810,17812,17815,17817,17819],{"class":438,"line":439},[436,17803,6516],{"class":5167},[436,17805,6520],{"class":6519},[436,17807,6524],{"class":6523},[436,17809,53],{"class":6519},[436,17811,6524],{"class":6523},[436,17813,17814],{"class":6519},"ORM",[436,17816,6524],{"class":6523},[436,17818,2121],{"class":6532},[436,17820,5816],{"class":5163},[436,17822,17823,17825,17827,17829,17831,17833,17835,17837,17839,17841,17843,17845,17847,17850],{"class":438,"line":1132},[436,17824,6516],{"class":5167},[436,17826,6520],{"class":6519},[436,17828,6524],{"class":6523},[436,17830,53],{"class":6519},[436,17832,6524],{"class":6523},[436,17834,17814],{"class":6519},[436,17836,6524],{"class":6523},[436,17838,9463],{"class":6519},[436,17840,6524],{"class":6523},[436,17842,7230],{"class":5163},[436,17844,17662],{"class":6532},[436,17846,5177],{"class":5163},[436,17848,17849],{"class":6532}," SoftDeletes",[436,17851,12439],{"class":5163},[436,17853,17854],{"class":438,"line":1158},[436,17855,5212],{"emptyLinePlaceholder":5211},[436,17857,17858,17860,17862,17864],{"class":438,"line":5196},[436,17859,6059],{"class":5155},[436,17861,9817],{"class":9486},[436,17863,9490],{"class":5152},[436,17865,9822],{"class":9493},[436,17867,17868],{"class":438,"line":5202},[436,17869,5193],{"class":5163},[436,17871,17872,17874,17877,17879,17881],{"class":438,"line":5208},[436,17873,9833],{"class":5167},[436,17875,17876],{"class":6532}," HasTimestamps",[436,17878,5177],{"class":5163},[436,17880,17849],{"class":6532},[436,17882,5816],{"class":5163},[436,17884,17885],{"class":438,"line":5215},[436,17886,5212],{"emptyLinePlaceholder":5211},[436,17888,17889,17891,17893,17895,17897,17899,17901,17903,17905],{"class":438,"line":5221},[436,17890,9503],{"class":5152},[436,17892,15639],{"class":5167},[436,17894,5171],{"class":5163},[436,17896,5260],{"class":1151},[436,17898,3168],{"class":1144},[436,17900,6064],{"class":5281},[436,17902,9787],{"class":446},[436,17904,5282],{"class":5281},[436,17906,5816],{"class":5163},[436,17908,17909,17911,17913,17915,17918,17920,17922,17924,17926,17928,17930,17932,17934,17936],{"class":438,"line":5249},[436,17910,9503],{"class":5152},[436,17912,5180],{"class":5167},[436,17914,5171],{"class":5163},[436,17916,17917],{"class":1151},"fillable ",[436,17919,3168],{"class":1144},[436,17921,6050],{"class":5163},[436,17923,5282],{"class":5281},[436,17925,9522],{"class":446},[436,17927,5282],{"class":5281},[436,17929,5177],{"class":5163},[436,17931,6064],{"class":5281},[436,17933,2688],{"class":446},[436,17935,5282],{"class":5281},[436,17937,6968],{"class":5163},[436,17939,17940,17942,17944,17946,17949,17951],{"class":438,"line":5254},[436,17941,9503],{"class":5152},[436,17943,5180],{"class":5167},[436,17945,5171],{"class":5163},[436,17947,17948],{"class":1151},"casts ",[436,17950,3168],{"class":1144},[436,17952,6857],{"class":5163},[436,17954,17955,17957,17960,17962,17964,17966,17968,17970],{"class":438,"line":5298},[436,17956,9519],{"class":5281},[436,17958,17959],{"class":446},"settings",[436,17961,5282],{"class":5281},[436,17963,6000],{"class":1144},[436,17965,6064],{"class":5281},[436,17967,5168],{"class":446},[436,17969,5282],{"class":5281},[436,17971,6907],{"class":5163},[436,17973,17974,17976,17979,17981,17983,17985,17988,17990],{"class":438,"line":5324},[436,17975,9519],{"class":5281},[436,17977,17978],{"class":446},"email_verified_at",[436,17980,5282],{"class":5281},[436,17982,6000],{"class":1144},[436,17984,6064],{"class":5281},[436,17986,17987],{"class":446},"datetime",[436,17989,5282],{"class":5281},[436,17991,6907],{"class":5163},[436,17993,17994],{"class":438,"line":5329},[436,17995,9676],{"class":5163},[436,17997,17998],{"class":438,"line":6717},[436,17999,5212],{"emptyLinePlaceholder":5211},[436,18001,18002,18004,18006,18009,18011,18013],{"class":438,"line":6742},[436,18003,11170],{"class":5152},[436,18005,5156],{"class":5155},[436,18007,18008],{"class":5159}," posts",[436,18010,7677],{"class":5163},[436,18012,5243],{"class":1144},[436,18014,18015],{"class":5233}," HasMany\n",[436,18017,18018],{"class":438,"line":6767},[436,18019,11187],{"class":5163},[436,18021,18022,18024,18026,18028,18031,18033,18036,18038,18040],{"class":438,"line":6772},[436,18023,11192],{"class":5788},[436,18025,5770],{"class":5769},[436,18027,5269],{"class":1144},[436,18029,18030],{"class":5159},"hasMany",[436,18032,5164],{"class":5163},[436,18034,18035],{"class":5233},"Post",[436,18037,6056],{"class":1144},[436,18039,6059],{"class":5167},[436,18041,5295],{"class":5163},[436,18043,18044],{"class":438,"line":6778},[436,18045,11205],{"class":5163},[436,18047,18048],{"class":438,"line":6810},[436,18049,5205],{"class":5163},[436,18051,18052],{"class":438,"line":9754},[436,18053,5212],{"emptyLinePlaceholder":5211},[436,18055,18056],{"class":438,"line":9801},[436,18057,18058],{"class":1168},"// CRUD operations\n",[436,18060,18061,18063,18065,18067,18069,18071,18074,18076,18078],{"class":438,"line":9806},[436,18062,5761],{"class":5163},[436,18064,15844],{"class":1151},[436,18066,3168],{"class":1144},[436,18068,9817],{"class":5233},[436,18070,6056],{"class":1144},[436,18072,18073],{"class":5159},"find",[436,18075,5164],{"class":5163},[436,18077,3191],{"class":7256},[436,18079,5295],{"class":5163},[436,18081,18082,18084,18086,18088,18090,18092,18094,18096,18098,18100,18102,18104,18106,18109,18111,18113,18115,18117,18119,18121,18123,18125,18127],{"class":438,"line":9812},[436,18083,5761],{"class":5163},[436,18085,15844],{"class":1151},[436,18087,3168],{"class":1144},[436,18089,9817],{"class":5233},[436,18091,6056],{"class":1144},[436,18093,15860],{"class":5159},[436,18095,5990],{"class":5163},[436,18097,5282],{"class":5281},[436,18099,9522],{"class":446},[436,18101,5282],{"class":5281},[436,18103,6000],{"class":1144},[436,18105,6064],{"class":5281},[436,18107,18108],{"class":446},"John",[436,18110,5282],{"class":5281},[436,18112,5177],{"class":5163},[436,18114,6064],{"class":5281},[436,18116,2688],{"class":446},[436,18118,5282],{"class":5281},[436,18120,6000],{"class":1144},[436,18122,6064],{"class":5281},[436,18124,11470],{"class":446},[436,18126,5282],{"class":5281},[436,18128,6072],{"class":5163},[436,18130,18131,18133,18135,18137,18139,18141,18143,18145,18147,18149,18151,18154,18156],{"class":438,"line":9825},[436,18132,5761],{"class":5163},[436,18134,11052],{"class":1151},[436,18136,5269],{"class":1144},[436,18138,4994],{"class":5159},[436,18140,5990],{"class":5163},[436,18142,5282],{"class":5281},[436,18144,9522],{"class":446},[436,18146,5282],{"class":5281},[436,18148,6000],{"class":1144},[436,18150,6064],{"class":5281},[436,18152,18153],{"class":446},"Jane",[436,18155,5282],{"class":5281},[436,18157,6072],{"class":5163},[436,18159,18160,18162,18164,18166,18168,18171],{"class":438,"line":9830},[436,18161,5761],{"class":5163},[436,18163,11052],{"class":1151},[436,18165,5269],{"class":1144},[436,18167,724],{"class":5159},[436,18169,18170],{"class":5163},"();",[436,18172,18173],{"class":1168}," // Soft delete\n",[436,18175,18176],{"class":438,"line":9841},[436,18177,5212],{"emptyLinePlaceholder":5211},[436,18179,18180],{"class":438,"line":9846},[436,18181,18182],{"class":1168},"// Eager loading\n",[436,18184,18185,18187,18189,18191,18193,18195,18197,18199,18201,18203,18205,18207,18209,18211],{"class":438,"line":9887},[436,18186,5761],{"class":5163},[436,18188,9759],{"class":1151},[436,18190,3168],{"class":1144},[436,18192,9817],{"class":5233},[436,18194,6056],{"class":1144},[436,18196,17176],{"class":5159},[436,18198,5164],{"class":5163},[436,18200,5282],{"class":5281},[436,18202,15942],{"class":446},[436,18204,5282],{"class":5281},[436,18206,4887],{"class":5163},[436,18208,5269],{"class":1144},[436,18210,715],{"class":5159},[436,18212,5321],{"class":5163},[436,18214,18215],{"class":438,"line":9892},[436,18216,5212],{"emptyLinePlaceholder":5211},[436,18218,18219],{"class":438,"line":9897},[436,18220,18221],{"class":1168},"// Query scopes\n",[436,18223,18224,18226,18229,18231,18233,18235,18238,18240,18242,18244,18246,18248,18250,18252,18254,18256,18258,18260],{"class":438,"line":9903},[436,18225,5761],{"class":5163},[436,18227,18228],{"class":1151},"active ",[436,18230,3168],{"class":1144},[436,18232,9817],{"class":5233},[436,18234,6056],{"class":1144},[436,18236,18237],{"class":5159},"where",[436,18239,5164],{"class":5163},[436,18241,5282],{"class":5281},[436,18243,9588],{"class":446},[436,18245,5282],{"class":5281},[436,18247,5177],{"class":5163},[436,18249,6064],{"class":5281},[436,18251,15752],{"class":446},[436,18253,5282],{"class":5281},[436,18255,4887],{"class":5163},[436,18257,5269],{"class":1144},[436,18259,715],{"class":5159},[436,18261,5321],{"class":5163},[347,18263,16148],{"id":18264},"console-commands-2",[428,18266,18268],{"className":430,"code":18267,"language":432,"meta":320,"style":320},"# Generate a new model\nphp glueful scaffold:model User\n\n# With migration\nphp glueful scaffold:model Post --migration\n\n# With soft deletes and timestamps\nphp glueful scaffold:model Comment --soft-deletes --timestamps\n\n# With fillable attributes\nphp glueful scaffold:model Product --fillable=name,price,description\n",[325,18269,18270,18275,18286,18290,18295,18308,18312,18317,18334,18338,18343],{"__ignoreMap":320},[436,18271,18272],{"class":438,"line":439},[436,18273,18274],{"class":1168},"# Generate a new model\n",[436,18276,18277,18279,18281,18283],{"class":438,"line":1132},[436,18278,1135],{"class":442},[436,18280,1138],{"class":446},[436,18282,14989],{"class":446},[436,18284,18285],{"class":446}," User\n",[436,18287,18288],{"class":438,"line":1158},[436,18289,5212],{"emptyLinePlaceholder":5211},[436,18291,18292],{"class":438,"line":5196},[436,18293,18294],{"class":1168},"# With migration\n",[436,18296,18297,18299,18301,18303,18305],{"class":438,"line":5202},[436,18298,1135],{"class":442},[436,18300,1138],{"class":446},[436,18302,14989],{"class":446},[436,18304,17171],{"class":446},[436,18306,18307],{"class":5565}," --migration\n",[436,18309,18310],{"class":438,"line":5208},[436,18311,5212],{"emptyLinePlaceholder":5211},[436,18313,18314],{"class":438,"line":5215},[436,18315,18316],{"class":1168},"# With soft deletes and timestamps\n",[436,18318,18319,18321,18323,18325,18328,18331],{"class":438,"line":5221},[436,18320,1135],{"class":442},[436,18322,1138],{"class":446},[436,18324,14989],{"class":446},[436,18326,18327],{"class":446}," Comment",[436,18329,18330],{"class":5565}," --soft-deletes",[436,18332,18333],{"class":5565}," --timestamps\n",[436,18335,18336],{"class":438,"line":5249},[436,18337,5212],{"emptyLinePlaceholder":5211},[436,18339,18340],{"class":438,"line":5254},[436,18341,18342],{"class":1168},"# With fillable attributes\n",[436,18344,18345,18347,18349,18351,18354],{"class":438,"line":5298},[436,18346,1135],{"class":442},[436,18348,1138],{"class":446},[436,18350,14989],{"class":446},[436,18352,18353],{"class":446}," Product",[436,18355,18356],{"class":5565}," --fillable=name,price,description\n",[347,18358,413],{"id":18359},"migration-notes-30",[415,18361,18362,18365,18368],{},[418,18363,18364],{},"No breaking changes. The ORM is opt-in and additive.",[418,18366,18367],{},"Existing QueryBuilder code continues to work unchanged.",[418,18369,18370,18371,18374],{},"Models require ",[325,18372,18373],{},"Model::setContainer()"," which is called automatically during framework boot.",[452,18376],{},[301,18378,18380],{"id":18379},"v1100-elnath-minor","v1.10.0 - Elnath (Minor)",[293,18382,18383],{},[308,18384,16347],{},[312,18386,18387],{"color":314,"icon":1697,"variant":316},[318,18388,18389],{"v-slot:description":320},[293,18390,18391],{},"Feature release introducing centralized exception handling and declarative request validation, completing the foundation layer of Priority 1 features.",[347,18393,350],{"id":18394},"key-highlights-41",[352,18396,18397,18402],{},[293,18398,18399],{},[308,18400,18401],{},"Centralized Exception Handling",[415,18403,18404,18410,18413,18419],{},[418,18405,705,18406,18409],{},[325,18407,18408],{},"ExceptionHandlerInterface"," contract for customizable exception handling",[418,18411,18412],{},"Typed HTTP exceptions for Client (4xx), Server (5xx), and Domain errors",[418,18414,18415,18418],{},[325,18416,18417],{},"ExceptionMiddleware"," for automatic exception-to-response conversion",[418,18420,18421],{},"Environment-aware error responses (detailed in dev, safe in production)",[352,18423,18424,18429],{},[293,18425,18426],{},[308,18427,18428],{},"Declarative Request Validation",[415,18430,18431,18437,18443,18449],{},[418,18432,18433,18436],{},[325,18434,18435],{},"#[Validate]"," attribute for inline validation on controller methods",[418,18438,18439,18442],{},[325,18440,18441],{},"FormRequest"," base class with authorization and data preparation hooks",[418,18444,18445,18448],{},[325,18446,18447],{},"ValidatedRequest"," wrapper for type-safe validated data access",[418,18450,18451,18452],{},"Laravel-style string rule syntax via ",[325,18453,18454],{},"RuleParser",[347,18456,18458],{"id":18457},"exception-handler","Exception Handler",[293,18460,18461],{},"New typed exception classes provide semantic error handling:",[293,18463,18464],{},[308,18465,18466],{},"Client Exceptions (4xx):",[5285,18468,18469,18481],{},[8831,18470,18471],{},[8834,18472,18473,18476,18479],{},[8837,18474,18475],{},"Exception",[8837,18477,18478],{},"HTTP Code",[8837,18480,17555],{},[8843,18482,18483,18496,18509,18522,18534,18547,18560,18573],{},[8834,18484,18485,18490,18493],{},[8848,18486,18487],{},[325,18488,18489],{},"BadRequestException",[8848,18491,18492],{},"400",[8848,18494,18495],{},"Malformed request",[8834,18497,18498,18503,18506],{},[8848,18499,18500],{},[325,18501,18502],{},"UnauthorizedException",[8848,18504,18505],{},"401",[8848,18507,18508],{},"Missing/invalid credentials",[8834,18510,18511,18516,18519],{},[8848,18512,18513],{},[325,18514,18515],{},"ForbiddenException",[8848,18517,18518],{},"403",[8848,18520,18521],{},"Insufficient permissions",[8834,18523,18524,18528,18531],{},[8848,18525,18526],{},[325,18527,4426],{},[8848,18529,18530],{},"404",[8848,18532,18533],{},"Resource not found",[8834,18535,18536,18541,18544],{},[8848,18537,18538],{},[325,18539,18540],{},"MethodNotAllowedException",[8848,18542,18543],{},"405",[8848,18545,18546],{},"Wrong HTTP method",[8834,18548,18549,18554,18557],{},[8848,18550,18551],{},[325,18552,18553],{},"ConflictException",[8848,18555,18556],{},"409",[8848,18558,18559],{},"Resource conflict",[8834,18561,18562,18567,18570],{},[8848,18563,18564],{},[325,18565,18566],{},"UnprocessableEntityException",[8848,18568,18569],{},"422",[8848,18571,18572],{},"Validation failed",[8834,18574,18575,18580,18583],{},[8848,18576,18577],{},[325,18578,18579],{},"TooManyRequestsException",[8848,18581,18582],{},"429",[8848,18584,18585],{},"Rate limit exceeded",[293,18587,18588],{},[308,18589,18590],{},"Server Exceptions (5xx):",[5285,18592,18593,18603],{},[8831,18594,18595],{},[8834,18596,18597,18599,18601],{},[8837,18598,18475],{},[8837,18600,18478],{},[8837,18602,17555],{},[8843,18604,18605,18618,18631],{},[8834,18606,18607,18612,18615],{},[8848,18608,18609],{},[325,18610,18611],{},"InternalServerException",[8848,18613,18614],{},"500",[8848,18616,18617],{},"Unexpected server error",[8834,18619,18620,18625,18628],{},[8848,18621,18622],{},[325,18623,18624],{},"ServiceUnavailableException",[8848,18626,18627],{},"503",[8848,18629,18630],{},"Service temporarily down",[8834,18632,18633,18638,18641],{},[8848,18634,18635],{},[325,18636,18637],{},"GatewayTimeoutException",[8848,18639,18640],{},"504",[8848,18642,18643],{},"Upstream timeout",[293,18645,18646],{},[308,18647,18648],{},"Domain Exceptions:",[5285,18650,18651,18659],{},[8831,18652,18653],{},[8834,18654,18655,18657],{},[8837,18656,18475],{},[8837,18658,17555],{},[8843,18660,18661,18671,18681,18691],{},[8834,18662,18663,18668],{},[8848,18664,18665],{},[325,18666,18667],{},"ModelNotFoundException",[8848,18669,18670],{},"Entity not found in database",[8834,18672,18673,18678],{},[8848,18674,18675],{},[325,18676,18677],{},"AuthenticationException",[8848,18679,18680],{},"Authentication failure",[8834,18682,18683,18688],{},[8848,18684,18685],{},[325,18686,18687],{},"AuthorizationException",[8848,18689,18690],{},"Permission denied",[8834,18692,18693,18698],{},[8848,18694,18695],{},[325,18696,18697],{},"TokenExpiredException",[8848,18699,18700],{},"JWT/session expired",[347,18702,18704],{"id":18703},"request-validation","Request Validation",[293,18706,18707],{},[308,18708,18709],{},"New Validation Rules:",[415,18711,18712,18718,18730,18742,18748,18757],{},[418,18713,18714,18717],{},[325,18715,18716],{},"Confirmed"," - Password confirmation matching",[418,18719,18720,332,18723,332,18726,18729],{},[325,18721,18722],{},"Date",[325,18724,18725],{},"Before",[325,18727,18728],{},"After"," - Date validation and comparison",[418,18731,18732,332,18735,332,18738,18741],{},[325,18733,18734],{},"Url",[325,18736,18737],{},"Uuid",[325,18739,18740],{},"Json"," - Format validation",[418,18743,18744,18747],{},[325,18745,18746],{},"Exists"," - Database existence check",[418,18749,18750,332,18753,18756],{},[325,18751,18752],{},"Nullable",[325,18754,18755],{},"Sometimes"," - Conditional validation",[418,18758,18759,332,18762,332,18765,18768],{},[325,18760,18761],{},"File",[325,18763,18764],{},"Image",[325,18766,18767],{},"Dimensions"," - File upload validation",[347,18770,9391],{"id":18771},"quick-usage-8",[428,18773,18775],{"className":5139,"code":18774,"language":1135,"meta":320,"style":320},"// Throwing typed exceptions\nthrow new NotFoundException('User not found', ['id' => $userId]);\nthrow new TooManyRequestsException(retryAfter: 60);\n\n// Using #[Validate] attribute\n#[Validate(['email' => 'required|email', 'name' => 'required|max:255'])]\npublic function store(ValidatedRequest $request): Response\n{\n    $data = $request->validated();\n}\n\n// Using FormRequest class\n// Generate with: php bin/glueful make:request CreateUserRequest\npublic function store(CreateUserRequest $request): Response\n{\n    $data = $request->validated();\n}\n",[325,18776,18777,18782,18820,18840,18844,18849,18895,18918,18922,18942,18946,18950,18955,18960,18983,18987,19005],{"__ignoreMap":320},[436,18778,18779],{"class":438,"line":439},[436,18780,18781],{"class":1168},"// Throwing typed exceptions\n",[436,18783,18784,18787,18789,18792,18794,18796,18799,18801,18803,18805,18807,18809,18811,18813,18815,18818],{"class":438,"line":1132},[436,18785,18786],{"class":5788},"throw",[436,18788,6551],{"class":5167},[436,18790,18791],{"class":5233}," NotFoundException",[436,18793,5164],{"class":5163},[436,18795,5282],{"class":5281},[436,18797,18798],{"class":446},"User not found",[436,18800,5282],{"class":5281},[436,18802,5177],{"class":5163},[436,18804,6050],{"class":5163},[436,18806,5282],{"class":5281},[436,18808,1822],{"class":446},[436,18810,5282],{"class":5281},[436,18812,6000],{"class":1144},[436,18814,5171],{"class":5163},[436,18816,18817],{"class":1151},"userId",[436,18819,6072],{"class":5163},[436,18821,18822,18824,18826,18829,18831,18834,18836,18838],{"class":438,"line":1158},[436,18823,18786],{"class":5788},[436,18825,6551],{"class":5167},[436,18827,18828],{"class":5233}," TooManyRequestsException",[436,18830,5164],{"class":5163},[436,18832,18833],{"class":6659},"retryAfter",[436,18835,5243],{"class":5163},[436,18837,12236],{"class":7256},[436,18839,5295],{"class":5163},[436,18841,18842],{"class":438,"line":5196},[436,18843,5212],{"emptyLinePlaceholder":5211},[436,18845,18846],{"class":438,"line":5202},[436,18847,18848],{"class":1168},"// Using #[Validate] attribute\n",[436,18850,18851,18853,18856,18858,18860,18862,18864,18866,18868,18871,18873,18875,18877,18879,18881,18883,18885,18888,18890,18893],{"class":438,"line":5208},[436,18852,12221],{"class":1151},[436,18854,18855],{"class":6519},"Validate",[436,18857,5990],{"class":5163},[436,18859,5282],{"class":5281},[436,18861,2688],{"class":446},[436,18863,5282],{"class":5281},[436,18865,6000],{"class":1144},[436,18867,6064],{"class":5281},[436,18869,18870],{"class":446},"required|email",[436,18872,5282],{"class":5281},[436,18874,5177],{"class":5163},[436,18876,6064],{"class":5281},[436,18878,9522],{"class":446},[436,18880,5282],{"class":5281},[436,18882,6000],{"class":1144},[436,18884,6064],{"class":5281},[436,18886,18887],{"class":446},"required|max:255",[436,18889,5282],{"class":5281},[436,18891,18892],{"class":5163},"])",[436,18894,11896],{"class":1151},[436,18896,18897,18899,18901,18904,18906,18908,18910,18912,18914,18916],{"class":438,"line":5215},[436,18898,4794],{"class":5152},[436,18900,5156],{"class":5155},[436,18902,18903],{"class":5159}," store",[436,18905,5164],{"class":5163},[436,18907,18447],{"class":5233},[436,18909,5171],{"class":5163},[436,18911,5238],{"class":1151},[436,18913,4887],{"class":5163},[436,18915,5243],{"class":1144},[436,18917,5246],{"class":5233},[436,18919,18920],{"class":438,"line":5221},[436,18921,5193],{"class":5163},[436,18923,18924,18926,18929,18931,18933,18935,18937,18940],{"class":438,"line":5249},[436,18925,5257],{"class":5163},[436,18927,18928],{"class":1151},"data ",[436,18930,3168],{"class":1144},[436,18932,5171],{"class":5163},[436,18934,5238],{"class":1151},[436,18936,5269],{"class":1144},[436,18938,18939],{"class":5159},"validated",[436,18941,5321],{"class":5163},[436,18943,18944],{"class":438,"line":5254},[436,18945,5205],{"class":5163},[436,18947,18948],{"class":438,"line":5298},[436,18949,5212],{"emptyLinePlaceholder":5211},[436,18951,18952],{"class":438,"line":5324},[436,18953,18954],{"class":1168},"// Using FormRequest class\n",[436,18956,18957],{"class":438,"line":5329},[436,18958,18959],{"class":1168},"// Generate with: php bin/glueful make:request CreateUserRequest\n",[436,18961,18962,18964,18966,18968,18970,18973,18975,18977,18979,18981],{"class":438,"line":6717},[436,18963,4794],{"class":5152},[436,18965,5156],{"class":5155},[436,18967,18903],{"class":5159},[436,18969,5164],{"class":5163},[436,18971,18972],{"class":5233},"CreateUserRequest",[436,18974,5171],{"class":5163},[436,18976,5238],{"class":1151},[436,18978,4887],{"class":5163},[436,18980,5243],{"class":1144},[436,18982,5246],{"class":5233},[436,18984,18985],{"class":438,"line":6742},[436,18986,5193],{"class":5163},[436,18988,18989,18991,18993,18995,18997,18999,19001,19003],{"class":438,"line":6767},[436,18990,5257],{"class":5163},[436,18992,18928],{"class":1151},[436,18994,3168],{"class":1144},[436,18996,5171],{"class":5163},[436,18998,5238],{"class":1151},[436,19000,5269],{"class":1144},[436,19002,18939],{"class":5159},[436,19004,5321],{"class":5163},[436,19006,19007],{"class":438,"line":6772},[436,19008,5205],{"class":5163},[347,19010,413],{"id":19011},"migration-notes-31",[415,19013,19014,19017,19020],{},[418,19015,19016],{},"No breaking changes. Both features are opt-in and additive.",[418,19018,19019],{},"Existing controllers continue to work unchanged.",[418,19021,3665,19022,19025],{},[325,19023,19024],{},"'validate'"," middleware to routes for automatic validation.",[452,19027],{},[301,19029,19031],{"id":19030},"v192-deneb-patch","v1.9.2 - Deneb (Patch)",[293,19033,19034],{},[308,19035,19036],{},"Released: January 20, 2026",[312,19038,19040],{"color":3075,"icon":19039,"variant":316},"i-tabler-api",[318,19041,19042],{"v-slot:description":320},[293,19043,19044],{},"OpenAPI 3.1 support with automatic resource route expansion from database schemas and documentation UI improvements.",[347,19046,350],{"id":19047},"key-highlights-42",[352,19049,19050,19055],{},[293,19051,19052],{},[308,19053,19054],{},"OpenAPI 3.1 Support",[415,19056,19057,19060,19066,19073,19079],{},[418,19058,19059],{},"Full JSON Schema draft 2020-12 alignment",[418,19061,19062,19063,4887],{},"Nullable types use array syntax (",[325,19064,19065],{},"type: [\"string\", \"null\"]",[418,19067,19068,19069,19072],{},"License supports SPDX ",[325,19070,19071],{},"identifier"," field",[418,19074,19075,19078],{},[325,19076,19077],{},"jsonSchemaDialect"," declaration included",[418,19080,19081],{},"Default version changed from 3.0.0 to 3.1.0",[352,19083,19084,19089],{},[293,19085,19086],{},[308,19087,19088],{},"Resource Route Expansion",[415,19090,19091,19101,19104,19107],{},[418,19092,705,19093,19096,19097,19100],{},[325,19094,19095],{},"ResourceRouteExpander"," class automatically expands ",[325,19098,19099],{},"{resource}"," routes",[418,19102,19103],{},"Generates table-specific endpoints with full database schemas",[418,19105,19106],{},"No more intermediate JSON files - schemas expand directly from database",[418,19108,19109],{},"Resource tags renamed from \"Resources - {table}\" to \"Table - {table}\"",[352,19111,19112,19117],{},[293,19113,19114],{},[308,19115,19116],{},"Documentation UI Improvements",[415,19118,19119,19129,19132],{},[418,19120,19121,19122,542,19125,19128],{},"Scalar: Added ",[325,19123,19124],{},"hideClientButton",[325,19126,19127],{},"showDeveloperTools"," options",[418,19130,19131],{},"Tags in sidebar now sorted alphabetically",[418,19133,19134,19135,3677,19138],{},"Output file renamed from ",[325,19136,19137],{},"swagger.json",[325,19139,19140],{},"openapi.json",[347,19142,19144],{"id":19143},"bug-fixes","Bug Fixes",[415,19146,19147],{},[418,19148,19149,19151,19152,19155,19156,19159],{},[308,19150,53],{},": Fixed ",[325,19153,19154],{},"SchemaBuilder::getTableColumns()"," returning empty arrays due to incorrect ",[325,19157,19158],{},"array_is_list()"," check on associative column data.",[347,19161,19163],{"id":19162},"removed","Removed",[415,19165,19166,19172],{},[418,19167,19168,19171],{},[325,19169,19170],{},"TableDefinitionGenerator"," class - resource routes now expand directly from database schemas",[418,19173,19174,542,19177,19180,19181,19184],{},[325,19175,19176],{},"--database",[325,19178,19179],{},"--table"," options from ",[325,19182,19183],{},"generate:openapi"," command (no longer needed)",[347,19186,413],{"id":19187},"migration-notes-32",[415,19189,19190,19198,19204],{},[418,19191,19192,19193,19195,19196,299],{},"No breaking changes. The output file is now ",[325,19194,19140],{}," instead of ",[325,19197,19137],{},[418,19199,19200,19201,19203],{},"If you had custom scripts referencing ",[325,19202,19137],{},", update the path.",[418,19205,19206,19207,19210,19211,299],{},"Config key ",[325,19208,19209],{},"paths.swagger"," renamed to ",[325,19212,19213],{},"paths.openapi",[452,19215],{},[301,19217,19219],{"id":19218},"v191-castor-patch","v1.9.1 - Castor (Patch)",[293,19221,19222],{},[308,19223,19224],{},"Released: January 19, 2026",[312,19226,19228],{"color":3075,"icon":19227,"variant":316},"i-tabler-ad-2",[318,19229,19230],{"v-slot:description":320},[293,19231,19232],{},"Major refactor of the OpenAPI documentation system with interactive UI generation support for Scalar, Swagger UI, and Redoc.",[347,19234,350],{"id":19235},"key-highlights-43",[352,19237,19238,19243],{},[293,19239,19240],{},[308,19241,19242],{},"Documentation UI Generation",[415,19244,19245,19251,19254,19263],{},[418,19246,705,19247,19250],{},[325,19248,19249],{},"DocumentationUIGenerator"," class generates interactive HTML documentation",[418,19252,19253],{},"Supports Scalar (default), Swagger UI, and Redoc",[418,19255,705,19256,19259,19260,19262],{},[325,19257,19258],{},"--ui"," option for ",[325,19261,19183],{}," command",[418,19264,19265,19266],{},"Centralized configuration in ",[325,19267,2853],{},[352,19269,19270,19275],{},[293,19271,19272],{},[308,19273,19274],{},"Documentation Architecture Refactor",[415,19276,19277,19289,19298,19307],{},[418,19278,19279,19280,19283,19284,542,19286],{},"Replaced ",[325,19281,19282],{},"ApiDefinitionGenerator"," with focused ",[325,19285,19170],{},[325,19287,19288],{},"OpenApiGenerator",[418,19290,19291,19292,3677,19295],{},"Renamed ",[325,19293,19294],{},"ApiDefinitionsCommand",[325,19296,19297],{},"OpenApiDocsCommand",[418,19299,19300,4867,19303,19306],{},[325,19301,19302],{},"CommentsDocGenerator",[325,19304,19305],{},"phpDocumentor/ReflectionDocBlock"," for robust PHPDoc parsing",[418,19308,19309,19310,19312],{},"Extension routes discovered via ",[325,19311,5705],{}," for Composer packages",[347,19314,19316],{"id":19315},"new-validation-rules","New Validation Rules",[415,19318,19319,19325],{},[418,19320,19321,19324],{},[325,19322,19323],{},"Numeric"," - Validates numeric values with optional range, integer-only, and positive-only constraints",[418,19326,19327,19330],{},[325,19328,19329],{},"Regex"," - Validates values against regular expression patterns",[347,19332,19334],{"id":19333},"dependencies","Dependencies",[415,19336,19337,19345],{},[418,19338,19339,19340,3677,19343],{},"Updated Symfony packages from ",[325,19341,19342],{},"^7.3",[325,19344,584],{},[418,19346,5000,19347],{},[325,19348,19349],{},"phpdocumentor/reflection-docblock: ^6.0",[347,19351,9391],{"id":19352},"quick-usage-9",[428,19354,19356],{"className":430,"code":19355,"language":432,"meta":320,"style":320},"# Generate docs with default UI (Scalar)\nphp glueful generate:openapi --ui\n\n# Generate with specific UI\nphp glueful generate:openapi --ui=swagger-ui\nphp glueful generate:openapi --ui=redoc\n",[325,19357,19358,19363,19375,19379,19384,19395],{"__ignoreMap":320},[436,19359,19360],{"class":438,"line":439},[436,19361,19362],{"class":1168},"# Generate docs with default UI (Scalar)\n",[436,19364,19365,19367,19369,19372],{"class":438,"line":1132},[436,19366,1135],{"class":442},[436,19368,1138],{"class":446},[436,19370,19371],{"class":446}," generate:openapi",[436,19373,19374],{"class":5565}," --ui\n",[436,19376,19377],{"class":438,"line":1158},[436,19378,5212],{"emptyLinePlaceholder":5211},[436,19380,19381],{"class":438,"line":5196},[436,19382,19383],{"class":1168},"# Generate with specific UI\n",[436,19385,19386,19388,19390,19392],{"class":438,"line":5202},[436,19387,1135],{"class":442},[436,19389,1138],{"class":446},[436,19391,19371],{"class":446},[436,19393,19394],{"class":5565}," --ui=swagger-ui\n",[436,19396,19397,19399,19401,19403],{"class":438,"line":5208},[436,19398,1135],{"class":442},[436,19400,1138],{"class":446},[436,19402,19371],{"class":446},[436,19404,19405],{"class":5565}," --ui=redoc\n",[347,19407,413],{"id":19408},"migration-notes-33",[415,19410,19411,19417],{},[418,19412,19413,19414,19416],{},"No breaking changes. The old ",[325,19415,19282],{}," is removed but the command interface remains compatible.",[418,19418,19419,19420,542,19422,299],{},"If you referenced internal documentation classes directly, update to use ",[325,19421,19288],{},[325,19423,19170],{},[452,19425],{},[301,19427,19429],{"id":19428},"v190-betelgeuse-minor","v1.9.0 - Betelgeuse (Minor)",[293,19431,19432],{},[308,19433,19434],{},"Released: January 17, 2026",[312,19436,19438],{"color":464,"icon":19437,"variant":316},"i-tabler-alert-triangle",[318,19439,19440],{"v-slot:description":320},[293,19441,19442],{},"Raises minimum PHP version to 8.3 and addresses Symfony Console 7.3 compatibility. Review the upgrade guide before updating.",[347,19444,4676],{"id":19445},"breaking-changes",[415,19447,19448,19454],{},[418,19449,19450,19453],{},[308,19451,19452],{},"PHP 8.3 Required",": Minimum PHP version raised from 8.2 to 8.3. Ensure your environment is updated before upgrading.",[418,19455,19456,1061,19459,19210,19462,19465,19466,19469],{},[308,19457,19458],{},"Console Method Renamed",[325,19460,19461],{},"Application::addCommand(string $class)",[325,19463,19464],{},"Application::registerCommandClass(string $class)"," due to Symfony Console 7.3 adding a conflicting ",[325,19467,19468],{},"addCommand(Command|callable)"," method.",[347,19471,350],{"id":19472},"key-highlights-44",[415,19474,19475,19483,19493,19499],{},[418,19476,19477,1061,19479,19482],{},[308,19478,33],{},[325,19480,19481],{},"RouteManifest::load()"," now prevents double-loading routes during framework initialization, eliminating \"Route already defined\" warnings in CLI commands.",[418,19484,19485,19488,19489,19492],{},[308,19486,19487],{},"Security",": Fixed PHPStan strict boolean check in ",[325,19490,19491],{},"CSRFMiddleware"," for explicit cookie token validation.",[418,19494,19495,19498],{},[308,19496,19497],{},"Tests",": Added missing PSR-4 namespace declarations to async test files for proper autoloading.",[418,19500,19501,19504],{},[308,19502,19503],{},"CI",": Test matrix now targets PHP 8.3 and 8.4 (dropped PHP 8.2 support).",[347,19506,19508],{"id":19507},"new-apis","New APIs",[415,19510,19511,19517],{},[418,19512,19513,19516],{},[325,19514,19515],{},"RouteManifest::reset()"," - Reset loaded state (for testing)",[418,19518,19519,19522],{},[325,19520,19521],{},"RouteManifest::isLoaded()"," - Check if routes have been loaded",[347,19524,413],{"id":19525},"migration-notes-34",[312,19527,19528],{"color":464,"icon":19437,"variant":316},[318,19529,19530],{"v-slot:description":320},[293,19531,19532,19535],{},[308,19533,19534],{},"Action Required",": Update your PHP environment to 8.3+ before upgrading.",[19537,19538,19539,19545,19558],"ol",{},[418,19540,19541,19544],{},[308,19542,19543],{},"Environment",": Ensure PHP 8.3 or higher is installed",[418,19546,19547,19550,19551,19554,19555],{},[308,19548,19549],{},"Method Rename",": If you called ",[325,19552,19553],{},"$app->addCommand(MyCommand::class)",", update to ",[325,19556,19557],{},"$app->registerCommandClass(MyCommand::class)",[418,19559,19560,19562,19563,19565],{},[308,19561,19334],{},": Run ",[325,19564,424],{}," to refresh the lock file",[452,19567],{},[301,19569,19571],{"id":19570},"v181-vega-patch","v1.8.1 - Vega (Patch)",[293,19573,19574],{},[308,19575,19576],{},"Released: November 23, 2025",[312,19578,19579],{"color":3075,"icon":19227,"variant":316},[318,19580,19581],{"v-slot:description":320},[293,19582,19583],{},"Tightens password policy helpers with lowercase enforcement and makes the async stream helper smarter about buffering existing async transports.",[347,19585,350],{"id":19586},"key-highlights-45",[415,19588,19589,19600],{},[418,19590,19591,19592,19595,19596,19599],{},"Security: ",[325,19593,19594],{},"Utils::validatePassword()"," now supports a ",[325,19597,19598],{},"$requireLowercase"," flag alongside existing numeric, special-character, and uppercase toggles, enabling mixed-case enforcement without custom validators.",[418,19601,19602,19603,19606,19607,2000,19610,19613],{},"Async I/O: ",[325,19604,19605],{},"async_stream()"," accepts raw resources, ",[325,19608,19609],{},"AsyncStream",[325,19611,19612],{},"BufferedAsyncStream"," instances and normalizes them before optionally wrapping in a buffer. This keeps buffered helpers type-safe and resolves analyzer warnings about expected vs. actual types.",[347,19615,413],{"id":19616},"migration-notes-35",[415,19618,19619],{},[418,19620,19621],{},"No breaking changes. Opt into the lowercase flag when updating password policies, and the stream helper works seamlessly with existing calls.",[452,19623],{},[301,19625,19627],{"id":19626},"v180-spica-minor","v1.8.0 - Spica (Minor)",[293,19629,19630],{},[308,19631,19632],{},"Released: November 13, 2025",[312,19634,19635],{"color":3075,"icon":19227,"variant":316},[318,19636,19637],{"v-slot:description":320},[293,19638,19639],{},"First-class session and login response events. Safely enrich cached session payloads and shape login responses without modifying framework code.",[347,19641,350],{"id":19642},"key-highlights-46",[415,19644,19645,19675,19696],{},[418,19646,19647,19648],{},"Events/Auth:\n",[415,19649,19650,19660,19669],{},[418,19651,19652,19655,19656,19659],{},[325,19653,19654],{},"SessionCachedEvent",": Dispatched after a session is written to cache (and DB). Listeners can augment the cached payload (e.g., ",[325,19657,19658],{},"user.organization",") or warm caches.",[418,19661,19662,19665,19666,3447],{},[325,19663,19664],{},"LoginResponseBuildingEvent",": Dispatched just before returning the login JSON. Provides a mutable response map so apps can add fields (e.g., ",[325,19667,19668],{},"context.organization",[418,19670,19671,19674],{},[325,19672,19673],{},"LoginResponseBuiltEvent",": Dispatched after the response is finalized for analytics/metrics.",[418,19676,19677,19678],{},"Wiring:\n",[415,19679,19680,19690],{},[418,19681,19682,19683,19686,19687,299],{},"Session cached hook in ",[325,19684,19685],{},"SessionCacheManager::storeSession()"," after successful ",[325,19688,19689],{},"cache->set",[418,19691,19692,19693,19695],{},"Login response hooks in ",[325,19694,1522],{}," just before returning.",[418,19697,19698,19699,19702],{},"Docs: Proposal updated with final API (setter-based mutation, paths under ",[325,19700,19701],{},"src/...",") and example listeners.",[347,19704,413],{"id":19705},"migration-notes-36",[415,19707,19708,19711,19714],{},[418,19709,19710],{},"Backward compatible: No behavior change unless listeners are registered.",[418,19712,19713],{},"Performance: Events are synchronous; offload heavy work to queues.",[418,19715,19716,19717,19720],{},"Guidance: Prefer adding app-specific fields under ",[325,19718,19719],{},"context.*"," to avoid collisions.",[452,19722],{},[301,19724,19726],{"id":19725},"v174-arcturus-patch","v1.7.4 - Arcturus (Patch)",[293,19728,19729],{},[308,19730,19731],{},"Released: October 28, 2025",[312,19733,19734],{"color":3075,"icon":19227,"variant":316},[318,19735,19736],{"v-slot:description":320},[293,19737,19738],{},"Minimal, configurable account‑status gate in AuthenticationService (secure by default).",[347,19740,350],{"id":19741},"key-highlights-47",[415,19743,19744,19762],{},[418,19745,19746,19747,1625,19750,19753,19754],{},"Auth: Enforce allowed statuses during username/password login and refresh‑token flows via ",[325,19748,19749],{},"security.auth.allowed_login_statuses",[325,19751,19752],{},"['active']",").\n",[415,19755,19756,19759],{},[418,19757,19758],{},"Fails silently to prevent account enumeration.",[418,19760,19761],{},"Policy intentionally lean for app‑level extension.",[418,19763,19764,19765,19768],{},"Docs: Added ",[325,19766,19767],{},"docs/migration-examples-views-functions.md"," covering three approaches to create views/functions in migrations (SchemaBuilder queue, direct PDO exec, QueryBuilder DDL).",[347,19770,413],{"id":19771},"migration-notes-37",[415,19773,19774],{},[418,19775,19776,19777,19780,19781,299],{},"If you experimented with ",[325,19778,19779],{},"auth.allowed_login_statuses",", move it to ",[325,19782,19749],{},[452,19784],{},[301,19786,19788],{"id":19787},"v173-pollux-patch","v1.7.3 - Pollux (Patch)",[293,19790,19791],{},[308,19792,19793],{},"Released: October 21, 2025",[312,19795,19796],{"color":3075,"icon":19227,"variant":316},[318,19797,19798],{"v-slot:description":320},[293,19799,19800],{},"QueryBuilder 2‑argument where/orWhere fix and clearer dev‑server logs.",[347,19802,350],{"id":19803},"key-highlights-48",[415,19805,19806,19827],{},[418,19807,19808,19809,542,19812,19815,19816,19818,19819],{},"Database/QueryBuilder: Normalize 2‑argument ",[325,19810,19811],{},"where($column, $value)",[325,19813,19814],{},"orWhere($column, $value)"," to use ",[325,19817,3168],{}," internally.\n",[415,19820,19821,19824],{},[418,19822,19823],{},"Prevents a TypeError when non‑string values were misread as the operator.",[418,19825,19826],{},"Improves portability for boolean filters across PostgreSQL/MySQL/SQLite.",[418,19828,6417,19829,19832,19833,19836],{},[325,19830,19831],{},"serve"," further reclassifies PHP built‑in server access/lifecycle lines written to STDERR (e.g., “Accepted”, “Closed without sending a request”, “",[436,19834,19835],{},"200",": GET /…”) as normal output, while preserving real errors.",[452,19838],{},[301,19840,19842],{"id":19841},"v172-antares-patch","v1.7.2 - Antares (Patch)",[293,19844,19845],{},[308,19846,19793],{},[312,19848,19849],{"color":3075,"icon":19227,"variant":316},[318,19850,19851],{"v-slot:description":320},[293,19852,19853],{},"Route loading resilience and quieter dev‑server logs.",[347,19855,350],{"id":19856},"key-highlights-49",[415,19858,19859,19874],{},[418,19860,19861,19862,19865,19866],{},"Extensions: ",[325,19863,19864],{},"ServiceProvider::loadRoutesFrom()"," is idempotent and exception‑safe now.\n",[415,19867,19868,19871],{},[418,19869,19870],{},"Prevents duplicate route registration if a routes file is loaded more than once.",[418,19872,19873],{},"Catches exceptions from route files; logs and continues in production, rethrows in non‑production for fast feedback.",[418,19875,6417,19876,19878,19879,19882],{},[325,19877,19831],{}," reclassifies common PHP built‑in server access/startup lines from STDERR as normal output, reducing false ",[325,19880,19881],{},"[ERROR]"," noise.",[452,19884],{},[301,19886,19888],{"id":19887},"v171-canopus-patch","v1.7.1 - Canopus (Patch)",[293,19890,19891],{},[308,19892,19793],{},[312,19894,19895],{"color":3075,"icon":19227,"variant":316},[318,19896,19897],{"v-slot:description":320},[293,19898,19899],{},"Fixes extension discovery/boot sequencing so extensions reliably load and their migrations appear.",[347,19901,350],{"id":19902},"key-highlights-50",[415,19904,19905,19916,19928],{},[418,19906,19907,19908,19911,19912,19915],{},"Extensions: Call ",[325,19909,19910],{},"ExtensionManager::discover()"," before ",[325,19913,19914],{},"::boot()"," during framework initialization so enabled providers load correctly.",[418,19917,19918,19919,19922,19923,380,19925,19927],{},"Migrations: Extension migrations registered via ",[325,19920,19921],{},"loadMigrationsFrom()"," are discovered by ",[325,19924,4767],{},[325,19926,4764],{}," once providers are discovered at boot.",[418,19929,6417,19930,380,19932,19934],{},[325,19931,1026],{},[325,19933,1012],{}," now reflect included providers after boot, improving diagnostics.",[347,19936,19938],{"id":19937},"impact","Impact",[415,19940,19941],{},[418,19942,19943],{},"Apps that previously saw “No pending migrations found” for extension migrations should now see them once the provider is enabled. No config changes required.",[452,19945],{},[301,19947,19949],{"id":19948},"v170-procyon","v1.7.0 - Procyon",[293,19951,19952],{},[308,19953,19954],{},"Released: October 18, 2025",[312,19956,19957],{"color":3075,"icon":19227,"variant":316},[318,19958,19959],{"v-slot:description":320},[293,19960,19961],{},"Major async/concurrency subsystem. Fiber‑based scheduler, async HTTP client with streaming/pooling, buffered I/O, cooperative cancellation, metrics instrumentation, and a Promise‑style wrapper. Centralized configuration and DI wiring included.",[347,19963,350],{"id":19964},"key-highlights-51",[352,19966,19967,19972],{},[293,19968,19969],{},[308,19970,19971],{},"Fiber‑Based Async Scheduler",[415,19973,19974,19990,19993],{},[418,19975,19976,3685,19979,332,19982,332,19984,332,19987],{},[325,19977,19978],{},"Glueful\\\\Async\\\\FiberScheduler",[325,19980,19981],{},"spawn",[325,19983,3354],{},[325,19985,19986],{},"race",[325,19988,19989],{},"sleep",[418,19991,19992],{},"Resource‑limit guards (max concurrent tasks, per‑task execution time, optional memory/FDS caps)",[418,19994,19995],{},"Rich metrics hooks (suspend/resume, queue depth, cancellations, resource limits)",[352,19997,19998,20003],{},[293,19999,20000],{},[308,20001,20002],{},"Async HTTP + Streaming",[415,20004,20005,20014,20024],{},[418,20006,20007,20010,20011],{},[325,20008,20009],{},"Glueful\\\\Async\\\\Http\\\\CurlMultiHttpClient"," with cooperative polling and optional ",[325,20012,20013],{},"max_concurrent",[418,20015,20016,20019,20020,20023],{},[325,20017,20018],{},"poolAsync()"," for concurrent requests; ",[325,20021,20022],{},"HttpStreamingClient::sendAsyncStream()"," for chunked callbacks",[418,20025,20026,20029],{},[325,20027,20028],{},"FakeHttpClient"," for test isolation",[352,20031,20032,20037],{},[293,20033,20034],{},[308,20035,20036],{},"Async I/O + Helpers",[415,20038,20039,20046,20075],{},[418,20040,20041,542,20043,20045],{},[325,20042,19609],{},[325,20044,19612],{}," with line/whole‑read helpers and buffered reads/writes",[418,20047,20048,20049,332,20052,332,20055,332,20058,332,20061,332,20064,332,20067,332,20070,332,20072],{},"Helpers: ",[325,20050,20051],{},"scheduler()",[325,20053,20054],{},"async()",[325,20056,20057],{},"await()",[325,20059,20060],{},"await_all()",[325,20062,20063],{},"await_race()",[325,20065,20066],{},"async_sleep()",[325,20068,20069],{},"async_sleep_default()",[325,20071,19605],{},[325,20073,20074],{},"cancellation_token()",[418,20076,20077,20078,3685,20081,332,20084],{},"Promise wrapper: ",[325,20079,20080],{},"Glueful\\\\Async\\\\Promise",[325,20082,20083],{},"then/catch/finally",[325,20085,20086],{},"all/race",[347,20088,20090],{"id":20089},"configuration-di","Configuration & DI",[415,20092,20093,20109],{},[418,20094,705,20095,20097,20098,332,20101,332,20103,332,20106],{},[325,20096,8304],{}," for ",[325,20099,20100],{},"scheduler",[325,20102,4362],{},[325,20104,20105],{},"streams",[325,20107,20108],{},"limits",[418,20110,20111,20113,20114,332,20117,332,20120,20123,20124,20127,20128,4887],{},[325,20112,8301],{}," wires ",[325,20115,20116],{},"Metrics",[325,20118,20119],{},"Scheduler",[325,20121,20122],{},"HttpClient","; registers ",[325,20125,20126],{},"AsyncMiddleware"," (alias ",[325,20129,20130],{},"async",[347,20132,413],{"id":20133},"migration-notes-38",[415,20135,20136,20139],{},[418,20137,20138],{},"Backward‑compatible defaults: limits disabled when set to 0",[418,20140,20141,20142,20144,20145,332,20147,4979],{},"To adopt in routes, add middleware alias ",[325,20143,20130],{}," or use helpers (",[325,20146,20054],{},[325,20148,20060],{},[452,20150],{},[301,20152,20154],{"id":20153},"v162-capella","v1.6.2 - Capella",[293,20156,20157],{},[308,20158,20159],{},"Released: October 14, 2025",[312,20161,20162],{"color":3075,"icon":19227,"variant":316},[318,20163,20164],{"v-slot:description":320},[293,20165,20166],{},"Template configuration responsibility moved to the Email Notification extension.",[347,20168,20170],{"id":20169},"whats-changed","What's Changed",[415,20172,20173,20176,20182],{},[418,20174,20175],{},"The primary templates directory is now controlled by the Email Notification extension configuration",[418,20177,20178,20179],{},"Framework no longer sets a default ",[325,20180,20181],{},"services.mail.templates.path",[418,20183,20184],{},"Custom paths, caching, layout, mappings, and globals remain supported",[347,20186,413],{"id":20187},"migration-notes-39",[415,20189,20190,20197],{},[418,20191,20192,20193,20196],{},"If you relied on the framework default templates path, configure ",[325,20194,20195],{},"email-notification.templates.extension_path"," in the extension",[418,20198,20199,20200,20202],{},"Or set ",[325,20201,20181],{}," in your app config",[452,20204],{},[301,20206,20208],{"id":20207},"v161-arcturus","v1.6.1 - Arcturus",[293,20210,20211],{},[308,20212,20159],{},[312,20214,20215],{"color":3075,"icon":19227,"variant":316},[318,20216,20217],{"v-slot:description":320},[293,20218,20219],{},"JWT RS256 signing support for generating JWTs using an RSA private key.",[347,20221,350],{"id":20222},"key-highlights-52",[415,20224,20225,20231],{},[418,20226,20227,20228],{},"Auth/JWT: ",[325,20229,20230],{},"JWTService::signRS256(array $claims, string $privateKey)",[418,20232,20233,20234,20237],{},"Requires PHP ",[325,20235,20236],{},"openssl"," extension",[452,20239],{},[293,20241,20242],{},"Risk scale: High = architectural changes / broad API shifts; Medium = targeted breaking or migration; Low = additive or internal refactors.",[301,20244,20246],{"id":20245},"v160-sirius","v1.6.0 - Sirius",[293,20248,20249],{},[308,20250,20251],{},"Released: October 13, 2025",[312,20253,20254],{"color":3075,"icon":19227,"variant":316},[318,20255,20256],{"v-slot:description":320},[293,20257,20258],{},"Minor features and DX improvements. This release focuses on compiled DI artifacts, conditional HTTP caching helpers, and configuration utilities.",[347,20260,350],{"id":20261},"key-highlights-53",[352,20263,20264,20269],{},[293,20265,20266],{},[308,20267,20268],{},"Compiled Container Artifacts",[415,20270,20271,20297,20306],{},[418,20272,20273,20276,20277,20280,20281,20284,20285,332,20288,332,20290,332,20292,332,20294,299],{},[325,20274,20275],{},"di:container:compile"," now emits ",[325,20278,20279],{},"services.json"," at ",[325,20282,20283],{},"storage/cache/container/services.json"," with fields: ",[325,20286,20287],{},"shared",[325,20289,1266],{},[325,20291,3605],{},[325,20293,7823],{},[325,20295,20296],{},"alias_of",[418,20298,20299,20302,20303,20305],{},[325,20300,20301],{},"di:container:map"," prefers the compiled ",[325,20304,20279],{}," in production (no reflection overhead).",[418,20307,20308,20311],{},[325,20309,20310],{},"ContainerFactory"," prefers a precompiled container class in production when available.",[352,20313,20314,20319],{},[293,20315,20316],{},[308,20317,20318],{},"Conditional HTTP Caching",[415,20320,20321,20327],{},[418,20322,705,20323,20326],{},[325,20324,20325],{},"ConditionalCacheMiddleware"," handles ETag/If‑None‑Match and Last‑Modified/If‑Modified‑Since to return 304 efficiently.",[418,20328,20329,20332],{},[325,20330,20331],{},"Response::withLastModified(DateTimeInterface)"," helper for setting validators.",[352,20334,20335,20340],{},[293,20336,20337],{},[308,20338,20339],{},"DSN Utilities",[415,20341,20342,20353],{},[418,20343,20344,3685,20347,542,20350,299],{},[325,20345,20346],{},"Glueful\\\\Config\\\\DsnParser",[325,20348,20349],{},"parseDbDsn()",[325,20351,20352],{},"parseRedisDsn()",[418,20354,20355,20356,20359,20360,332,20363,3447],{},"New CLI: ",[325,20357,20358],{},"config:dsn:validate"," validates DSNs from flags or environment (e.g., ",[325,20361,20362],{},"DATABASE_URL",[325,20364,20365],{},"REDIS_URL",[347,20367,20369],{"id":20368},"notes","Notes",[415,20371,20372],{},[418,20373,20374],{},"OpenTelemetry support is planned as a Glueful extension package (not part of the core framework).",[452,20376],{},[301,20378,20380],{"id":20379},"v150-orion","v1.5.0 - Orion",[293,20382,20383],{},[308,20384,20251],{},[312,20386,20387],{"color":3075,"icon":19227,"variant":316},[318,20388,20389],{"v-slot:description":320},[293,20390,20391],{},"Notifications DI wiring and safer email flows. This release introduces a shared notifications provider and makes email verification/password reset flows more robust.",[347,20393,350],{"id":20394},"key-highlights-54",[352,20396,20397,20402],{},[293,20398,20399],{},[308,20400,20401],{},"Notifications DI Provider",[415,20403,20404,20417],{},[418,20405,705,20406,20409,20410,542,20413,20416],{},[325,20407,20408],{},"NotificationsProvider"," registers shared ",[325,20411,20412],{},"ChannelManager",[325,20414,20415],{},"NotificationDispatcher"," in the container.",[418,20418,20419],{},"Extensions can register channels/hooks against the dispatcher during boot.",[352,20421,20422,20427],{},[293,20423,20424],{},[308,20425,20426],{},"Safer Email Flows",[415,20428,20429,20432,20438],{},[418,20430,20431],{},"Email verification and SendNotification now prefer DI‑resolved dispatcher/channel with safe fallbacks.",[418,20433,20434,20435,20437],{},"Removed hard ",[325,20436,980],{}," prechecks; channel availability is evaluated at send time.",[418,20439,20440],{},"Soft diagnostics when the email channel is unavailable or when no channels succeeded.",[347,20442,20170],{"id":20443},"whats-changed-1",[415,20445,20446],{},[418,20447,20448,20449,299],{},"Retry configuration aligned to ",[325,20450,20451],{},"email-notification.retry",[452,20453],{},[301,20455,20457],{"id":20456},"v142-rigel-patch","v1.4.2 - Rigel (Patch)",[293,20459,20460],{},[308,20461,20462],{},"Released: October 11, 2025",[312,20464,20465],{"color":3075,"icon":19227,"variant":316},[318,20466,20467],{"v-slot:description":320},[293,20468,20469],{},"Developer‑facing tidy‑ups; no runtime behavior changes.",[347,20471,20473],{"id":20472},"fixes","Fixes",[415,20475,20476],{},[418,20477,20478,20479,20482],{},"PSR‑4 autoloading for tests: corrected a test namespace to match ",[325,20480,20481],{},"Glueful\\\\Tests\\\\…"," and remove Composer warnings during autoload generation.",[347,20484,20486],{"id":20485},"documentation","Documentation",[415,20488,20489],{},[418,20490,20491],{},"Roadmap and this page updated to reflect 1.4.1’s SQLite‑first install flow and non‑interactive flags.",[452,20493],{},[301,20495,20497],{"id":20496},"v141-rigel-patch","v1.4.1 - Rigel (Patch)",[293,20499,20500],{},[308,20501,20462],{},[312,20503,20504],{"color":3075,"icon":19227,"variant":316},[318,20505,20506],{"v-slot:description":320},[293,20507,20508],{},"Installation flow hardening and SQLite‑first defaults. This patch improves non‑interactive installs and avoids fragile checks during initial setup.",[347,20510,350],{"id":20511},"key-highlights-55",[352,20513,20514,20519],{},[293,20515,20516],{},[308,20517,20518],{},"SQLite‑first Install & Non‑Interactive Flags",[415,20520,20521,20524,20536,20545],{},[418,20522,20523],{},"Install enforces SQLite during setup; other engines can be configured after install",[418,20525,20526,20528,20529,20531,20532,542,20534],{},[325,20527,4764],{}," executed with ",[325,20530,6470],{},"; in quiet installs also ",[325,20533,14554],{},[325,20535,4646],{},[418,20537,20538,20541,20542,20544],{},[325,20539,20540],{},"cache:clear"," during install passes ",[325,20543,6470],{}," and respects quiet mode flags",[418,20546,20547],{},"Removed DB connection health check during install (SQLite does not require network; migrations surface issues)",[347,20549,9391],{"id":20550},"quick-usage-10",[428,20552,20554],{"className":430,"code":20553,"language":432,"meta":320,"style":320},"# Default (SQLite) install\nphp glueful install --quiet --force\n\n# After switching DB in .env, run migrations\nphp glueful migrate:run -f --no-interaction\n",[325,20555,20556,20561,20575,20579,20584],{"__ignoreMap":320},[436,20557,20558],{"class":438,"line":439},[436,20559,20560],{"class":1168},"# Default (SQLite) install\n",[436,20562,20563,20565,20567,20570,20573],{"class":438,"line":1132},[436,20564,1135],{"class":442},[436,20566,1138],{"class":446},[436,20568,20569],{"class":446}," install",[436,20571,20572],{"class":5565}," --quiet",[436,20574,17382],{"class":5565},[436,20576,20577],{"class":438,"line":1158},[436,20578,5212],{"emptyLinePlaceholder":5211},[436,20580,20581],{"class":438,"line":5196},[436,20582,20583],{"class":1168},"# After switching DB in .env, run migrations\n",[436,20585,20586,20588,20590,20593,20596],{"class":438,"line":5202},[436,20587,1135],{"class":442},[436,20589,1138],{"class":446},[436,20591,20592],{"class":446}," migrate:run",[436,20594,20595],{"class":5565}," -f",[436,20597,14997],{"class":5565},[347,20599,20369],{"id":20600},"notes-1",[415,20602,20603],{},[418,20604,20605],{},"Post‑install message now includes a brief guide for switching databases and running migrations later.",[452,20607],{},[301,20609,20611],{"id":20610},"v140-rigel","v1.4.0 - Rigel",[293,20613,20614],{},[308,20615,20462],{},[312,20617,20618],{"color":3075,"icon":19227,"variant":316},[318,20619,20620],{"v-slot:description":320},[293,20621,20622,20625],{},[308,20623,20624],{},"Rigel"," consolidates session management behind a single, testable SessionStore API and removes the legacy TokenStorageService. It unifies TTL policy, standardizes DI resolution, and hardens cache-key handling for tokens.",[347,20627,350],{"id":20628},"key-highlights-56",[352,20630,20631,20636],{},[293,20632,20633],{},[308,20634,20635],{},"Unified Session Store",[415,20637,20638,20641,20651,20654],{},[418,20639,20640],{},"New SessionStoreInterface + default SessionStore for create/update/revoke/lookup/health",[418,20642,20643,20644,332,20647,20650],{},"Canonical TTL helpers: ",[325,20645,20646],{},"getAccessTtl()",[325,20648,20649],{},"getRefreshTtl()"," (provider + remember‑me aware)",[418,20652,20653],{},"DI consistency with SessionStoreResolver utility and ResolvesSessionStore trait",[418,20655,20656],{},"Safe cache keys for token mappings (hashed tokens + sanitized prefixes)",[347,20658,20170],{"id":20659},"whats-changed-2",[415,20661,20662,20665,20672,20675],{},[418,20663,20664],{},"TokenManager defers TTL policy to SessionStore and persists sessions via the store.",[418,20666,20667,20668,20671],{},"JwtAuthenticationProvider and SessionCacheManager resolve the store via the trait; fewer ad‑hoc ",[325,20669,20670],{},"new"," calls.",[418,20673,20674],{},"SessionAnalytics prefers the store for listing sessions (falls back to cache query when needed).",[418,20676,20677],{},"JWTService cleanup; rely on DB‑backed revocation.",[347,20679,19163],{"id":20680},"removed-1",[415,20682,20683,20686],{},[418,20684,20685],{},"TokenStorageService and TokenStorageInterface (fully migrated to SessionStore).",[418,20687,20688],{},"Deprecated code paths tied to the legacy storage/invalidation.",[347,20690,413],{"id":20691},"migration-notes-40",[312,20693,20694],{"color":464,"icon":19437,"variant":316},[318,20695,20696],{"v-slot:description":320},[293,20697,20698,20699,20702,20703,5243],{},"If you previously referenced ",[325,20700,20701],{},"TokenStorageService",", migrate to ",[325,20704,20705],{},"SessionStoreInterface",[428,20707,20709],{"className":5139,"code":20708,"language":1135,"meta":320,"style":320},"use Glueful\\\\Auth\\\\Interfaces\\\\SessionStoreInterface;\n\n/** @var SessionStoreInterface $store */\n$store = container()->get(SessionStoreInterface::class);\n\n// Create\n$created = $store->create($user, $tokens, 'jwt', false);\n\n// Read / Update / Revoke\n$session = $store->getByAccessToken($tokens['access_token']);\n$updated = $store->updateTokens($tokens['refresh_token'], $newTokens);\n$revoked = $store->revoke($newTokens['access_token']);\n",[325,20710,20711,20734,20738,20754,20782,20786,20791,20834,20838,20843,20875,20915],{"__ignoreMap":320},[436,20712,20713,20715,20717,20720,20723,20725,20728,20730,20732],{"class":438,"line":439},[436,20714,6516],{"class":5167},[436,20716,6520],{"class":6519},[436,20718,20719],{"class":6523},"\\\\",[436,20721,20722],{"class":6519},"Auth",[436,20724,20719],{"class":6523},[436,20726,20727],{"class":6519},"Interfaces",[436,20729,20719],{"class":6523},[436,20731,20705],{"class":6532},[436,20733,5816],{"class":5163},[436,20735,20736],{"class":438,"line":1132},[436,20737,5212],{"emptyLinePlaceholder":5211},[436,20739,20740,20743,20747,20751],{"class":438,"line":1158},[436,20741,20742],{"class":1168},"/** ",[436,20744,20746],{"class":20745},"s41CE","@var",[436,20748,20750],{"class":20749},"s6MXs"," SessionStoreInterface",[436,20752,20753],{"class":1168}," $store */\n",[436,20755,20756,20758,20761,20763,20766,20768,20770,20772,20774,20776,20778,20780],{"class":438,"line":5196},[436,20757,5761],{"class":5163},[436,20759,20760],{"class":1151},"store ",[436,20762,3168],{"class":1144},[436,20764,20765],{"class":5159}," container",[436,20767,7677],{"class":5163},[436,20769,5269],{"class":1144},[436,20771,715],{"class":5159},[436,20773,5164],{"class":5163},[436,20775,20705],{"class":5233},[436,20777,6056],{"class":1144},[436,20779,6059],{"class":5167},[436,20781,5295],{"class":5163},[436,20783,20784],{"class":438,"line":5202},[436,20785,5212],{"emptyLinePlaceholder":5211},[436,20787,20788],{"class":438,"line":5208},[436,20789,20790],{"class":1168},"// Create\n",[436,20792,20793,20795,20798,20800,20802,20804,20806,20808,20810,20812,20814,20816,20819,20821,20823,20826,20828,20830,20832],{"class":438,"line":5215},[436,20794,5761],{"class":5163},[436,20796,20797],{"class":1151},"created ",[436,20799,3168],{"class":1144},[436,20801,5171],{"class":5163},[436,20803,4991],{"class":1151},[436,20805,5269],{"class":1144},[436,20807,15860],{"class":5159},[436,20809,5778],{"class":5163},[436,20811,11052],{"class":1151},[436,20813,5177],{"class":5163},[436,20815,5171],{"class":5163},[436,20817,20818],{"class":1151},"tokens",[436,20820,5177],{"class":5163},[436,20822,6064],{"class":5281},[436,20824,20825],{"class":446},"jwt",[436,20827,5282],{"class":5281},[436,20829,5177],{"class":5163},[436,20831,10171],{"class":10170},[436,20833,5295],{"class":5163},[436,20835,20836],{"class":438,"line":5221},[436,20837,5212],{"emptyLinePlaceholder":5211},[436,20839,20840],{"class":438,"line":5249},[436,20841,20842],{"class":1168},"// Read / Update / Revoke\n",[436,20844,20845,20847,20850,20852,20854,20856,20858,20861,20863,20865,20867,20869,20871,20873],{"class":438,"line":5254},[436,20846,5761],{"class":5163},[436,20848,20849],{"class":1151},"session ",[436,20851,3168],{"class":1144},[436,20853,5171],{"class":5163},[436,20855,4991],{"class":1151},[436,20857,5269],{"class":1144},[436,20859,20860],{"class":5159},"getByAccessToken",[436,20862,5778],{"class":5163},[436,20864,20818],{"class":1151},[436,20866,8042],{"class":5163},[436,20868,5282],{"class":5281},[436,20870,3647],{"class":446},[436,20872,5282],{"class":5281},[436,20874,6072],{"class":5163},[436,20876,20877,20879,20882,20884,20886,20888,20890,20893,20895,20897,20899,20901,20903,20905,20908,20910,20913],{"class":438,"line":5298},[436,20878,5761],{"class":5163},[436,20880,20881],{"class":1151},"updated ",[436,20883,3168],{"class":1144},[436,20885,5171],{"class":5163},[436,20887,4991],{"class":1151},[436,20889,5269],{"class":1144},[436,20891,20892],{"class":5159},"updateTokens",[436,20894,5778],{"class":5163},[436,20896,20818],{"class":1151},[436,20898,8042],{"class":5163},[436,20900,5282],{"class":5281},[436,20902,3650],{"class":446},[436,20904,5282],{"class":5281},[436,20906,20907],{"class":5163},"],",[436,20909,5171],{"class":5163},[436,20911,20912],{"class":1151},"newTokens",[436,20914,5295],{"class":5163},[436,20916,20917,20919,20922,20924,20926,20928,20930,20933,20935,20937,20939,20941,20943,20945],{"class":438,"line":5324},[436,20918,5761],{"class":5163},[436,20920,20921],{"class":1151},"revoked ",[436,20923,3168],{"class":1144},[436,20925,5171],{"class":5163},[436,20927,4991],{"class":1151},[436,20929,5269],{"class":1144},[436,20931,20932],{"class":5159},"revoke",[436,20934,5778],{"class":5163},[436,20936,20912],{"class":1151},[436,20938,8042],{"class":5163},[436,20940,5282],{"class":5281},[436,20942,3647],{"class":446},[436,20944,5282],{"class":5281},[436,20946,6072],{"class":5163},[452,20948],{},[301,20950,20952],{"id":20951},"v131-altair","v1.3.1 - Altair",[293,20954,20955],{},[308,20956,20957],{},"Released: October 10, 2025",[312,20959,20960],{"color":3075,"icon":19227,"variant":316},[318,20961,20962],{"v-slot:description":320},[293,20963,20964,20967],{},[308,20965,20966],{},"Altair"," improves CI/automation ergonomics: the installation command now runs truly non-interactive for scripted environments, and static analysis warnings are cleaned up.",[347,20969,350],{"id":20970},"key-highlights-57",[352,20972,20973,20978],{},[293,20974,20975],{},[308,20976,20977],{},"Install Command: Non-Interactive Mode",[415,20979,20980,20992],{},[418,20981,20982,20985,20986,332,20988,2000,20990,299],{},[325,20983,20984],{},"php glueful install"," skips the environment confirmation prompt when any of these flags are present: ",[325,20987,4646],{},[325,20989,14554],{},[325,20991,6470],{},[418,20993,20994,20995,20997],{},"Keeps helpful output; add Symfony's global ",[325,20996,4616],{}," if you want near-silent runs.",[347,20999,20170],{"id":21000},"whats-changed-3",[415,21002,21003,21016],{},[418,21004,21005,21006,21009,21010,332,21012,2000,21014,299],{},"Unattended installs: skip ",[325,21007,21008],{},"Have you set all required environment variables?"," when running with ",[325,21011,4646],{},[325,21013,14554],{},[325,21015,6470],{},[418,21017,21018,21019,21022,21023,21026],{},"DX: remove redundant ",[325,21020,21021],{},"method_exists()"," check around ",[325,21024,21025],{},"InputInterface::isInteractive()"," to satisfy PHPStan.",[347,21028,9391],{"id":21029},"quick-usage-11",[428,21031,21033],{"className":430,"code":21032,"language":432,"meta":320,"style":320},"# CI-safe, non-interactive install\nphp glueful install --quiet --force\n\n# Or use Symfony's global flag to reduce verbosity further\nphp glueful install --quiet --force -q\n",[325,21034,21035,21040,21052,21056,21061],{"__ignoreMap":320},[436,21036,21037],{"class":438,"line":439},[436,21038,21039],{"class":1168},"# CI-safe, non-interactive install\n",[436,21041,21042,21044,21046,21048,21050],{"class":438,"line":1132},[436,21043,1135],{"class":442},[436,21045,1138],{"class":446},[436,21047,20569],{"class":446},[436,21049,20572],{"class":5565},[436,21051,17382],{"class":5565},[436,21053,21054],{"class":438,"line":1158},[436,21055,5212],{"emptyLinePlaceholder":5211},[436,21057,21058],{"class":438,"line":5196},[436,21059,21060],{"class":1168},"# Or use Symfony's global flag to reduce verbosity further\n",[436,21062,21063,21065,21067,21069,21071,21073],{"class":438,"line":5202},[436,21064,1135],{"class":442},[436,21066,1138],{"class":446},[436,21068,20569],{"class":446},[436,21070,20572],{"class":5565},[436,21072,16297],{"class":5565},[436,21074,21075],{"class":5565}," -q\n",[347,21077,8199],{"id":21078},"migration-4",[415,21080,21081],{},[418,21082,21083,21084,21087],{},"No action required. For CI pipelines, prefer ",[325,21085,21086],{},"--quiet --force"," to avoid prompts.",[452,21089],{},[301,21091,21093],{"id":21092},"v130-deneb","v1.3.0 - Deneb",[293,21095,21096],{},[308,21097,21098],{},"Released: October 6, 2025",[312,21100,21101],{"color":3075,"icon":19227,"variant":316},[318,21102,21103],{"v-slot:description":320},[293,21104,21105,21108],{},[308,21106,21107],{},"Deneb"," refines the HTTP client with first-class, configurable retries via Symfony's retry system, improving resilience and clarity for API integrations.",[347,21110,350],{"id":21111},"key-highlights-58",[352,21113,21114,21119],{},[293,21115,21116],{},[308,21117,21118],{},"HTTP Client Retry Support",[415,21120,21121,21124,21131],{},[418,21122,21123],{},"Automatic retry logic with configurable strategies",[418,21125,21126,21127,21130],{},"Built on Symfony's ",[325,21128,21129],{},"RetryableHttpClient"," for production-ready reliability",[418,21132,21133],{},"Sensible defaults for common scenarios (payments, external APIs)",[347,21135,21137],{"id":21136},"whats-new","What's New",[415,21139,21140,21150,21176],{},[418,21141,21142,21145,21146,21149],{},[308,21143,21144],{},"Retry Configuration API",": New ",[325,21147,21148],{},"Client::withRetry(array $config)"," method to wrap any configured client with retry logic",[418,21151,21152,21155,21156],{},[308,21153,21154],{},"ApiClientBuilder Enhancements",":\n",[415,21157,21158,21164,21170],{},[418,21159,21160,21163],{},[325,21161,21162],{},"retries()"," - Configure retry behavior",[418,21165,21166,21169],{},[325,21167,21168],{},"buildWithRetries()"," - Build client with retries enabled",[418,21171,21172,21175],{},[325,21173,21174],{},"getRetryConfig()"," - Inspect retry configuration",[418,21177,21178,21181],{},[308,21179,21180],{},"Smart Defaults",": Preset retry configurations for payments and external service integrations",[347,21183,21185],{"id":21184},"code-example","Code Example",[428,21187,21189],{"className":5139,"code":21188,"language":1135,"meta":320,"style":320},"use Glueful\\Http\\Client;\nuse Glueful\\Http\\Builders\\ApiClientBuilder;\n\n// Configure retries with custom settings via DI + scoped client\n$client = app($context, Client::class)\n    ->createScopedClient(['base_uri' => 'https://api.example.com'])\n    ->withRetry([\n        'max_retries' => 3,\n        'delay_ms' => 1000,\n        'multiplier' => 2.0,\n        'status_codes' => [429, 500, 502, 503, 504],\n    ]);\n\n// Or use builder with presets\n$apiClient = (new ApiClientBuilder(app($context, Client::class)))\n    ->baseUri('https://payment-gateway.com')\n    ->forPayments()\n    ->buildWithRetries();\n",[325,21190,21191,21208,21230,21234,21239,21265,21291,21300,21315,21330,21350,21386,21391,21395,21400,21436,21454,21463],{"__ignoreMap":320},[436,21192,21193,21195,21197,21199,21201,21203,21206],{"class":438,"line":439},[436,21194,6516],{"class":5167},[436,21196,6520],{"class":6519},[436,21198,6524],{"class":6523},[436,21200,16726],{"class":6519},[436,21202,6524],{"class":6523},[436,21204,21205],{"class":6532},"Client",[436,21207,5816],{"class":5163},[436,21209,21210,21212,21214,21216,21218,21220,21223,21225,21228],{"class":438,"line":1132},[436,21211,6516],{"class":5167},[436,21213,6520],{"class":6519},[436,21215,6524],{"class":6523},[436,21217,16726],{"class":6519},[436,21219,6524],{"class":6523},[436,21221,21222],{"class":6519},"Builders",[436,21224,6524],{"class":6523},[436,21226,21227],{"class":6532},"ApiClientBuilder",[436,21229,5816],{"class":5163},[436,21231,21232],{"class":438,"line":1158},[436,21233,5212],{"emptyLinePlaceholder":5211},[436,21235,21236],{"class":438,"line":5196},[436,21237,21238],{"class":1168},"// Configure retries with custom settings via DI + scoped client\n",[436,21240,21241,21243,21246,21248,21250,21252,21254,21256,21259,21261,21263],{"class":438,"line":5202},[436,21242,5761],{"class":5163},[436,21244,21245],{"class":1151},"client ",[436,21247,3168],{"class":1144},[436,21249,7584],{"class":5159},[436,21251,5778],{"class":5163},[436,21253,6008],{"class":1151},[436,21255,5177],{"class":5163},[436,21257,21258],{"class":5233}," Client",[436,21260,6056],{"class":1144},[436,21262,6059],{"class":5167},[436,21264,5188],{"class":5163},[436,21266,21267,21269,21272,21274,21276,21279,21281,21283,21285,21287,21289],{"class":438,"line":5208},[436,21268,12789],{"class":1144},[436,21270,21271],{"class":5159},"createScopedClient",[436,21273,5990],{"class":5163},[436,21275,5282],{"class":5281},[436,21277,21278],{"class":446},"base_uri",[436,21280,5282],{"class":5281},[436,21282,6000],{"class":1144},[436,21284,6064],{"class":5281},[436,21286,8734],{"class":446},[436,21288,5282],{"class":5281},[436,21290,12784],{"class":5163},[436,21292,21293,21295,21298],{"class":438,"line":5215},[436,21294,12789],{"class":1144},[436,21296,21297],{"class":5159},"withRetry",[436,21299,16057],{"class":5163},[436,21301,21302,21304,21307,21309,21311,21313],{"class":438,"line":5221},[436,21303,9519],{"class":5281},[436,21305,21306],{"class":446},"max_retries",[436,21308,5282],{"class":5281},[436,21310,6000],{"class":1144},[436,21312,15949],{"class":7256},[436,21314,6907],{"class":5163},[436,21316,21317,21319,21322,21324,21326,21328],{"class":438,"line":5249},[436,21318,9519],{"class":5281},[436,21320,21321],{"class":446},"delay_ms",[436,21323,5282],{"class":5281},[436,21325,6000],{"class":1144},[436,21327,12503],{"class":7256},[436,21329,6907],{"class":5163},[436,21331,21332,21334,21337,21339,21341,21344,21346,21348],{"class":438,"line":5254},[436,21333,9519],{"class":5281},[436,21335,21336],{"class":446},"multiplier",[436,21338,5282],{"class":5281},[436,21340,6000],{"class":1144},[436,21342,21343],{"class":7256}," 2",[436,21345,299],{"class":10170},[436,21347,3194],{"class":7256},[436,21349,6907],{"class":5163},[436,21351,21352,21354,21357,21359,21361,21363,21365,21367,21369,21371,21374,21376,21379,21381,21384],{"class":438,"line":5298},[436,21353,9519],{"class":5281},[436,21355,21356],{"class":446},"status_codes",[436,21358,5282],{"class":5281},[436,21360,6000],{"class":1144},[436,21362,6050],{"class":5163},[436,21364,18582],{"class":7256},[436,21366,5177],{"class":5163},[436,21368,12934],{"class":7256},[436,21370,5177],{"class":5163},[436,21372,21373],{"class":7256}," 502",[436,21375,5177],{"class":5163},[436,21377,21378],{"class":7256}," 503",[436,21380,5177],{"class":5163},[436,21382,21383],{"class":7256}," 504",[436,21385,9553],{"class":5163},[436,21387,21388],{"class":438,"line":5324},[436,21389,21390],{"class":5163},"    ]);\n",[436,21392,21393],{"class":438,"line":5329},[436,21394,5212],{"emptyLinePlaceholder":5211},[436,21396,21397],{"class":438,"line":6717},[436,21398,21399],{"class":1168},"// Or use builder with presets\n",[436,21401,21402,21404,21407,21409,21411,21413,21416,21418,21421,21423,21425,21427,21429,21431,21433],{"class":438,"line":6742},[436,21403,5761],{"class":5163},[436,21405,21406],{"class":1151},"apiClient ",[436,21408,3168],{"class":1144},[436,21410,388],{"class":5163},[436,21412,20670],{"class":5167},[436,21414,21415],{"class":5233}," ApiClientBuilder",[436,21417,5164],{"class":5163},[436,21419,21420],{"class":5159},"app",[436,21422,5778],{"class":5163},[436,21424,6008],{"class":1151},[436,21426,5177],{"class":5163},[436,21428,21258],{"class":5233},[436,21430,6056],{"class":1144},[436,21432,6059],{"class":5167},[436,21434,21435],{"class":5163},")))\n",[436,21437,21438,21440,21443,21445,21447,21450,21452],{"class":438,"line":6767},[436,21439,12789],{"class":1144},[436,21441,21442],{"class":5159},"baseUri",[436,21444,5164],{"class":5163},[436,21446,5282],{"class":5281},[436,21448,21449],{"class":446},"https://payment-gateway.com",[436,21451,5282],{"class":5281},[436,21453,5188],{"class":5163},[436,21455,21456,21458,21461],{"class":438,"line":6772},[436,21457,12789],{"class":1144},[436,21459,21460],{"class":5159},"forPayments",[436,21462,15928],{"class":5163},[436,21464,21465,21467,21470],{"class":438,"line":6778},[436,21466,12789],{"class":1144},[436,21468,21469],{"class":5159},"buildWithRetries",[436,21471,5321],{"class":5163},[347,21473,21475],{"id":21474},"additional-context","Additional Context",[293,21477,21478],{},"Underlying change: retry logic migrated from prior internal handling to Symfony's strategy model (status-based exponential backoff) improving observability and consistency.",[347,21480,21482],{"id":21481},"related-documentation","Related Documentation",[415,21484,21485,21491],{},[418,21486,21487],{},[297,21488,21490],{"href":21489},"/essentials/requests-responses#http-client","HTTP Client",[418,21492,21493],{},[297,21494,121],{"href":122},[452,21496],{},[301,21498,21500],{"id":21499},"v120-vega","v1.2.0 - Vega",[293,21502,21503],{},[308,21504,21505],{},"Released: September 23, 2025",[312,21507,21508],{"color":3075,"icon":19227,"variant":316},[318,21509,21510],{"v-slot:description":320},[293,21511,21512,21515],{},[308,21513,21514],{},"Vega"," introduces robust task management architecture and enhanced testing reliability. Named after one of the brightest stars in the night sky, this release brings enhanced reliability and clarity to task execution and framework testing infrastructure.",[347,21517,350],{"id":21518},"key-highlights-59",[352,21520,21521,21526],{},[293,21522,21523],{},[308,21524,21525],{},"Tasks/Jobs Architecture",[415,21527,21528,21531,21534],{},[418,21529,21530],{},"Clean separation of business logic (Tasks) from queue execution (Jobs)",[418,21532,21533],{},"Support for both direct execution and queued processing",[418,21535,21536],{},"Comprehensive task management system for common operations",[347,21538,21137],{"id":21539},"whats-new-1",[21541,21542,21544],"h4",{"id":21543},"task-management-system","Task Management System",[293,21546,21547],{},"New task classes for common maintenance operations:",[415,21549,21550,21556,21562,21568,21574],{},[418,21551,21552,21555],{},[325,21553,21554],{},"CacheMaintenanceTask"," - Comprehensive cache maintenance",[418,21557,21558,21561],{},[325,21559,21560],{},"DatabaseBackupTask"," - Automated backups with retention policies",[418,21563,21564,21567],{},[325,21565,21566],{},"LogCleanupTask"," - Log file cleanup",[418,21569,21570,21573],{},[325,21571,21572],{},"NotificationRetryTask"," - Retry failed notifications",[418,21575,21576,21579],{},[325,21577,21578],{},"SessionCleanupTask"," - Session maintenance",[21541,21581,21583],{"id":21582},"queue-job-wrappers","Queue Job Wrappers",[293,21585,21586],{},"Reliable queue integration with dedicated job classes:",[415,21588,21589,21600,21608],{},[418,21590,21591,332,21594,332,21597],{},[325,21592,21593],{},"CacheMaintenanceJob",[325,21595,21596],{},"DatabaseBackupJob",[325,21598,21599],{},"LogCleanupJob",[418,21601,21602,332,21605],{},[325,21603,21604],{},"NotificationRetryJob",[325,21606,21607],{},"SessionCleanupJob",[418,21609,21610],{},"Built-in failure handling and logging",[21541,21612,21614],{"id":21613},"enhanced-console-commands","Enhanced Console Commands",[428,21616,21618],{"className":430,"code":21617,"language":432,"meta":320,"style":320},"# New cache maintenance command with improved options\nphp glueful cache:maintenance --operation=clearExpiredKeys\n\n# Enqueue instead of running immediately\nphp glueful cache:maintenance --operation=fullCleanup --queue\n",[325,21619,21620,21625,21637,21641,21646],{"__ignoreMap":320},[436,21621,21622],{"class":438,"line":439},[436,21623,21624],{"class":1168},"# New cache maintenance command with improved options\n",[436,21626,21627,21629,21631,21634],{"class":438,"line":1132},[436,21628,1135],{"class":442},[436,21630,1138],{"class":446},[436,21632,21633],{"class":446}," cache:maintenance",[436,21635,21636],{"class":5565}," --operation=clearExpiredKeys\n",[436,21638,21639],{"class":438,"line":1158},[436,21640,5212],{"emptyLinePlaceholder":5211},[436,21642,21643],{"class":438,"line":5196},[436,21644,21645],{"class":1168},"# Enqueue instead of running immediately\n",[436,21647,21648,21650,21652,21654,21657],{"class":438,"line":5202},[436,21649,1135],{"class":442},[436,21651,1138],{"class":446},[436,21653,21633],{"class":446},[436,21655,21656],{"class":5565}," --operation=fullCleanup",[436,21658,14278],{"class":5565},[21541,21660,21662],{"id":21661},"comprehensive-testing-suite","Comprehensive Testing Suite",[415,21664,21665,21668,21671],{},[418,21666,21667],{},"Complete integration test coverage for all Tasks and Jobs",[418,21669,21670],{},"Enhanced test bootstrap with proper DI container management",[418,21672,21673],{},"Fixed test interference issues",[347,21675,21677],{"id":21676},"stability-fixes","Stability & Fixes",[415,21679,21680,21683],{},[418,21681,21682],{},"Improved container state isolation in tests.",[418,21684,21685],{},"Reduced interference between suites by refining bootstrap resets.",[347,21687,21689],{"id":21688},"removed-for-clarity","Removed (for clarity)",[415,21691,21692],{},[418,21693,21694],{},"Legacy Cron classes replaced by Tasks + Queue Jobs.",[347,21696,5129],{"id":21697},"migration-guide-1",[312,21699,21700],{"color":464,"icon":19227,"variant":316},[318,21701,21702],{"v-slot:description":320},[293,21703,21704,21706,21707,21710,21711,491,21714,4088],{},[308,21705,4676],{},": The ",[325,21708,21709],{},"src/Cron/"," directory has been removed in favor of the new ",[325,21712,21713],{},"src/Tasks/",[325,21715,21716],{},"src/Queue/Jobs/",[21541,21718,21720],{"id":21719},"step-1-update-namespace-imports","Step 1: Update Namespace Imports",[293,21722,21723],{},[308,21724,21725],{},"Before:",[428,21727,21729],{"className":5139,"code":21728,"language":1135,"meta":320,"style":320},"use Glueful\\Cron\\CacheMaintenance;\nuse Glueful\\Cron\\DatabaseBackup;\n",[325,21730,21731,21749],{"__ignoreMap":320},[436,21732,21733,21735,21737,21739,21742,21744,21747],{"class":438,"line":439},[436,21734,6516],{"class":5167},[436,21736,6520],{"class":6519},[436,21738,6524],{"class":6523},[436,21740,21741],{"class":6519},"Cron",[436,21743,6524],{"class":6523},[436,21745,21746],{"class":6532},"CacheMaintenance",[436,21748,5816],{"class":5163},[436,21750,21751,21753,21755,21757,21759,21761,21764],{"class":438,"line":1132},[436,21752,6516],{"class":5167},[436,21754,6520],{"class":6519},[436,21756,6524],{"class":6523},[436,21758,21741],{"class":6519},[436,21760,6524],{"class":6523},[436,21762,21763],{"class":6532},"DatabaseBackup",[436,21765,5816],{"class":5163},[293,21767,21768],{},[308,21769,21770],{},"After:",[428,21772,21774],{"className":5139,"code":21773,"language":1135,"meta":320,"style":320},"use Glueful\\Tasks\\CacheMaintenanceTask;\nuse Glueful\\Queue\\Jobs\\CacheMaintenanceJob;\n",[325,21775,21776,21793],{"__ignoreMap":320},[436,21777,21778,21780,21782,21784,21787,21789,21791],{"class":438,"line":439},[436,21779,6516],{"class":5167},[436,21781,6520],{"class":6519},[436,21783,6524],{"class":6523},[436,21785,21786],{"class":6519},"Tasks",[436,21788,6524],{"class":6523},[436,21790,21554],{"class":6532},[436,21792,5816],{"class":5163},[436,21794,21795,21797,21799,21801,21804,21806,21809,21811,21813],{"class":438,"line":1132},[436,21796,6516],{"class":5167},[436,21798,6520],{"class":6519},[436,21800,6524],{"class":6523},[436,21802,21803],{"class":6519},"Queue",[436,21805,6524],{"class":6523},[436,21807,21808],{"class":6519},"Jobs",[436,21810,6524],{"class":6523},[436,21812,21593],{"class":6532},[436,21814,5816],{"class":5163},[21541,21816,21818],{"id":21817},"step-2-update-service-registration","Step 2: Update Service Registration",[293,21820,21821],{},[308,21822,21725],{},[428,21824,21826],{"className":5139,"code":21825,"language":1135,"meta":320,"style":320},"// In your service provider\n$container->set('cron.cache', CacheMaintenance::class);\n",[325,21827,21828,21833],{"__ignoreMap":320},[436,21829,21830],{"class":438,"line":439},[436,21831,21832],{"class":1168},"// In your service provider\n",[436,21834,21835,21837,21840,21842,21845,21847,21849,21852,21854,21856,21859,21861,21863],{"class":438,"line":1132},[436,21836,5761],{"class":5163},[436,21838,21839],{"class":1151},"container",[436,21841,5269],{"class":1144},[436,21843,21844],{"class":5159},"set",[436,21846,5164],{"class":5163},[436,21848,5282],{"class":5281},[436,21850,21851],{"class":446},"cron.cache",[436,21853,5282],{"class":5281},[436,21855,5177],{"class":5163},[436,21857,21858],{"class":5233}," CacheMaintenance",[436,21860,6056],{"class":1144},[436,21862,6059],{"class":5167},[436,21864,5295],{"class":5163},[293,21866,21867],{},[308,21868,21770],{},[428,21870,21872],{"className":5139,"code":21871,"language":1135,"meta":320,"style":320},"// Tasks are auto-registered via TasksProvider\n// For queued execution, push the Job wrapper via QueueManager:\nuse Glueful\\Queue\\Jobs\\CacheMaintenanceJob;\nuse Glueful\\Queue\\QueueManager;\n\n$queue = app($context, QueueManager::class);\n$queue->push(CacheMaintenanceJob::class, ['operation' => 'clearExpiredKeys'], 'maintenance');\n",[325,21873,21874,21879,21884,21904,21921,21925,21951],{"__ignoreMap":320},[436,21875,21876],{"class":438,"line":439},[436,21877,21878],{"class":1168},"// Tasks are auto-registered via TasksProvider\n",[436,21880,21881],{"class":438,"line":1132},[436,21882,21883],{"class":1168},"// For queued execution, push the Job wrapper via QueueManager:\n",[436,21885,21886,21888,21890,21892,21894,21896,21898,21900,21902],{"class":438,"line":1158},[436,21887,6516],{"class":5167},[436,21889,6520],{"class":6519},[436,21891,6524],{"class":6523},[436,21893,21803],{"class":6519},[436,21895,6524],{"class":6523},[436,21897,21808],{"class":6519},[436,21899,6524],{"class":6523},[436,21901,21593],{"class":6532},[436,21903,5816],{"class":5163},[436,21905,21906,21908,21910,21912,21914,21916,21919],{"class":438,"line":5196},[436,21907,6516],{"class":5167},[436,21909,6520],{"class":6519},[436,21911,6524],{"class":6523},[436,21913,21803],{"class":6519},[436,21915,6524],{"class":6523},[436,21917,21918],{"class":6532},"QueueManager",[436,21920,5816],{"class":5163},[436,21922,21923],{"class":438,"line":5202},[436,21924,5212],{"emptyLinePlaceholder":5211},[436,21926,21927,21929,21932,21934,21936,21938,21940,21942,21945,21947,21949],{"class":438,"line":5208},[436,21928,5761],{"class":5163},[436,21930,21931],{"class":1151},"queue ",[436,21933,3168],{"class":1144},[436,21935,7584],{"class":5159},[436,21937,5778],{"class":5163},[436,21939,6008],{"class":1151},[436,21941,5177],{"class":5163},[436,21943,21944],{"class":5233}," QueueManager",[436,21946,6056],{"class":1144},[436,21948,6059],{"class":5167},[436,21950,5295],{"class":5163},[436,21952,21953,21955,21957,21959,21962,21964,21966,21968,21970,21972,21974,21976,21979,21981,21983,21985,21988,21990,21992,21994,21996,21998],{"class":438,"line":5215},[436,21954,5761],{"class":5163},[436,21956,11656],{"class":1151},[436,21958,5269],{"class":1144},[436,21960,21961],{"class":5159},"push",[436,21963,5164],{"class":5163},[436,21965,21593],{"class":5233},[436,21967,6056],{"class":1144},[436,21969,6059],{"class":5167},[436,21971,5177],{"class":5163},[436,21973,6050],{"class":5163},[436,21975,5282],{"class":5281},[436,21977,21978],{"class":446},"operation",[436,21980,5282],{"class":5281},[436,21982,6000],{"class":1144},[436,21984,6064],{"class":5281},[436,21986,21987],{"class":446},"clearExpiredKeys",[436,21989,5282],{"class":5281},[436,21991,20907],{"class":5163},[436,21993,6064],{"class":5281},[436,21995,4512],{"class":446},[436,21997,5282],{"class":5281},[436,21999,5295],{"class":5163},[21541,22001,22003],{"id":22002},"step-3-update-direct-execution","Step 3: Update Direct Execution",[293,22005,22006],{},[308,22007,21725],{},[428,22009,22011],{"className":5139,"code":22010,"language":1135,"meta":320,"style":320},"$cronJob = new CacheMaintenance();\n$cronJob->execute();\n",[325,22012,22013,22028],{"__ignoreMap":320},[436,22014,22015,22017,22020,22022,22024,22026],{"class":438,"line":439},[436,22016,5761],{"class":5163},[436,22018,22019],{"class":1151},"cronJob ",[436,22021,3168],{"class":1144},[436,22023,6551],{"class":5167},[436,22025,21858],{"class":5233},[436,22027,5321],{"class":5163},[436,22029,22030,22032,22035,22037,22040],{"class":438,"line":1132},[436,22031,5761],{"class":5163},[436,22033,22034],{"class":1151},"cronJob",[436,22036,5269],{"class":1144},[436,22038,22039],{"class":5159},"execute",[436,22041,5321],{"class":5163},[293,22043,22044],{},[308,22045,21770],{},[428,22047,22049],{"className":5139,"code":22048,"language":1135,"meta":320,"style":320},"/** @var CacheMaintenanceTask $task */\n$task = app($context, CacheMaintenanceTask::class);\n$task->handle(['driver' => 'redis', 'operation' => 'clearExpiredKeys']);\n",[325,22050,22051,22063,22088],{"__ignoreMap":320},[436,22052,22053,22055,22057,22060],{"class":438,"line":439},[436,22054,20742],{"class":1168},[436,22056,20746],{"class":20745},[436,22058,22059],{"class":20749}," CacheMaintenanceTask",[436,22061,22062],{"class":1168}," $task */\n",[436,22064,22065,22067,22070,22072,22074,22076,22078,22080,22082,22084,22086],{"class":438,"line":1132},[436,22066,5761],{"class":5163},[436,22068,22069],{"class":1151},"task ",[436,22071,3168],{"class":1144},[436,22073,7584],{"class":5159},[436,22075,5778],{"class":5163},[436,22077,6008],{"class":1151},[436,22079,5177],{"class":5163},[436,22081,22059],{"class":5233},[436,22083,6056],{"class":1144},[436,22085,6059],{"class":5167},[436,22087,5295],{"class":5163},[436,22089,22090,22092,22095,22097,22100,22102,22104,22106,22108,22110,22112,22115,22117,22119,22121,22123,22125,22127,22129,22131,22133],{"class":438,"line":1158},[436,22091,5761],{"class":5163},[436,22093,22094],{"class":1151},"task",[436,22096,5269],{"class":1144},[436,22098,22099],{"class":5159},"handle",[436,22101,5990],{"class":5163},[436,22103,5282],{"class":5281},[436,22105,10222],{"class":446},[436,22107,5282],{"class":5281},[436,22109,6000],{"class":1144},[436,22111,6064],{"class":5281},[436,22113,22114],{"class":446},"redis",[436,22116,5282],{"class":5281},[436,22118,5177],{"class":5163},[436,22120,6064],{"class":5281},[436,22122,21978],{"class":446},[436,22124,5282],{"class":5281},[436,22126,6000],{"class":1144},[436,22128,6064],{"class":5281},[436,22130,21987],{"class":446},[436,22132,5282],{"class":5281},[436,22134,6072],{"class":5163},[347,22136,21482],{"id":22137},"related-documentation-1",[415,22139,22140,22144,22149,22153],{},[418,22141,22142],{},[297,22143,101],{"href":102},[418,22145,22146],{},[297,22147,22148],{"href":110},"Scheduling",[418,22150,22151],{},[297,22152,145],{"href":146},[418,22154,22155],{},[297,22156,141],{"href":142},[452,22158],{},[301,22160,22162],{"id":22161},"v110-polaris","v1.1.0 - Polaris",[293,22164,22165],{},[308,22166,22167],{},"Released: September 22, 2025",[312,22169,22170],{"color":3075,"icon":19227,"variant":316},[318,22171,22172],{"v-slot:description":320},[293,22173,22174,22177],{},[308,22175,22176],{},"Polaris"," introduces comprehensive testing infrastructure and enhanced documentation to guide framework development. Like the North Star that guides navigation, this release provides developers with the tools and knowledge to build robust applications.",[347,22179,350],{"id":22180},"key-highlights-60",[352,22182,22183,22188],{},[293,22184,22185],{},[308,22186,22187],{},"Testing Infrastructure",[415,22189,22190,22197,22200],{},[418,22191,22192,22193,22196],{},"Base ",[325,22194,22195],{},"TestCase"," class for application-level tests",[418,22198,22199],{},"Framework state reset utilities for isolation",[418,22201,22202],{},"Expanded event system documentation",[347,22204,21137],{"id":22205},"whats-new-2",[415,22207,22208,22221,22227],{},[418,22209,22210,22213,22214,22216,22217,22220],{},[308,22211,22212],{},"Testing Utilities",": Base ",[325,22215,22195],{}," with container access (",[325,22218,22219],{},"$this->get()","), app boot, refresh support",[418,22222,22223,22226],{},[308,22224,22225],{},"Event Documentation",": Expanded conceptual and usage coverage (listeners, dispatch patterns)",[418,22228,22229,22232,22233,332,22235,22238],{},[308,22230,22231],{},"(Planned / Pending)"," Event abstraction & HTTP helper methods (e.g. ",[325,22234,5099],{},[325,22236,22237],{},"assertStatus()",") — not yet present in current codebase; will appear in a future minor.",[347,22240,22242],{"id":22241},"example-current-capabilities","Example (Current Capabilities)",[428,22244,22246],{"className":5139,"code":22245,"language":1135,"meta":320,"style":320},"use Glueful\\Testing\\TestCase;\n\nfinal class UserLifecycleTest extends TestCase\n{\n    public function test_boots_application(): void\n    {\n        $this->assertNotNull($this->app());\n        $this->assertTrue($this->has(\\Glueful\\Logging\\LogManager::class));\n    }\n}\n",[325,22247,22248,22264,22268,22284,22288,22303,22307,22328,22367,22371],{"__ignoreMap":320},[436,22249,22250,22252,22254,22256,22258,22260,22262],{"class":438,"line":439},[436,22251,6516],{"class":5167},[436,22253,6520],{"class":6519},[436,22255,6524],{"class":6523},[436,22257,145],{"class":6519},[436,22259,6524],{"class":6523},[436,22261,22195],{"class":6532},[436,22263,5816],{"class":5163},[436,22265,22266],{"class":438,"line":1132},[436,22267,5212],{"emptyLinePlaceholder":5211},[436,22269,22270,22273,22276,22279,22281],{"class":438,"line":1158},[436,22271,22272],{"class":5152},"final",[436,22274,22275],{"class":5155}," class",[436,22277,22278],{"class":9486}," UserLifecycleTest",[436,22280,9490],{"class":5152},[436,22282,22283],{"class":9493}," TestCase\n",[436,22285,22286],{"class":438,"line":5196},[436,22287,5193],{"class":5163},[436,22289,22290,22292,22294,22297,22299,22301],{"class":438,"line":5202},[436,22291,11170],{"class":5152},[436,22293,5156],{"class":5155},[436,22295,22296],{"class":5159}," test_boots_application",[436,22298,7677],{"class":5163},[436,22300,5243],{"class":1144},[436,22302,16029],{"class":5167},[436,22304,22305],{"class":438,"line":5208},[436,22306,11187],{"class":5163},[436,22308,22309,22312,22314,22317,22319,22321,22323,22325],{"class":438,"line":5215},[436,22310,22311],{"class":5769},"        $this",[436,22313,5269],{"class":1144},[436,22315,22316],{"class":5159},"assertNotNull",[436,22318,5164],{"class":5163},[436,22320,4084],{"class":5769},[436,22322,5269],{"class":1144},[436,22324,21420],{"class":5159},[436,22326,22327],{"class":5163},"());\n",[436,22329,22330,22332,22334,22337,22339,22341,22343,22345,22347,22349,22352,22354,22356,22358,22360,22362,22364],{"class":438,"line":5221},[436,22331,22311],{"class":5769},[436,22333,5269],{"class":1144},[436,22335,22336],{"class":5159},"assertTrue",[436,22338,5164],{"class":5163},[436,22340,4084],{"class":5769},[436,22342,5269],{"class":1144},[436,22344,15935],{"class":5159},[436,22346,5164],{"class":5163},[436,22348,6524],{"class":6523},[436,22350,22351],{"class":6519},"Glueful",[436,22353,6524],{"class":6523},[436,22355,161],{"class":6519},[436,22357,6524],{"class":6523},[436,22359,3000],{"class":5233},[436,22361,6056],{"class":1144},[436,22363,6059],{"class":5167},[436,22365,22366],{"class":5163},"));\n",[436,22368,22369],{"class":438,"line":5249},[436,22370,11205],{"class":5163},[436,22372,22373],{"class":438,"line":5254},[436,22374,5205],{"class":5163},[22376,22377,22378],"blockquote",{},[293,22379,22380,22381,373,22384,22387],{},"Helpers like ",[325,22382,22383],{},"$this->post()",[325,22385,22386],{},"$this->assertStatus()"," will be documented once implemented; they are intentionally omitted here to avoid confusion.",[347,22389,21482],{"id":22390},"related-documentation-2",[415,22392,22393,22397],{},[418,22394,22395],{},[297,22396,145],{"href":146},[418,22398,22399],{},[297,22400,22401],{"href":86},"Events",[452,22403],{},[301,22405,22407],{"id":22406},"v100-aurora","v1.0.0 - Aurora",[293,22409,22410],{},[308,22411,22412],{},"Released: September 20, 2025",[312,22414,22415],{"color":314,"icon":19227,"variant":316},[318,22416,22417],{"v-slot:description":320},[293,22418,22419,22422],{},[308,22420,22421],{},"Aurora"," — The first stable release of the split Glueful Framework package. This version establishes the framework runtime as a standalone library with comprehensive features and sets a clear baseline for future 1.x releases.",[347,22424,350],{"id":22425},"key-highlights-61",[352,22427,22428,22433],{},[293,22429,22430],{},[308,22431,22432],{},"Major Features",[415,22434,22435,22438,22441,22444,22447,22450],{},[418,22436,22437],{},"Custom Dependency Injection system (DSL + compiled container)",[418,22439,22440],{},"Permissions & authorization layer",[418,22442,22443],{},"Observability & metrics (profiling + middleware)",[418,22445,22446],{},"Security middleware suite (auth, rate limiting, CSRF, headers, guards)",[418,22448,22449],{},"File upload pipeline (validation, S3, signed URLs)",[418,22451,22452],{},"Extensions system v2 (deterministic provider discovery)",[347,22454,21137],{"id":22455},"whats-new-3",[21541,22457,6018],{"id":5983},[415,22459,22460,22463,22472,22475],{},[418,22461,22462],{},"Fast static/dynamic matching with first-segment bucketing",[418,22464,22465,22466,332,22469,4979],{},"Attribute-based route definitions (",[325,22467,22468],{},"#[Get]",[325,22470,22471],{},"#[Post]",[418,22473,22474],{},"Route cache compiler with automatic invalidation",[418,22476,22477],{},"Standardized JSON errors for 404/405",[428,22479,22481],{"className":5139,"code":22480,"language":1135,"meta":320,"style":320},"use Glueful\\Routing\\Attributes\\{Get, Post};\n\nclass UserController\n{\n    #[Get('/users/{id}')]\n    public function show(int $id): Response\n    {\n        // Route automatically registered\n    }\n\n    #[Post('/users')]\n    public function create(Request $request): Response\n    {\n        // POST /users\n    }\n}\n",[325,22482,22483,22510,22514,22520,22524,22542,22566,22570,22575,22579,22583,22602,22625,22629,22634,22638],{"__ignoreMap":320},[436,22484,22485,22487,22489,22491,22493,22495,22497,22499,22501,22504,22506,22508],{"class":438,"line":439},[436,22486,6516],{"class":5167},[436,22488,6520],{"class":6519},[436,22490,6524],{"class":6523},[436,22492,33],{"class":6519},[436,22494,6524],{"class":6523},[436,22496,12206],{"class":6519},[436,22498,6524],{"class":6523},[436,22500,7230],{"class":5163},[436,22502,22503],{"class":6532},"Get",[436,22505,5177],{"class":5163},[436,22507,17171],{"class":6532},[436,22509,12439],{"class":5163},[436,22511,22512],{"class":438,"line":1132},[436,22513,5212],{"emptyLinePlaceholder":5211},[436,22515,22516,22518],{"class":438,"line":1158},[436,22517,6059],{"class":5155},[436,22519,12450],{"class":9486},[436,22521,22522],{"class":438,"line":5196},[436,22523,5193],{"class":5163},[436,22525,22526,22528,22530,22532,22534,22536,22538,22540],{"class":438,"line":5202},[436,22527,12464],{"class":1151},[436,22529,22503],{"class":6519},[436,22531,5164],{"class":5163},[436,22533,5282],{"class":5281},[436,22535,808],{"class":446},[436,22537,5282],{"class":5281},[436,22539,4887],{"class":5163},[436,22541,11896],{"class":1151},[436,22543,22544,22546,22548,22551,22553,22556,22558,22560,22562,22564],{"class":438,"line":5208},[436,22545,11170],{"class":5152},[436,22547,5156],{"class":5155},[436,22549,22550],{"class":5159}," show",[436,22552,5164],{"class":5163},[436,22554,22555],{"class":5167},"int",[436,22557,5171],{"class":5163},[436,22559,1822],{"class":1151},[436,22561,4887],{"class":5163},[436,22563,5243],{"class":1144},[436,22565,5246],{"class":5233},[436,22567,22568],{"class":438,"line":5215},[436,22569,11187],{"class":5163},[436,22571,22572],{"class":438,"line":5221},[436,22573,22574],{"class":1168},"        // Route automatically registered\n",[436,22576,22577],{"class":438,"line":5249},[436,22578,11205],{"class":5163},[436,22580,22581],{"class":438,"line":5254},[436,22582,5212],{"emptyLinePlaceholder":5211},[436,22584,22585,22587,22589,22591,22593,22596,22598,22600],{"class":438,"line":5298},[436,22586,12464],{"class":1151},[436,22588,18035],{"class":6519},[436,22590,5164],{"class":5163},[436,22592,5282],{"class":5281},[436,22594,22595],{"class":446},"/users",[436,22597,5282],{"class":5281},[436,22599,4887],{"class":5163},[436,22601,11896],{"class":1151},[436,22603,22604,22606,22608,22611,22613,22615,22617,22619,22621,22623],{"class":438,"line":5324},[436,22605,11170],{"class":5152},[436,22607,5156],{"class":5155},[436,22609,22610],{"class":5159}," create",[436,22612,5164],{"class":5163},[436,22614,5013],{"class":5233},[436,22616,5171],{"class":5163},[436,22618,5238],{"class":1151},[436,22620,4887],{"class":5163},[436,22622,5243],{"class":1144},[436,22624,5246],{"class":5233},[436,22626,22627],{"class":438,"line":5329},[436,22628,11187],{"class":5163},[436,22630,22631],{"class":438,"line":6717},[436,22632,22633],{"class":1168},"        // POST /users\n",[436,22635,22636],{"class":438,"line":6742},[436,22637,11205],{"class":5163},[436,22639,22640],{"class":438,"line":6767},[436,22641,5205],{"class":5163},[21541,22643,22645],{"id":22644},"dependency-injection-overhaul","Dependency Injection Overhaul",[415,22647,22648,22651,22654],{},[418,22649,22650],{},"Custom lightweight container optimized for Glueful",[418,22652,22653],{},"DSL for service registration with compile-time generation",[418,22655,22656],{},"Compiled container support for faster production startup",[428,22658,22660],{"className":5139,"code":22659,"language":1135,"meta":320,"style":320},"// Typical application bootstrap (dev/prod aware)\nuse Glueful\\Container\\Bootstrap\\ContainerFactory;\n\n$container = ContainerFactory::create(prod: false); // prod:true enables compilation path\n\n// Overriding / adding a service at runtime (e.g. during tests)\n$testContainer = $container->with([\n    'fake.clock' => fn() => new \\Glueful\\Support\\Clock\\FrozenClock('2025-10-08T00:00:00Z'),\n]);\n\n// Accessing a service\n$logger = $testContainer->get('logger');\n\n// Defining services in a Provider (preferred for framework + extensions)\nuse Glueful\\Container\\Providers\\BaseServiceProvider;\nuse Glueful\\Container\\Definition\\FactoryDefinition;\n\nfinal class PaymentProvider extends BaseServiceProvider\n{\n    public function defs(): array\n    {\n        return [\n            // FactoryDefinition gives you full control\n            'payment.client' => new FactoryDefinition('payment.client', function(\\Psr\\Container\\ContainerInterface $c) {\n                return new PaymentClient($c->get('http.client'), baseUrl: config($context, 'payments.base_url'));\n            }),\n            // Simple autowire helper (shared by default)\n            PaymentService::class => $this->autowire(PaymentService::class),\n        ];\n    }\n}\n",[325,22661,22662,22667,22689,22693,22724,22728,22733,22752,22803,22807,22811,22816,22845,22849,22854,22876,22898,22902,22916,22920,22935,22939,22945,22950,23002,23053,23058,23063,23092,23096,23100],{"__ignoreMap":320},[436,22663,22664],{"class":438,"line":439},[436,22665,22666],{"class":1168},"// Typical application bootstrap (dev/prod aware)\n",[436,22668,22669,22671,22673,22675,22678,22680,22683,22685,22687],{"class":438,"line":1132},[436,22670,6516],{"class":5167},[436,22672,6520],{"class":6519},[436,22674,6524],{"class":6523},[436,22676,22677],{"class":6519},"Container",[436,22679,6524],{"class":6523},[436,22681,22682],{"class":6519},"Bootstrap",[436,22684,6524],{"class":6523},[436,22686,20310],{"class":6532},[436,22688,5816],{"class":5163},[436,22690,22691],{"class":438,"line":1158},[436,22692,5212],{"emptyLinePlaceholder":5211},[436,22694,22695,22697,22700,22702,22705,22707,22709,22711,22714,22716,22718,22721],{"class":438,"line":5196},[436,22696,5761],{"class":5163},[436,22698,22699],{"class":1151},"container ",[436,22701,3168],{"class":1144},[436,22703,22704],{"class":5233}," ContainerFactory",[436,22706,6056],{"class":1144},[436,22708,15860],{"class":5159},[436,22710,5164],{"class":5163},[436,22712,22713],{"class":6659},"prod",[436,22715,5243],{"class":5163},[436,22717,10171],{"class":10170},[436,22719,22720],{"class":5163},");",[436,22722,22723],{"class":1168}," // prod:true enables compilation path\n",[436,22725,22726],{"class":438,"line":5202},[436,22727,5212],{"emptyLinePlaceholder":5211},[436,22729,22730],{"class":438,"line":5208},[436,22731,22732],{"class":1168},"// Overriding / adding a service at runtime (e.g. during tests)\n",[436,22734,22735,22737,22740,22742,22744,22746,22748,22750],{"class":438,"line":5215},[436,22736,5761],{"class":5163},[436,22738,22739],{"class":1151},"testContainer ",[436,22741,3168],{"class":1144},[436,22743,5171],{"class":5163},[436,22745,21839],{"class":1151},[436,22747,5269],{"class":1144},[436,22749,17176],{"class":5159},[436,22751,16057],{"class":5163},[436,22753,22754,22756,22759,22761,22763,22766,22768,22770,22772,22775,22777,22779,22782,22784,22787,22789,22792,22794,22796,22799,22801],{"class":438,"line":5221},[436,22755,6862],{"class":5281},[436,22757,22758],{"class":446},"fake.clock",[436,22760,5282],{"class":5281},[436,22762,6000],{"class":1144},[436,22764,22765],{"class":5155}," fn",[436,22767,7677],{"class":5163},[436,22769,6000],{"class":5163},[436,22771,6551],{"class":5167},[436,22773,22774],{"class":6523}," \\",[436,22776,22351],{"class":6519},[436,22778,6524],{"class":6523},[436,22780,22781],{"class":6519},"Support",[436,22783,6524],{"class":6523},[436,22785,22786],{"class":6519},"Clock",[436,22788,6524],{"class":6523},[436,22790,22791],{"class":5233},"FrozenClock",[436,22793,5164],{"class":5163},[436,22795,5282],{"class":5281},[436,22797,22798],{"class":446},"2025-10-08T00:00:00Z",[436,22800,5282],{"class":5281},[436,22802,10248],{"class":5163},[436,22804,22805],{"class":438,"line":5249},[436,22806,6072],{"class":5163},[436,22808,22809],{"class":438,"line":5254},[436,22810,5212],{"emptyLinePlaceholder":5211},[436,22812,22813],{"class":438,"line":5298},[436,22814,22815],{"class":1168},"// Accessing a service\n",[436,22817,22818,22820,22823,22825,22827,22830,22832,22834,22836,22838,22841,22843],{"class":438,"line":5324},[436,22819,5761],{"class":5163},[436,22821,22822],{"class":1151},"logger ",[436,22824,3168],{"class":1144},[436,22826,5171],{"class":5163},[436,22828,22829],{"class":1151},"testContainer",[436,22831,5269],{"class":1144},[436,22833,715],{"class":5159},[436,22835,5164],{"class":5163},[436,22837,5282],{"class":5281},[436,22839,22840],{"class":446},"logger",[436,22842,5282],{"class":5281},[436,22844,5295],{"class":5163},[436,22846,22847],{"class":438,"line":5329},[436,22848,5212],{"emptyLinePlaceholder":5211},[436,22850,22851],{"class":438,"line":6717},[436,22852,22853],{"class":1168},"// Defining services in a Provider (preferred for framework + extensions)\n",[436,22855,22856,22858,22860,22862,22864,22866,22869,22871,22874],{"class":438,"line":6742},[436,22857,6516],{"class":5167},[436,22859,6520],{"class":6519},[436,22861,6524],{"class":6523},[436,22863,22677],{"class":6519},[436,22865,6524],{"class":6523},[436,22867,22868],{"class":6519},"Providers",[436,22870,6524],{"class":6523},[436,22872,22873],{"class":6532},"BaseServiceProvider",[436,22875,5816],{"class":5163},[436,22877,22878,22880,22882,22884,22886,22888,22891,22893,22896],{"class":438,"line":6767},[436,22879,6516],{"class":5167},[436,22881,6520],{"class":6519},[436,22883,6524],{"class":6523},[436,22885,22677],{"class":6519},[436,22887,6524],{"class":6523},[436,22889,22890],{"class":6519},"Definition",[436,22892,6524],{"class":6523},[436,22894,22895],{"class":6532},"FactoryDefinition",[436,22897,5816],{"class":5163},[436,22899,22900],{"class":438,"line":6772},[436,22901,5212],{"emptyLinePlaceholder":5211},[436,22903,22904,22906,22908,22911,22913],{"class":438,"line":6778},[436,22905,22272],{"class":5152},[436,22907,22275],{"class":5155},[436,22909,22910],{"class":9486}," PaymentProvider",[436,22912,9490],{"class":5152},[436,22914,22915],{"class":9493}," BaseServiceProvider\n",[436,22917,22918],{"class":438,"line":6810},[436,22919,5193],{"class":5163},[436,22921,22922,22924,22926,22929,22931,22933],{"class":438,"line":9754},[436,22923,11170],{"class":5152},[436,22925,5156],{"class":5155},[436,22927,22928],{"class":5159}," defs",[436,22930,7677],{"class":5163},[436,22932,5243],{"class":1144},[436,22934,11225],{"class":5167},[436,22936,22937],{"class":438,"line":9801},[436,22938,11187],{"class":5163},[436,22940,22941,22943],{"class":438,"line":9806},[436,22942,11192],{"class":5788},[436,22944,6857],{"class":5163},[436,22946,22947],{"class":438,"line":9812},[436,22948,22949],{"class":1168},"            // FactoryDefinition gives you full control\n",[436,22951,22952,22954,22957,22959,22961,22963,22966,22968,22970,22972,22974,22976,22978,22980,22982,22985,22987,22989,22991,22993,22995,22998,23000],{"class":438,"line":9825},[436,22953,10331],{"class":5281},[436,22955,22956],{"class":446},"payment.client",[436,22958,5282],{"class":5281},[436,22960,6000],{"class":1144},[436,22962,6551],{"class":5167},[436,22964,22965],{"class":5233}," FactoryDefinition",[436,22967,5164],{"class":5163},[436,22969,5282],{"class":5281},[436,22971,22956],{"class":446},[436,22973,5282],{"class":5281},[436,22975,5177],{"class":5163},[436,22977,5156],{"class":5155},[436,22979,5164],{"class":5163},[436,22981,6524],{"class":6523},[436,22983,22984],{"class":6519},"Psr",[436,22986,6524],{"class":6523},[436,22988,22677],{"class":6519},[436,22990,6524],{"class":6523},[436,22992,4724],{"class":5233},[436,22994,5171],{"class":5163},[436,22996,22997],{"class":1151},"c",[436,22999,4887],{"class":5163},[436,23001,5803],{"class":5163},[436,23003,23004,23007,23009,23012,23014,23016,23018,23020,23022,23024,23027,23029,23031,23034,23036,23038,23040,23042,23044,23046,23049,23051],{"class":438,"line":9830},[436,23005,23006],{"class":5788},"                return",[436,23008,6551],{"class":5167},[436,23010,23011],{"class":5233}," PaymentClient",[436,23013,5778],{"class":5163},[436,23015,22997],{"class":1151},[436,23017,5269],{"class":1144},[436,23019,715],{"class":5159},[436,23021,5164],{"class":5163},[436,23023,5282],{"class":5281},[436,23025,23026],{"class":446},"http.client",[436,23028,5282],{"class":5281},[436,23030,6883],{"class":5163},[436,23032,23033],{"class":6659}," baseUrl",[436,23035,5243],{"class":5163},[436,23037,7561],{"class":5159},[436,23039,5778],{"class":5163},[436,23041,6008],{"class":1151},[436,23043,5177],{"class":5163},[436,23045,6064],{"class":5281},[436,23047,23048],{"class":446},"payments.base_url",[436,23050,5282],{"class":5281},[436,23052,22366],{"class":5163},[436,23054,23055],{"class":438,"line":9841},[436,23056,23057],{"class":5163},"            }),\n",[436,23059,23060],{"class":438,"line":9846},[436,23061,23062],{"class":1168},"            // Simple autowire helper (shared by default)\n",[436,23064,23065,23068,23070,23072,23074,23076,23078,23081,23083,23086,23088,23090],{"class":438,"line":9887},[436,23066,23067],{"class":5233},"            PaymentService",[436,23069,6056],{"class":1144},[436,23071,6059],{"class":5167},[436,23073,6000],{"class":1144},[436,23075,5770],{"class":5769},[436,23077,5269],{"class":1144},[436,23079,23080],{"class":5159},"autowire",[436,23082,5164],{"class":5163},[436,23084,23085],{"class":5233},"PaymentService",[436,23087,6056],{"class":1144},[436,23089,6059],{"class":5167},[436,23091,10248],{"class":5163},[436,23093,23094],{"class":438,"line":9892},[436,23095,15761],{"class":5163},[436,23097,23098],{"class":438,"line":9897},[436,23099,11205],{"class":5163},[436,23101,23102],{"class":438,"line":9903},[436,23103,5205],{"class":5163},[22376,23105,23106],{},[293,23107,23108,23109,23112,23113,299],{},"Service registration happens through Provider ",[325,23110,23111],{},"defs()"," returning definitions; runtime overrides use ",[325,23114,23115],{},"$container->with([...])",[21541,23117,23119],{"id":23118},"security-enhancements","Security Enhancements",[293,23121,23122],{},"New middleware suite:",[415,23124,23125,23128,23130,23133,23136,23139],{},[418,23126,23127],{},"Authentication & Authorization",[418,23129,105],{},[418,23131,23132],{},"CSRF Protection",[418,23134,23135],{},"Security Headers",[418,23137,23138],{},"Admin Guard",[418,23140,23141],{},"IP Allow-listing",[293,23143,23144],{},"New CLI security commands:",[428,23146,23148],{"className":430,"code":23147,"language":432,"meta":320,"style":320},"php glueful security:check\nphp glueful security:scan\nphp glueful security:vulnerabilities\n",[325,23149,23150,23159,23168],{"__ignoreMap":320},[436,23151,23152,23154,23156],{"class":438,"line":439},[436,23153,1135],{"class":442},[436,23155,1138],{"class":446},[436,23157,23158],{"class":446}," security:check\n",[436,23160,23161,23163,23165],{"class":438,"line":1132},[436,23162,1135],{"class":442},[436,23164,1138],{"class":446},[436,23166,23167],{"class":446}," security:scan\n",[436,23169,23170,23172,23174],{"class":438,"line":1158},[436,23171,1135],{"class":442},[436,23173,1138],{"class":446},[436,23175,23176],{"class":446}," security:vulnerabilities\n",[21541,23178,23180],{"id":23179},"file-upload-system","File Upload System",[415,23182,23183,23190,23193,23196,23199],{},[418,23184,23185,23186,23189],{},"Native Symfony ",[325,23187,23188],{},"UploadedFile"," support",[418,23191,23192],{},"Extension and MIME validation",[418,23194,23195],{},"Hazard scanning for security",[418,23197,23198],{},"S3 storage with signed URLs",[418,23200,23201],{},"Configurable ACL (private by default)",[428,23203,23205],{"className":5139,"code":23204,"language":1135,"meta":320,"style":320},"use Glueful\\Uploader\\FileUploader;\n\n// Upload using the framework uploader (validates and stores metadata)\n$uploader = app($context, FileUploader::class);\n$result = $uploader->handleUpload(\n    $token,                   // your upload token / CSRF guard\n    ['user_id' => $userId, 'key' => 'document'],\n    $request->files->all()    // or $_FILES\n);\n\n// $result contains: ['uuid' => '...', 'url' => 'https://...']\n// To create a presigned link for a known path on S3:\n// $signedUrl = app($context, Glueful\\Uploader\\Storage\\FlysystemStorage::class)\n//     ->getSignedUrl('documents/example.pdf', 3600);\n",[325,23206,23207,23223,23227,23232,23256,23275,23287,23323,23343,23347,23351,23356,23361,23366],{"__ignoreMap":320},[436,23208,23209,23211,23213,23215,23217,23219,23221],{"class":438,"line":439},[436,23210,6516],{"class":5167},[436,23212,6520],{"class":6519},[436,23214,6524],{"class":6523},[436,23216,7950],{"class":6519},[436,23218,6524],{"class":6523},[436,23220,7955],{"class":6532},[436,23222,5816],{"class":5163},[436,23224,23225],{"class":438,"line":1132},[436,23226,5212],{"emptyLinePlaceholder":5211},[436,23228,23229],{"class":438,"line":1158},[436,23230,23231],{"class":1168},"// Upload using the framework uploader (validates and stores metadata)\n",[436,23233,23234,23236,23238,23240,23242,23244,23246,23248,23250,23252,23254],{"class":438,"line":5196},[436,23235,5761],{"class":5163},[436,23237,7968],{"class":1151},[436,23239,3168],{"class":1144},[436,23241,7584],{"class":5159},[436,23243,5778],{"class":5163},[436,23245,6008],{"class":1151},[436,23247,5177],{"class":5163},[436,23249,7975],{"class":5233},[436,23251,6056],{"class":1144},[436,23253,6059],{"class":5167},[436,23255,5295],{"class":5163},[436,23257,23258,23260,23262,23264,23266,23268,23270,23273],{"class":438,"line":5202},[436,23259,5761],{"class":5163},[436,23261,7989],{"class":1151},[436,23263,3168],{"class":1144},[436,23265,5171],{"class":5163},[436,23267,7996],{"class":1151},[436,23269,5269],{"class":1144},[436,23271,23272],{"class":5159},"handleUpload",[436,23274,6925],{"class":5163},[436,23276,23277,23279,23282,23284],{"class":438,"line":5208},[436,23278,5257],{"class":5163},[436,23280,23281],{"class":1151},"token",[436,23283,5177],{"class":5163},[436,23285,23286],{"class":1168},"                   // your upload token / CSRF guard\n",[436,23288,23289,23291,23293,23296,23298,23300,23302,23304,23306,23308,23310,23312,23314,23316,23319,23321],{"class":438,"line":5215},[436,23290,11096],{"class":5163},[436,23292,5282],{"class":5281},[436,23294,23295],{"class":446},"user_id",[436,23297,5282],{"class":5281},[436,23299,6000],{"class":1144},[436,23301,5171],{"class":5163},[436,23303,18817],{"class":1151},[436,23305,5177],{"class":5163},[436,23307,6064],{"class":5281},[436,23309,341],{"class":446},[436,23311,5282],{"class":5281},[436,23313,6000],{"class":1144},[436,23315,6064],{"class":5281},[436,23317,23318],{"class":446},"document",[436,23320,5282],{"class":5281},[436,23322,9553],{"class":5163},[436,23324,23325,23327,23329,23331,23334,23336,23338,23340],{"class":438,"line":5221},[436,23326,5257],{"class":5163},[436,23328,5238],{"class":1151},[436,23330,5269],{"class":1144},[436,23332,23333],{"class":1151},"files",[436,23335,5269],{"class":1144},[436,23337,3354],{"class":5159},[436,23339,7677],{"class":5163},[436,23341,23342],{"class":1168},"    // or $_FILES\n",[436,23344,23345],{"class":438,"line":5249},[436,23346,5295],{"class":5163},[436,23348,23349],{"class":438,"line":5254},[436,23350,5212],{"emptyLinePlaceholder":5211},[436,23352,23353],{"class":438,"line":5298},[436,23354,23355],{"class":1168},"// $result contains: ['uuid' => '...', 'url' => 'https://...']\n",[436,23357,23358],{"class":438,"line":5324},[436,23359,23360],{"class":1168},"// To create a presigned link for a known path on S3:\n",[436,23362,23363],{"class":438,"line":5329},[436,23364,23365],{"class":1168},"// $signedUrl = app($context, Glueful\\Uploader\\Storage\\FlysystemStorage::class)\n",[436,23367,23368],{"class":438,"line":6717},[436,23369,23370],{"class":1168},"//     ->getSignedUrl('documents/example.pdf', 3600);\n",[21541,23372,23374],{"id":23373},"observability-metrics","Observability & Metrics",[415,23376,23377,23383,23389,23395],{},[418,23378,23379,23382],{},[325,23380,23381],{},"BootProfiler"," for startup timing analysis",[418,23384,23385,23388],{},[325,23386,23387],{},"MetricsMiddleware"," for request tracking",[418,23390,23391,23394],{},[325,23392,23393],{},"ApiMetricsService"," for API analytics",[418,23396,23397],{},"Pluggable tracing middleware",[21541,23399,23401],{"id":23400},"extensions-system-v2","Extensions System v2",[415,23403,23404,23407,23410],{},[418,23405,23406],{},"Deterministic provider discovery",[418,23408,23409],{},"App providers + vendor extensions unified",[418,23411,23412],{},"Extension service compilation for better performance",[347,23414,5129],{"id":23415},"migration-guide-2",[312,23417,23418],{"color":3480,"icon":19227,"variant":316},[318,23419,23420],{"v-slot:description":320},[293,23421,23422,23424],{},[308,23423,4676],{},": This release includes significant architectural changes. Please review carefully before upgrading.",[21541,23426,23428],{"id":23427},"_1-dependency-injection-container","1. Dependency Injection Container",[293,23430,23431],{},"The framework now uses a custom DI container instead of Symfony DI.",[293,23433,23434],{},[308,23435,21725],{},[428,23437,23439],{"className":5139,"code":23438,"language":1135,"meta":320,"style":320},"use Symfony\\Component\\DependencyInjection\\ContainerBuilder;\n\n$container = new ContainerBuilder();\n$container->register('my.service', MyService::class);\n",[325,23440,23441,23465,23469,23484],{"__ignoreMap":320},[436,23442,23443,23445,23448,23450,23453,23455,23458,23460,23463],{"class":438,"line":439},[436,23444,6516],{"class":5167},[436,23446,23447],{"class":6519}," Symfony",[436,23449,6524],{"class":6523},[436,23451,23452],{"class":6519},"Component",[436,23454,6524],{"class":6523},[436,23456,23457],{"class":6519},"DependencyInjection",[436,23459,6524],{"class":6523},[436,23461,23462],{"class":6532},"ContainerBuilder",[436,23464,5816],{"class":5163},[436,23466,23467],{"class":438,"line":1132},[436,23468,5212],{"emptyLinePlaceholder":5211},[436,23470,23471,23473,23475,23477,23479,23482],{"class":438,"line":1158},[436,23472,5761],{"class":5163},[436,23474,22699],{"class":1151},[436,23476,3168],{"class":1144},[436,23478,6551],{"class":5167},[436,23480,23481],{"class":5233}," ContainerBuilder",[436,23483,5321],{"class":5163},[436,23485,23486,23488,23490,23492,23494,23496,23498,23501,23503,23505,23507,23509,23511],{"class":438,"line":5196},[436,23487,5761],{"class":5163},[436,23489,21839],{"class":1151},[436,23491,5269],{"class":1144},[436,23493,6108],{"class":5159},[436,23495,5164],{"class":5163},[436,23497,5282],{"class":5281},[436,23499,23500],{"class":446},"my.service",[436,23502,5282],{"class":5281},[436,23504,5177],{"class":5163},[436,23506,7647],{"class":5233},[436,23508,6056],{"class":1144},[436,23510,6059],{"class":5167},[436,23512,5295],{"class":5163},[293,23514,23515],{},[308,23516,21770],{},[428,23518,23520],{"className":5139,"code":23519,"language":1135,"meta":320,"style":320},"// Create container (typically done via ContainerFactory in bootstrap)\nuse Glueful\\Container\\Bootstrap\\ContainerFactory;\n\n$container = ContainerFactory::create(prod: false); // prod:true enables compilation\n\n// Runtime service override (e.g., in tests)\n$container = $container->with([\n    'my.service' => fn($c) => new MyService($c->get('dependency')),\n]);\n\n// Or define services in a Provider (recommended for extensions/framework services)\nuse Glueful\\Container\\Providers\\BaseServiceProvider;\nuse Glueful\\Container\\Definition\\FactoryDefinition;\n\nfinal class MyServiceProvider extends BaseServiceProvider\n{\n    public function defs(): array\n    {\n        return [\n            // Factory definition\n            'my.service' => new FactoryDefinition('my.service', function($c) {\n                return new MyService($c->get('dependency'));\n            }),\n            // Or autowire\n            MyService::class => $this->autowire(MyService::class),\n        ];\n    }\n}\n",[325,23521,23522,23527,23547,23551,23578,23582,23587,23605,23649,23653,23657,23662,23682,23702,23706,23719,23723,23737,23741,23747,23752,23786,23812,23816,23821,23848,23852,23856],{"__ignoreMap":320},[436,23523,23524],{"class":438,"line":439},[436,23525,23526],{"class":1168},"// Create container (typically done via ContainerFactory in bootstrap)\n",[436,23528,23529,23531,23533,23535,23537,23539,23541,23543,23545],{"class":438,"line":1132},[436,23530,6516],{"class":5167},[436,23532,6520],{"class":6519},[436,23534,6524],{"class":6523},[436,23536,22677],{"class":6519},[436,23538,6524],{"class":6523},[436,23540,22682],{"class":6519},[436,23542,6524],{"class":6523},[436,23544,20310],{"class":6532},[436,23546,5816],{"class":5163},[436,23548,23549],{"class":438,"line":1158},[436,23550,5212],{"emptyLinePlaceholder":5211},[436,23552,23553,23555,23557,23559,23561,23563,23565,23567,23569,23571,23573,23575],{"class":438,"line":5196},[436,23554,5761],{"class":5163},[436,23556,22699],{"class":1151},[436,23558,3168],{"class":1144},[436,23560,22704],{"class":5233},[436,23562,6056],{"class":1144},[436,23564,15860],{"class":5159},[436,23566,5164],{"class":5163},[436,23568,22713],{"class":6659},[436,23570,5243],{"class":5163},[436,23572,10171],{"class":10170},[436,23574,22720],{"class":5163},[436,23576,23577],{"class":1168}," // prod:true enables compilation\n",[436,23579,23580],{"class":438,"line":5202},[436,23581,5212],{"emptyLinePlaceholder":5211},[436,23583,23584],{"class":438,"line":5208},[436,23585,23586],{"class":1168},"// Runtime service override (e.g., in tests)\n",[436,23588,23589,23591,23593,23595,23597,23599,23601,23603],{"class":438,"line":5215},[436,23590,5761],{"class":5163},[436,23592,22699],{"class":1151},[436,23594,3168],{"class":1144},[436,23596,5171],{"class":5163},[436,23598,21839],{"class":1151},[436,23600,5269],{"class":1144},[436,23602,17176],{"class":5159},[436,23604,16057],{"class":5163},[436,23606,23607,23609,23611,23613,23615,23617,23619,23621,23623,23625,23627,23629,23631,23633,23635,23637,23639,23641,23644,23646],{"class":438,"line":5221},[436,23608,6862],{"class":5281},[436,23610,23500],{"class":446},[436,23612,5282],{"class":5281},[436,23614,6000],{"class":1144},[436,23616,22765],{"class":5155},[436,23618,5778],{"class":5163},[436,23620,22997],{"class":1151},[436,23622,4887],{"class":5163},[436,23624,6000],{"class":5163},[436,23626,6551],{"class":5167},[436,23628,7647],{"class":5233},[436,23630,5778],{"class":5163},[436,23632,22997],{"class":1151},[436,23634,5269],{"class":1144},[436,23636,715],{"class":5159},[436,23638,5164],{"class":5163},[436,23640,5282],{"class":5281},[436,23642,23643],{"class":446},"dependency",[436,23645,5282],{"class":5281},[436,23647,23648],{"class":5163},")),\n",[436,23650,23651],{"class":438,"line":5249},[436,23652,6072],{"class":5163},[436,23654,23655],{"class":438,"line":5254},[436,23656,5212],{"emptyLinePlaceholder":5211},[436,23658,23659],{"class":438,"line":5298},[436,23660,23661],{"class":1168},"// Or define services in a Provider (recommended for extensions/framework services)\n",[436,23663,23664,23666,23668,23670,23672,23674,23676,23678,23680],{"class":438,"line":5324},[436,23665,6516],{"class":5167},[436,23667,6520],{"class":6519},[436,23669,6524],{"class":6523},[436,23671,22677],{"class":6519},[436,23673,6524],{"class":6523},[436,23675,22868],{"class":6519},[436,23677,6524],{"class":6523},[436,23679,22873],{"class":6532},[436,23681,5816],{"class":5163},[436,23683,23684,23686,23688,23690,23692,23694,23696,23698,23700],{"class":438,"line":5329},[436,23685,6516],{"class":5167},[436,23687,6520],{"class":6519},[436,23689,6524],{"class":6523},[436,23691,22677],{"class":6519},[436,23693,6524],{"class":6523},[436,23695,22890],{"class":6519},[436,23697,6524],{"class":6523},[436,23699,22895],{"class":6532},[436,23701,5816],{"class":5163},[436,23703,23704],{"class":438,"line":6717},[436,23705,5212],{"emptyLinePlaceholder":5211},[436,23707,23708,23710,23712,23715,23717],{"class":438,"line":6742},[436,23709,22272],{"class":5152},[436,23711,22275],{"class":5155},[436,23713,23714],{"class":9486}," MyServiceProvider",[436,23716,9490],{"class":5152},[436,23718,22915],{"class":9493},[436,23720,23721],{"class":438,"line":6767},[436,23722,5193],{"class":5163},[436,23724,23725,23727,23729,23731,23733,23735],{"class":438,"line":6772},[436,23726,11170],{"class":5152},[436,23728,5156],{"class":5155},[436,23730,22928],{"class":5159},[436,23732,7677],{"class":5163},[436,23734,5243],{"class":1144},[436,23736,11225],{"class":5167},[436,23738,23739],{"class":438,"line":6778},[436,23740,11187],{"class":5163},[436,23742,23743,23745],{"class":438,"line":6810},[436,23744,11192],{"class":5788},[436,23746,6857],{"class":5163},[436,23748,23749],{"class":438,"line":9754},[436,23750,23751],{"class":1168},"            // Factory definition\n",[436,23753,23754,23756,23758,23760,23762,23764,23766,23768,23770,23772,23774,23776,23778,23780,23782,23784],{"class":438,"line":9801},[436,23755,10331],{"class":5281},[436,23757,23500],{"class":446},[436,23759,5282],{"class":5281},[436,23761,6000],{"class":1144},[436,23763,6551],{"class":5167},[436,23765,22965],{"class":5233},[436,23767,5164],{"class":5163},[436,23769,5282],{"class":5281},[436,23771,23500],{"class":446},[436,23773,5282],{"class":5281},[436,23775,5177],{"class":5163},[436,23777,5156],{"class":5155},[436,23779,5778],{"class":5163},[436,23781,22997],{"class":1151},[436,23783,4887],{"class":5163},[436,23785,5803],{"class":5163},[436,23787,23788,23790,23792,23794,23796,23798,23800,23802,23804,23806,23808,23810],{"class":438,"line":9806},[436,23789,23006],{"class":5788},[436,23791,6551],{"class":5167},[436,23793,7647],{"class":5233},[436,23795,5778],{"class":5163},[436,23797,22997],{"class":1151},[436,23799,5269],{"class":1144},[436,23801,715],{"class":5159},[436,23803,5164],{"class":5163},[436,23805,5282],{"class":5281},[436,23807,23643],{"class":446},[436,23809,5282],{"class":5281},[436,23811,22366],{"class":5163},[436,23813,23814],{"class":438,"line":9812},[436,23815,23057],{"class":5163},[436,23817,23818],{"class":438,"line":9825},[436,23819,23820],{"class":1168},"            // Or autowire\n",[436,23822,23823,23826,23828,23830,23832,23834,23836,23838,23840,23842,23844,23846],{"class":438,"line":9830},[436,23824,23825],{"class":5233},"            MyService",[436,23827,6056],{"class":1144},[436,23829,6059],{"class":5167},[436,23831,6000],{"class":1144},[436,23833,5770],{"class":5769},[436,23835,5269],{"class":1144},[436,23837,23080],{"class":5159},[436,23839,5164],{"class":5163},[436,23841,7589],{"class":5233},[436,23843,6056],{"class":1144},[436,23845,6059],{"class":5167},[436,23847,10248],{"class":5163},[436,23849,23850],{"class":438,"line":9841},[436,23851,15761],{"class":5163},[436,23853,23854],{"class":438,"line":9846},[436,23855,11205],{"class":5163},[436,23857,23858],{"class":438,"line":9887},[436,23859,5205],{"class":5163},[21541,23861,23863],{"id":23862},"_2-event-system-psr-14","2. Event System (PSR-14)",[293,23865,23866],{},"Event system migrated from custom implementation to PSR-14.",[293,23868,23869],{},[308,23870,21725],{},[428,23872,23874],{"className":5139,"code":23873,"language":1135,"meta":320,"style":320},"$events->listen('user.created', function($event) {\n    // Handle event\n});\n",[325,23875,23876,23908,23913],{"__ignoreMap":320},[436,23877,23878,23880,23883,23885,23888,23890,23892,23894,23896,23898,23900,23902,23904,23906],{"class":438,"line":439},[436,23879,5761],{"class":5163},[436,23881,23882],{"class":1151},"events",[436,23884,5269],{"class":1144},[436,23886,23887],{"class":5159},"listen",[436,23889,5164],{"class":5163},[436,23891,5282],{"class":5281},[436,23893,11041],{"class":446},[436,23895,5282],{"class":5281},[436,23897,5177],{"class":5163},[436,23899,5156],{"class":5155},[436,23901,5778],{"class":5163},[436,23903,11377],{"class":1151},[436,23905,4887],{"class":5163},[436,23907,5803],{"class":5163},[436,23909,23910],{"class":438,"line":1132},[436,23911,23912],{"class":1168},"    // Handle event\n",[436,23914,23915],{"class":438,"line":1158},[436,23916,6157],{"class":5163},[293,23918,23919],{},[308,23920,21770],{},[428,23922,23924],{"className":5139,"code":23923,"language":1135,"meta":320,"style":320},"use Psr\\EventDispatcher\\EventDispatcherInterface;\nuse Glueful\\Events\\Contracts\\BaseEvent;\nuse Glueful\\Events\\ListenerProvider;\n\nclass UserCreated extends BaseEvent\n{\n    public function __construct(public User $user) {}\n}\n\n// Register listener via ListenerProvider\n$provider = app($context, ListenerProvider::class);\n$provider->addListener(UserCreated::class, function (UserCreated $event) {\n    // Handle event\n});\n\n// Dispatch via PSR-14 dispatcher\n$dispatcher = app($context, EventDispatcherInterface::class);\n$dispatcher->dispatch(new UserCreated($user));\n",[325,23925,23926,23945,23967,23984,23988,23998,24002,24026,24030,24034,24039,24065,24101,24105,24109,24113,24118,24144],{"__ignoreMap":320},[436,23927,23928,23930,23933,23935,23938,23940,23943],{"class":438,"line":439},[436,23929,6516],{"class":5167},[436,23931,23932],{"class":6519}," Psr",[436,23934,6524],{"class":6523},[436,23936,23937],{"class":6519},"EventDispatcher",[436,23939,6524],{"class":6523},[436,23941,23942],{"class":6532},"EventDispatcherInterface",[436,23944,5816],{"class":5163},[436,23946,23947,23949,23951,23953,23955,23957,23960,23962,23965],{"class":438,"line":1132},[436,23948,6516],{"class":5167},[436,23950,6520],{"class":6519},[436,23952,6524],{"class":6523},[436,23954,22401],{"class":6519},[436,23956,6524],{"class":6523},[436,23958,23959],{"class":6519},"Contracts",[436,23961,6524],{"class":6523},[436,23963,23964],{"class":6532},"BaseEvent",[436,23966,5816],{"class":5163},[436,23968,23969,23971,23973,23975,23977,23979,23982],{"class":438,"line":1158},[436,23970,6516],{"class":5167},[436,23972,6520],{"class":6519},[436,23974,6524],{"class":6523},[436,23976,22401],{"class":6519},[436,23978,6524],{"class":6523},[436,23980,23981],{"class":6532},"ListenerProvider",[436,23983,5816],{"class":5163},[436,23985,23986],{"class":438,"line":5196},[436,23987,5212],{"emptyLinePlaceholder":5211},[436,23989,23990,23992,23994,23996],{"class":438,"line":5202},[436,23991,6059],{"class":5155},[436,23993,11143],{"class":9486},[436,23995,9490],{"class":5152},[436,23997,11148],{"class":9493},[436,23999,24000],{"class":438,"line":5208},[436,24001,5193],{"class":5163},[436,24003,24004,24006,24008,24011,24013,24015,24017,24019,24021,24023],{"class":438,"line":5215},[436,24005,11170],{"class":5152},[436,24007,5156],{"class":5155},[436,24009,24010],{"class":6921}," __construct",[436,24012,5164],{"class":5163},[436,24014,4794],{"class":5152},[436,24016,9817],{"class":5233},[436,24018,5171],{"class":5163},[436,24020,11052],{"class":1151},[436,24022,4887],{"class":5163},[436,24024,24025],{"class":5163}," {}\n",[436,24027,24028],{"class":438,"line":5221},[436,24029,5205],{"class":5163},[436,24031,24032],{"class":438,"line":5249},[436,24033,5212],{"emptyLinePlaceholder":5211},[436,24035,24036],{"class":438,"line":5254},[436,24037,24038],{"class":1168},"// Register listener via ListenerProvider\n",[436,24040,24041,24043,24046,24048,24050,24052,24054,24056,24059,24061,24063],{"class":438,"line":5298},[436,24042,5761],{"class":5163},[436,24044,24045],{"class":1151},"provider ",[436,24047,3168],{"class":1144},[436,24049,7584],{"class":5159},[436,24051,5778],{"class":5163},[436,24053,6008],{"class":1151},[436,24055,5177],{"class":5163},[436,24057,24058],{"class":5233}," ListenerProvider",[436,24060,6056],{"class":1144},[436,24062,6059],{"class":5167},[436,24064,5295],{"class":5163},[436,24066,24067,24069,24071,24073,24076,24078,24081,24083,24085,24087,24089,24091,24093,24095,24097,24099],{"class":438,"line":5324},[436,24068,5761],{"class":5163},[436,24070,3605],{"class":1151},[436,24072,5269],{"class":1144},[436,24074,24075],{"class":5159},"addListener",[436,24077,5164],{"class":5163},[436,24079,24080],{"class":5233},"UserCreated",[436,24082,6056],{"class":1144},[436,24084,6059],{"class":5167},[436,24086,5177],{"class":5163},[436,24088,5156],{"class":5155},[436,24090,388],{"class":5163},[436,24092,24080],{"class":5233},[436,24094,5171],{"class":5163},[436,24096,11377],{"class":1151},[436,24098,4887],{"class":5163},[436,24100,5803],{"class":5163},[436,24102,24103],{"class":438,"line":5329},[436,24104,23912],{"class":1168},[436,24106,24107],{"class":438,"line":6717},[436,24108,6157],{"class":5163},[436,24110,24111],{"class":438,"line":6742},[436,24112,5212],{"emptyLinePlaceholder":5211},[436,24114,24115],{"class":438,"line":6767},[436,24116,24117],{"class":1168},"// Dispatch via PSR-14 dispatcher\n",[436,24119,24120,24122,24125,24127,24129,24131,24133,24135,24138,24140,24142],{"class":438,"line":6772},[436,24121,5761],{"class":5163},[436,24123,24124],{"class":1151},"dispatcher ",[436,24126,3168],{"class":1144},[436,24128,7584],{"class":5159},[436,24130,5778],{"class":5163},[436,24132,6008],{"class":1151},[436,24134,5177],{"class":5163},[436,24136,24137],{"class":5233}," EventDispatcherInterface",[436,24139,6056],{"class":1144},[436,24141,6059],{"class":5167},[436,24143,5295],{"class":5163},[436,24145,24146,24148,24151,24153,24155,24157,24159,24161,24163,24165],{"class":438,"line":6778},[436,24147,5761],{"class":5163},[436,24149,24150],{"class":1151},"dispatcher",[436,24152,5269],{"class":1144},[436,24154,11034],{"class":5159},[436,24156,5164],{"class":5163},[436,24158,20670],{"class":5167},[436,24160,11143],{"class":5233},[436,24162,5778],{"class":5163},[436,24164,11052],{"class":1151},[436,24166,22366],{"class":5163},[21541,24168,24170],{"id":24169},"_3-storage-configuration","3. Storage Configuration",[293,24172,24173],{},"Migrated to Flysystem with updated configuration structure.",[293,24175,24176],{},[308,24177,21725],{},[428,24179,24181],{"className":5139,"code":24180,"language":1135,"meta":320,"style":320},"// config/storage.php\nreturn [\n    's3' => [\n        'key' => env('AWS_KEY'),\n        'secret' => env('AWS_SECRET'),\n    ]\n];\n",[325,24182,24183,24188,24194,24207,24230,24254,24259],{"__ignoreMap":320},[436,24184,24185],{"class":438,"line":439},[436,24186,24187],{"class":1168},"// config/storage.php\n",[436,24189,24190,24192],{"class":438,"line":1132},[436,24191,5830],{"class":5788},[436,24193,6857],{"class":5163},[436,24195,24196,24198,24201,24203,24205],{"class":438,"line":1158},[436,24197,6862],{"class":5281},[436,24199,24200],{"class":446},"s3",[436,24202,5282],{"class":5281},[436,24204,6000],{"class":1144},[436,24206,6857],{"class":5163},[436,24208,24209,24211,24213,24215,24217,24219,24221,24223,24226,24228],{"class":438,"line":5196},[436,24210,9519],{"class":5281},[436,24212,341],{"class":446},[436,24214,5282],{"class":5281},[436,24216,6000],{"class":1144},[436,24218,6871],{"class":5159},[436,24220,5164],{"class":5163},[436,24222,5282],{"class":5281},[436,24224,24225],{"class":446},"AWS_KEY",[436,24227,5282],{"class":5281},[436,24229,10248],{"class":5163},[436,24231,24232,24234,24237,24239,24241,24243,24245,24247,24250,24252],{"class":438,"line":5202},[436,24233,9519],{"class":5281},[436,24235,24236],{"class":446},"secret",[436,24238,5282],{"class":5281},[436,24240,6000],{"class":1144},[436,24242,6871],{"class":5159},[436,24244,5164],{"class":5163},[436,24246,5282],{"class":5281},[436,24248,24249],{"class":446},"AWS_SECRET",[436,24251,5282],{"class":5281},[436,24253,10248],{"class":5163},[436,24255,24256],{"class":438,"line":5208},[436,24257,24258],{"class":5163},"    ]\n",[436,24260,24261],{"class":438,"line":5215},[436,24262,6968],{"class":5163},[293,24264,24265],{},[308,24266,21770],{},[428,24268,24270],{"className":5139,"code":24269,"language":1135,"meta":320,"style":320},"// config/storage.php\nreturn [\n    's3' => [\n        'driver' => 's3',\n        'key' => env('S3_ACCESS_KEY_ID'),\n        'secret' => env('S3_SECRET_ACCESS_KEY'),\n        'region' => env('S3_REGION', 'us-east-1'),\n        'bucket' => env('S3_BUCKET'),\n        'endpoint' => env('S3_ENDPOINT'),\n        'use_path_style_endpoint' => true,\n\n        // Optional behavior hints\n        'acl' => env('S3_ACL', 'private'),\n        'signed_urls' => env('S3_SIGNED_URLS', true),\n        'signed_ttl' => (int) env('S3_SIGNED_URL_TTL', 3600),\n        'cdn_base_url' => env('S3_CDN_BASE_URL'),\n    ],\n];\n",[325,24271,24272,24276,24282,24294,24312,24335,24358,24391,24415,24439,24454,24458,24463,24495,24523,24558,24582,24586],{"__ignoreMap":320},[436,24273,24274],{"class":438,"line":439},[436,24275,24187],{"class":1168},[436,24277,24278,24280],{"class":438,"line":1132},[436,24279,5830],{"class":5788},[436,24281,6857],{"class":5163},[436,24283,24284,24286,24288,24290,24292],{"class":438,"line":1158},[436,24285,6862],{"class":5281},[436,24287,24200],{"class":446},[436,24289,5282],{"class":5281},[436,24291,6000],{"class":1144},[436,24293,6857],{"class":5163},[436,24295,24296,24298,24300,24302,24304,24306,24308,24310],{"class":438,"line":5196},[436,24297,9519],{"class":5281},[436,24299,10222],{"class":446},[436,24301,5282],{"class":5281},[436,24303,6000],{"class":1144},[436,24305,6064],{"class":5281},[436,24307,24200],{"class":446},[436,24309,5282],{"class":5281},[436,24311,6907],{"class":5163},[436,24313,24314,24316,24318,24320,24322,24324,24326,24328,24331,24333],{"class":438,"line":5202},[436,24315,9519],{"class":5281},[436,24317,341],{"class":446},[436,24319,5282],{"class":5281},[436,24321,6000],{"class":1144},[436,24323,6871],{"class":5159},[436,24325,5164],{"class":5163},[436,24327,5282],{"class":5281},[436,24329,24330],{"class":446},"S3_ACCESS_KEY_ID",[436,24332,5282],{"class":5281},[436,24334,10248],{"class":5163},[436,24336,24337,24339,24341,24343,24345,24347,24349,24351,24354,24356],{"class":438,"line":5208},[436,24338,9519],{"class":5281},[436,24340,24236],{"class":446},[436,24342,5282],{"class":5281},[436,24344,6000],{"class":1144},[436,24346,6871],{"class":5159},[436,24348,5164],{"class":5163},[436,24350,5282],{"class":5281},[436,24352,24353],{"class":446},"S3_SECRET_ACCESS_KEY",[436,24355,5282],{"class":5281},[436,24357,10248],{"class":5163},[436,24359,24360,24362,24365,24367,24369,24371,24373,24375,24378,24380,24382,24384,24387,24389],{"class":438,"line":5215},[436,24361,9519],{"class":5281},[436,24363,24364],{"class":446},"region",[436,24366,5282],{"class":5281},[436,24368,6000],{"class":1144},[436,24370,6871],{"class":5159},[436,24372,5164],{"class":5163},[436,24374,5282],{"class":5281},[436,24376,24377],{"class":446},"S3_REGION",[436,24379,5282],{"class":5281},[436,24381,5177],{"class":5163},[436,24383,6064],{"class":5281},[436,24385,24386],{"class":446},"us-east-1",[436,24388,5282],{"class":5281},[436,24390,10248],{"class":5163},[436,24392,24393,24395,24398,24400,24402,24404,24406,24408,24411,24413],{"class":438,"line":5221},[436,24394,9519],{"class":5281},[436,24396,24397],{"class":446},"bucket",[436,24399,5282],{"class":5281},[436,24401,6000],{"class":1144},[436,24403,6871],{"class":5159},[436,24405,5164],{"class":5163},[436,24407,5282],{"class":5281},[436,24409,24410],{"class":446},"S3_BUCKET",[436,24412,5282],{"class":5281},[436,24414,10248],{"class":5163},[436,24416,24417,24419,24422,24424,24426,24428,24430,24432,24435,24437],{"class":438,"line":5249},[436,24418,9519],{"class":5281},[436,24420,24421],{"class":446},"endpoint",[436,24423,5282],{"class":5281},[436,24425,6000],{"class":1144},[436,24427,6871],{"class":5159},[436,24429,5164],{"class":5163},[436,24431,5282],{"class":5281},[436,24433,24434],{"class":446},"S3_ENDPOINT",[436,24436,5282],{"class":5281},[436,24438,10248],{"class":5163},[436,24440,24441,24443,24446,24448,24450,24452],{"class":438,"line":5254},[436,24442,9519],{"class":5281},[436,24444,24445],{"class":446},"use_path_style_endpoint",[436,24447,5282],{"class":5281},[436,24449,6000],{"class":1144},[436,24451,10187],{"class":10170},[436,24453,6907],{"class":5163},[436,24455,24456],{"class":438,"line":5298},[436,24457,5212],{"emptyLinePlaceholder":5211},[436,24459,24460],{"class":438,"line":5324},[436,24461,24462],{"class":1168},"        // Optional behavior hints\n",[436,24464,24465,24467,24470,24472,24474,24476,24478,24480,24483,24485,24487,24489,24491,24493],{"class":438,"line":5329},[436,24466,9519],{"class":5281},[436,24468,24469],{"class":446},"acl",[436,24471,5282],{"class":5281},[436,24473,6000],{"class":1144},[436,24475,6871],{"class":5159},[436,24477,5164],{"class":5163},[436,24479,5282],{"class":5281},[436,24481,24482],{"class":446},"S3_ACL",[436,24484,5282],{"class":5281},[436,24486,5177],{"class":5163},[436,24488,6064],{"class":5281},[436,24490,3824],{"class":446},[436,24492,5282],{"class":5281},[436,24494,10248],{"class":5163},[436,24496,24497,24499,24502,24504,24506,24508,24510,24512,24515,24517,24519,24521],{"class":438,"line":6717},[436,24498,9519],{"class":5281},[436,24500,24501],{"class":446},"signed_urls",[436,24503,5282],{"class":5281},[436,24505,6000],{"class":1144},[436,24507,6871],{"class":5159},[436,24509,5164],{"class":5163},[436,24511,5282],{"class":5281},[436,24513,24514],{"class":446},"S3_SIGNED_URLS",[436,24516,5282],{"class":5281},[436,24518,5177],{"class":5163},[436,24520,10187],{"class":10170},[436,24522,10248],{"class":5163},[436,24524,24525,24527,24530,24532,24534,24536,24538,24540,24542,24544,24546,24549,24551,24553,24556],{"class":438,"line":6742},[436,24526,9519],{"class":5281},[436,24528,24529],{"class":446},"signed_ttl",[436,24531,5282],{"class":5281},[436,24533,6000],{"class":1144},[436,24535,388],{"class":5163},[436,24537,22555],{"class":5155},[436,24539,4887],{"class":5163},[436,24541,6871],{"class":5159},[436,24543,5164],{"class":5163},[436,24545,5282],{"class":5281},[436,24547,24548],{"class":446},"S3_SIGNED_URL_TTL",[436,24550,5282],{"class":5281},[436,24552,5177],{"class":5163},[436,24554,24555],{"class":7256}," 3600",[436,24557,10248],{"class":5163},[436,24559,24560,24562,24565,24567,24569,24571,24573,24575,24578,24580],{"class":438,"line":6767},[436,24561,9519],{"class":5281},[436,24563,24564],{"class":446},"cdn_base_url",[436,24566,5282],{"class":5281},[436,24568,6000],{"class":1144},[436,24570,6871],{"class":5159},[436,24572,5164],{"class":5163},[436,24574,5282],{"class":5281},[436,24576,24577],{"class":446},"S3_CDN_BASE_URL",[436,24579,5282],{"class":5281},[436,24581,10248],{"class":5163},[436,24583,24584],{"class":438,"line":6772},[436,24585,10455],{"class":5163},[436,24587,24588],{"class":438,"line":6778},[436,24589,6968],{"class":5163},[21541,24591,24593],{"id":24592},"_4-environment-variable-updates","4. Environment Variable Updates",[293,24595,24596],{},"Several environment variables have been renamed for consistency:",[428,24598,24600],{"className":430,"code":24599,"language":432,"meta":320,"style":320},"# Redis\nREDIS_CACHE_DB → REDIS_DB\n\n# Mail\nMAIL_SECURE → MAIL_ENCRYPTION\n\n# Logging\nLOG_PATH → LOG_FILE_PATH\n# New: LOG_TO_DB=false (default)\n\n# S3 Storage\n# New variables:\nS3_ACL=private\nS3_SIGNED_URLS=true\nS3_SIGNED_URL_TTL=3600\n\n# PSR-15 Middleware\nPSR15_ENABLED=true\nPSR15_AUTO_DETECT=true\nPSR15_STRICT=false\n",[325,24601,24602,24607,24618,24622,24627,24637,24641,24646,24656,24661,24665,24670,24675,24684,24693,24702,24706,24711,24720,24729],{"__ignoreMap":320},[436,24603,24604],{"class":438,"line":439},[436,24605,24606],{"class":1168},"# Redis\n",[436,24608,24609,24612,24615],{"class":438,"line":1132},[436,24610,24611],{"class":442},"REDIS_CACHE_DB",[436,24613,24614],{"class":446}," →",[436,24616,24617],{"class":446}," REDIS_DB\n",[436,24619,24620],{"class":438,"line":1158},[436,24621,5212],{"emptyLinePlaceholder":5211},[436,24623,24624],{"class":438,"line":5196},[436,24625,24626],{"class":1168},"# Mail\n",[436,24628,24629,24632,24634],{"class":438,"line":5202},[436,24630,24631],{"class":442},"MAIL_SECURE",[436,24633,24614],{"class":446},[436,24635,24636],{"class":446}," MAIL_ENCRYPTION\n",[436,24638,24639],{"class":438,"line":5208},[436,24640,5212],{"emptyLinePlaceholder":5211},[436,24642,24643],{"class":438,"line":5215},[436,24644,24645],{"class":1168},"# Logging\n",[436,24647,24648,24651,24653],{"class":438,"line":5221},[436,24649,24650],{"class":442},"LOG_PATH",[436,24652,24614],{"class":446},[436,24654,24655],{"class":446}," LOG_FILE_PATH\n",[436,24657,24658],{"class":438,"line":5249},[436,24659,24660],{"class":1168},"# New: LOG_TO_DB=false (default)\n",[436,24662,24663],{"class":438,"line":5254},[436,24664,5212],{"emptyLinePlaceholder":5211},[436,24666,24667],{"class":438,"line":5298},[436,24668,24669],{"class":1168},"# S3 Storage\n",[436,24671,24672],{"class":438,"line":5324},[436,24673,24674],{"class":1168},"# New variables:\n",[436,24676,24677,24679,24681],{"class":438,"line":5329},[436,24678,24482],{"class":1151},[436,24680,3168],{"class":1144},[436,24682,24683],{"class":446},"private\n",[436,24685,24686,24688,24690],{"class":438,"line":6717},[436,24687,24514],{"class":1151},[436,24689,3168],{"class":1144},[436,24691,24692],{"class":446},"true\n",[436,24694,24695,24697,24699],{"class":438,"line":6742},[436,24696,24548],{"class":1151},[436,24698,3168],{"class":1144},[436,24700,24701],{"class":446},"3600\n",[436,24703,24704],{"class":438,"line":6767},[436,24705,5212],{"emptyLinePlaceholder":5211},[436,24707,24708],{"class":438,"line":6772},[436,24709,24710],{"class":1168},"# PSR-15 Middleware\n",[436,24712,24713,24716,24718],{"class":438,"line":6778},[436,24714,24715],{"class":1151},"PSR15_ENABLED",[436,24717,3168],{"class":1144},[436,24719,24692],{"class":446},[436,24721,24722,24725,24727],{"class":438,"line":6810},[436,24723,24724],{"class":1151},"PSR15_AUTO_DETECT",[436,24726,3168],{"class":1144},[436,24728,24692],{"class":446},[436,24730,24731,24734,24736],{"class":438,"line":9754},[436,24732,24733],{"class":1151},"PSR15_STRICT",[436,24735,3168],{"class":1144},[436,24737,24738],{"class":446},"false\n",[21541,24740,24742],{"id":24741},"_5-validation-system","5. Validation System",[293,24744,24745],{},"Moved to rules-based system with clearer composition.",[293,24747,24748],{},[308,24749,21725],{},[428,24751,24753],{"className":5139,"code":24752,"language":1135,"meta":320,"style":320},"$validator = new Validator([\n    'email' => 'required|email',\n]);\n",[325,24754,24755,24771,24789],{"__ignoreMap":320},[436,24756,24757,24759,24762,24764,24766,24769],{"class":438,"line":439},[436,24758,5761],{"class":5163},[436,24760,24761],{"class":1151},"validator ",[436,24763,3168],{"class":1144},[436,24765,6551],{"class":5167},[436,24767,24768],{"class":5233}," Validator",[436,24770,16057],{"class":5163},[436,24772,24773,24775,24777,24779,24781,24783,24785,24787],{"class":438,"line":1132},[436,24774,6862],{"class":5281},[436,24776,2688],{"class":446},[436,24778,5282],{"class":5281},[436,24780,6000],{"class":1144},[436,24782,6064],{"class":5281},[436,24784,18870],{"class":446},[436,24786,5282],{"class":5281},[436,24788,6907],{"class":5163},[436,24790,24791],{"class":438,"line":1158},[436,24792,6072],{"class":5163},[293,24794,24795],{},[308,24796,21770],{},[428,24798,24800],{"className":5139,"code":24799,"language":1135,"meta":320,"style":320},"use Glueful\\Validation\\Validator;\nuse Glueful\\Validation\\Rules\\{Required, Email};\n\n$validator = new Validator([\n    'email' => [new Required(), new Email()],\n]);\n\n$errors = $validator->validate($data);\n",[325,24801,24802,24819,24848,24852,24866,24893,24897,24901],{"__ignoreMap":320},[436,24803,24804,24806,24808,24810,24812,24814,24817],{"class":438,"line":439},[436,24805,6516],{"class":5167},[436,24807,6520],{"class":6519},[436,24809,6524],{"class":6523},[436,24811,57],{"class":6519},[436,24813,6524],{"class":6523},[436,24815,24816],{"class":6532},"Validator",[436,24818,5816],{"class":5163},[436,24820,24821,24823,24825,24827,24829,24831,24834,24836,24838,24841,24843,24846],{"class":438,"line":1132},[436,24822,6516],{"class":5167},[436,24824,6520],{"class":6519},[436,24826,6524],{"class":6523},[436,24828,57],{"class":6519},[436,24830,6524],{"class":6523},[436,24832,24833],{"class":6519},"Rules",[436,24835,6524],{"class":6523},[436,24837,7230],{"class":5163},[436,24839,24840],{"class":6532},"Required",[436,24842,5177],{"class":5163},[436,24844,24845],{"class":6532}," Email",[436,24847,12439],{"class":5163},[436,24849,24850],{"class":438,"line":1158},[436,24851,5212],{"emptyLinePlaceholder":5211},[436,24853,24854,24856,24858,24860,24862,24864],{"class":438,"line":5196},[436,24855,5761],{"class":5163},[436,24857,24761],{"class":1151},[436,24859,3168],{"class":1144},[436,24861,6551],{"class":5167},[436,24863,24768],{"class":5233},[436,24865,16057],{"class":5163},[436,24867,24868,24870,24872,24874,24876,24878,24880,24883,24886,24888,24890],{"class":438,"line":5202},[436,24869,6862],{"class":5281},[436,24871,2688],{"class":446},[436,24873,5282],{"class":5281},[436,24875,6000],{"class":1144},[436,24877,6050],{"class":5163},[436,24879,20670],{"class":5167},[436,24881,24882],{"class":5233}," Required",[436,24884,24885],{"class":5163},"(),",[436,24887,6551],{"class":5167},[436,24889,24845],{"class":5233},[436,24891,24892],{"class":5163},"()],\n",[436,24894,24895],{"class":438,"line":5208},[436,24896,6072],{"class":5163},[436,24898,24899],{"class":438,"line":5215},[436,24900,5212],{"emptyLinePlaceholder":5211},[436,24902,24903,24905,24908,24910,24912,24915,24917,24920,24922,24924],{"class":438,"line":5221},[436,24904,5761],{"class":5163},[436,24906,24907],{"class":1151},"errors ",[436,24909,3168],{"class":1144},[436,24911,5171],{"class":5163},[436,24913,24914],{"class":1151},"validator",[436,24916,5269],{"class":1144},[436,24918,24919],{"class":5159},"validate",[436,24921,5778],{"class":5163},[436,24923,11415],{"class":1151},[436,24925,5295],{"class":5163},[21541,24927,24929],{"id":24928},"_6-router-changes","6. Router Changes",[293,24931,24932],{},"Routes now return standardized JSON for errors.",[293,24934,24935],{},[308,24936,24937],{},"404 Response:",[428,24939,24941],{"className":11340,"code":24940,"language":2013,"meta":320,"style":320},"{\n    \"error\": \"Not Found\",\n    \"message\": \"The requested resource was not found\",\n    \"status\": 404\n}\n",[325,24942,24943,24947,24966,24985,24998],{"__ignoreMap":320},[436,24944,24945],{"class":438,"line":439},[436,24946,5193],{"class":5163},[436,24948,24949,24951,24953,24955,24957,24959,24962,24964],{"class":438,"line":1132},[436,24950,7168],{"class":11352},[436,24952,3480],{"class":11355},[436,24954,7174],{"class":11352},[436,24956,5243],{"class":5163},[436,24958,7179],{"class":11362},[436,24960,24961],{"class":11365},"Not Found",[436,24963,7174],{"class":11362},[436,24965,6907],{"class":5163},[436,24967,24968,24970,24972,24974,24976,24978,24981,24983],{"class":438,"line":1158},[436,24969,7168],{"class":11352},[436,24971,13763],{"class":11355},[436,24973,7174],{"class":11352},[436,24975,5243],{"class":5163},[436,24977,7179],{"class":11362},[436,24979,24980],{"class":11365},"The requested resource was not found",[436,24982,7174],{"class":11362},[436,24984,6907],{"class":5163},[436,24986,24987,24989,24991,24993,24995],{"class":438,"line":5196},[436,24988,7168],{"class":11352},[436,24990,9588],{"class":11355},[436,24992,7174],{"class":11352},[436,24994,5243],{"class":5163},[436,24996,24997],{"class":7256}," 404\n",[436,24999,25000],{"class":438,"line":5202},[436,25001,5205],{"class":5163},[293,25003,25004],{},[308,25005,25006],{},"405 Response:",[428,25008,25010],{"className":11340,"code":25009,"language":2013,"meta":320,"style":320},"{\n    \"error\": \"Method Not Allowed\",\n    \"message\": \"Method POST not allowed. Allowed methods: GET, PUT\",\n    \"status\": 405,\n    \"allowed_methods\": [\"GET\", \"PUT\"]\n}\n",[325,25011,25012,25016,25035,25054,25069,25099],{"__ignoreMap":320},[436,25013,25014],{"class":438,"line":439},[436,25015,5193],{"class":5163},[436,25017,25018,25020,25022,25024,25026,25028,25031,25033],{"class":438,"line":1132},[436,25019,7168],{"class":11352},[436,25021,3480],{"class":11355},[436,25023,7174],{"class":11352},[436,25025,5243],{"class":5163},[436,25027,7179],{"class":11362},[436,25029,25030],{"class":11365},"Method Not Allowed",[436,25032,7174],{"class":11362},[436,25034,6907],{"class":5163},[436,25036,25037,25039,25041,25043,25045,25047,25050,25052],{"class":438,"line":1158},[436,25038,7168],{"class":11352},[436,25040,13763],{"class":11355},[436,25042,7174],{"class":11352},[436,25044,5243],{"class":5163},[436,25046,7179],{"class":11362},[436,25048,25049],{"class":11365},"Method POST not allowed. Allowed methods: GET, PUT",[436,25051,7174],{"class":11362},[436,25053,6907],{"class":5163},[436,25055,25056,25058,25060,25062,25064,25067],{"class":438,"line":5196},[436,25057,7168],{"class":11352},[436,25059,9588],{"class":11355},[436,25061,7174],{"class":11352},[436,25063,5243],{"class":5163},[436,25065,25066],{"class":7256}," 405",[436,25068,6907],{"class":5163},[436,25070,25071,25073,25076,25078,25080,25082,25084,25086,25088,25090,25092,25095,25097],{"class":438,"line":5202},[436,25072,7168],{"class":11352},[436,25074,25075],{"class":11355},"allowed_methods",[436,25077,7174],{"class":11352},[436,25079,5243],{"class":5163},[436,25081,6050],{"class":5163},[436,25083,7174],{"class":11362},[436,25085,10877],{"class":11365},[436,25087,7174],{"class":11362},[436,25089,5177],{"class":5163},[436,25091,7179],{"class":11362},[436,25093,25094],{"class":11365},"PUT",[436,25096,7174],{"class":11362},[436,25098,11896],{"class":5163},[436,25100,25101],{"class":438,"line":5208},[436,25102,5205],{"class":5163},[21541,25104,25106],{"id":25105},"_7-fileuploader-changes","7. FileUploader Changes",[293,25108,25109],{},"FileUploader now resolves repositories via the DI container.",[293,25111,25112],{},[308,25113,21725],{},[428,25115,25117],{"className":5139,"code":25116,"language":1135,"meta":320,"style":320},"$uploader = new FileUploader($storage);\n$uploader->setRepository($repository);\n",[325,25118,25119,25137],{"__ignoreMap":320},[436,25120,25121,25123,25125,25127,25129,25131,25133,25135],{"class":438,"line":439},[436,25122,5761],{"class":5163},[436,25124,7968],{"class":1151},[436,25126,3168],{"class":1144},[436,25128,6551],{"class":5167},[436,25130,7975],{"class":5233},[436,25132,5778],{"class":5163},[436,25134,7980],{"class":1151},[436,25136,5295],{"class":5163},[436,25138,25139,25141,25143,25145,25148,25150,25153],{"class":438,"line":1132},[436,25140,5761],{"class":5163},[436,25142,7996],{"class":1151},[436,25144,5269],{"class":1144},[436,25146,25147],{"class":5159},"setRepository",[436,25149,5778],{"class":5163},[436,25151,25152],{"class":1151},"repository",[436,25154,5295],{"class":5163},[293,25156,25157],{},[308,25158,21770],{},[428,25160,25162],{"className":5139,"code":25161,"language":1135,"meta":320,"style":320},"// Repository is auto-resolved from container\n$uploader = $container->get(FileUploader::class);\n",[325,25163,25164,25169],{"__ignoreMap":320},[436,25165,25166],{"class":438,"line":439},[436,25167,25168],{"class":1168},"// Repository is auto-resolved from container\n",[436,25170,25171,25173,25175,25177,25179,25181,25183,25185,25187,25189,25191,25193],{"class":438,"line":1132},[436,25172,5761],{"class":5163},[436,25174,7968],{"class":1151},[436,25176,3168],{"class":1144},[436,25178,5171],{"class":5163},[436,25180,21839],{"class":1151},[436,25182,5269],{"class":1144},[436,25184,715],{"class":5159},[436,25186,5164],{"class":5163},[436,25188,7955],{"class":5233},[436,25190,6056],{"class":1144},[436,25192,6059],{"class":5167},[436,25194,5295],{"class":5163},[347,25196,21482],{"id":25197},"related-documentation-3",[415,25199,25200,25204,25208,25212,25216,25220,25224,25228],{},[418,25201,25202],{},[297,25203,13],{"href":14},[418,25205,25206],{},[297,25207,17],{"href":18},[418,25209,25210],{},[297,25211,33],{"href":34},[418,25213,25214],{},[297,25215,125],{"href":126},[418,25217,25218],{},[297,25219,22401],{"href":86},[418,25221,25222],{},[297,25223,93],{"href":94},[418,25225,25226],{},[297,25227,129],{"href":130},[418,25229,25230],{},[297,25231,121],{"href":122},[452,25233],{},[301,25235,25237],{"id":25236},"upgrade-checklist","Upgrade Checklist",[293,25239,25240],{},"When upgrading between major or minor versions:",[415,25242,25245,25254,25262,25271,25279,25288,25294,25300,25306],{"className":25243},[25244],"contains-task-list",[418,25246,25249,25253],{"className":25247},[25248],"task-list-item",[25250,25251],"input",{"disabled":5211,"type":25252},"checkbox"," Review breaking changes for your target version",[418,25255,25257,25259,25260,4887],{"className":25256},[25248],[25250,25258],{"disabled":5211,"type":25252}," Update environment variables (",[325,25261,2865],{},[418,25263,25265,25267,25268],{"className":25264},[25248],[25250,25266],{"disabled":5211,"type":25252}," Update configuration files in ",[325,25269,25270],{},"config/",[418,25272,25274,25276,25277],{"className":25273},[25248],[25250,25275],{"disabled":5211,"type":25252}," Run ",[325,25278,424],{},[418,25280,25282,25284,25285],{"className":25281},[25248],[25250,25283],{"disabled":5211,"type":25252}," Clear compiled caches: ",[325,25286,25287],{},"php glueful cache:clear",[418,25289,25291,25293],{"className":25290},[25248],[25250,25292],{"disabled":5211,"type":25252}," Update service provider registrations",[418,25295,25297,25299],{"className":25296},[25248],[25250,25298],{"disabled":5211,"type":25252}," Run your test suite",[418,25301,25303,25305],{"className":25302},[25248],[25250,25304],{"disabled":5211,"type":25252}," Review and update custom middleware",[418,25307,25309,25311],{"className":25308},[25248],[25250,25310],{"disabled":5211,"type":25252}," Check deprecated features in your codebase",[301,25313,25315],{"id":25314},"semantic-versioning","Semantic Versioning",[293,25317,25318,25319,5243],{},"Glueful follows ",[297,25320,25315],{"href":25321,"rel":25322},"https://semver.org/",[648],[415,25324,25325,25331,25337],{},[418,25326,25327,25330],{},[308,25328,25329],{},"Major versions"," (2.0.0): Breaking changes, major new features",[418,25332,25333,25336],{},[308,25334,25335],{},"Minor versions"," (1.1.0): New features, backward-compatible",[418,25338,25339,25342],{},[308,25340,25341],{},"Patch versions"," (1.0.1): Bug fixes, backward-compatible",[301,25344,25346],{"id":25345},"support-policy","Support Policy",[415,25348,25349,25355,25361],{},[418,25350,25351,25354],{},[308,25352,25353],{},"Latest minor version",": Active development, new features, bug fixes",[418,25356,25357,25360],{},[308,25358,25359],{},"Previous minor version",": Bug fixes for 6 months",[418,25362,25363,25366],{},[308,25364,25365],{},"Older versions",": Security fixes only for 12 months",[301,25368,25370],{"id":25369},"release-names","Release Names",[293,25372,25373],{},"Glueful releases are named after stars and celestial objects:",[415,25375,25376,25381,25386,25391,25396,25402,25408,25414,25420,25426,25432,25438,25443,25449,25455],{},[418,25377,25378,25380],{},[308,25379,22421],{}," (1.0.0) - The dawn of the framework",[418,25382,25383,25385],{},[308,25384,22176],{}," (1.1.0) - The guiding star",[418,25387,25388,25390],{},[308,25389,21514],{}," (1.2.0) - Bright and reliable",[418,25392,25393,25395],{},[308,25394,21107],{}," (1.3.0) - Distant but brilliant",[418,25397,25398,25401],{},[308,25399,25400],{},"Betelgeuse"," (1.9.0) - A red supergiant marking a new era",[418,25403,25404,25407],{},[308,25405,25406],{},"Castor"," (1.9.1) - One of the twin stars, bringing documentation clarity",[418,25409,25410,25413],{},[308,25411,25412],{},"Elnath"," (1.10.0) - The butting horn, bringing structured error handling and validation",[418,25415,25416,25419],{},[308,25417,25418],{},"Alnilam"," (1.11.0) - The central star of Orion's Belt, bringing the ORM foundation",[418,25421,25422,25425],{},[308,25423,25424],{},"Mintaka"," (1.12.0) - The western star of Orion's Belt, completing the output transformation layer",[418,25427,25428,25431],{},[308,25429,25430],{},"Saiph"," (1.13.0) - The sword of Orion, enhancing developer productivity with scaffolding and factories",[418,25433,25434,25437],{},[308,25435,25436],{},"Bellatrix"," (1.14.0) - The Amazon Star, powering interactive CLI wizards",[418,25439,25440,25442],{},[308,25441,20624],{}," (1.15.0) - The bright foot of Orion, illuminating real-time development",[418,25444,25445,25448],{},[308,25446,25447],{},"Meissa"," (1.16.0) - The head of Orion, governing API versioning strategy",[418,25450,25451,25454],{},[308,25452,25453],{},"Alnitak"," (1.17.0) - The eastern star of Orion's Belt, protecting APIs with rate limiting",[418,25456,25457,25460],{},[308,25458,25459],{},"Hadar"," (1.18.0) - Beta Centauri, a bright beacon enabling event-driven webhook integrations",[301,25462,25464],{"id":25463},"v150-orion-minor","v1.5.0 - Orion (Minor)",[293,25466,25467],{},[308,25468,20251],{},[312,25470,25471],{"color":3075,"icon":19227,"variant":316},[318,25472,25473],{"v-slot:description":320},[293,25474,25475],{},"Notification system wiring improvements with a shared DI provider and a safer email verification flow that avoids hard prechecks.",[347,25477,350],{"id":25478},"key-highlights-62",[352,25480,25481,25485],{},[293,25482,25483],{},[308,25484,20401],{},[415,25486,25487,25497],{},[418,25488,705,25489,25491,25492,542,25494,25496],{},[325,25490,20408],{}," binds ",[325,25493,20412],{},[325,25495,20415],{}," as shared services",[418,25498,25499],{},"Extensions can register channels and hooks during boot without ad‑hoc construction",[352,25501,25502,25507],{},[293,25503,25504],{},[308,25505,25506],{},"Safer Email Verification & Password Reset",[415,25508,25509,25512,25517],{},[418,25510,25511],{},"EmailVerification/SendNotification resolve dispatcher/channel via DI first (with a clean fallback)",[418,25513,8298,25514,25516],{},[325,25515,980],{}," prechecks; rely on dispatcher/channel availability at send time",[418,25518,25519],{},"Soft diagnostics log when the email channel is unavailable or no channels succeed",[347,25521,25523],{"id":25522},"other-changes","Other Changes",[415,25525,25526,25532],{},[418,25527,25528,25529,25531],{},"Align retry configuration lookup to ",[325,25530,20451],{}," (consistent with the extension)",[418,25533,25534],{},"Namespacing and static analysis fixes; line‑length formatting for diagnostics",[347,25536,413],{"id":25537},"migration-notes-41",[312,25539,25540],{"color":464,"icon":19437,"variant":316},[318,25541,25542],{"v-slot:description":320},[293,25543,25544,25545,19554,25548,25551],{},"If you referenced ",[325,25546,25547],{},"config($context, 'extensions.EmailNotification.retry')",[325,25549,25550],{},"config($context, 'email-notification.retry')",". No breaking API changes are introduced in 1.5.0.",[452,25553],{},[301,25555,25557],{"id":25556},"v171-canopus","v1.7.1 - Canopus",[293,25559,25560],{},[308,25561,19793],{},[312,25563,25564],{"color":3075,"icon":19227,"variant":316},[318,25565,25566],{"v-slot:description":320},[293,25567,25568],{},"Patch release that fixes extension discovery and boot sequencing so enabled extensions reliably load at runtime.",[347,25570,25572],{"id":25571},"whats-fixed","What’s Fixed",[415,25574,25575,25582,25592],{},[418,25576,25577,25578,19911,25580,299],{},"Framework initializes extensions by calling ",[325,25579,19910],{},[325,25581,19914],{},[418,25583,25584,25585,25587,25588,392,25590,299],{},"Extension migrations registered via ",[325,25586,19921],{}," are now discovered by ",[325,25589,4767],{},[325,25591,4764],{},[418,25593,25594,25595,542,25597,25599],{},"CLI ",[325,25596,1026],{},[325,25598,1012],{}," now accurately reflect included providers after boot.",[347,25601,19938],{"id":25602},"impact-1",[415,25604,25605],{},[418,25606,25607],{},"If you saw “EXCLUDED from final provider list” or “No pending migrations found” for extension migrations, this patch resolves it. No configuration changes required.",[452,25609],{},[301,25611,25613],{"id":25612},"v172-antares","v1.7.2 - Antares",[293,25615,25616],{},[308,25617,19793],{},[312,25619,25620],{"color":3075,"icon":19227,"variant":316},[318,25621,25622],{"v-slot:description":320},[293,25623,25624],{},"Patch release improving route loading resilience in extensions and reducing noise in the development server logs.",[347,25626,25572],{"id":25627},"whats-fixed-1",[415,25629,25630],{},[418,25631,19861,25632,25634,25635],{},[325,25633,19864],{}," is now idempotent and exception‑safe.\n",[415,25636,25637,25640],{},[418,25638,25639],{},"Prevents duplicate route registration when a routes file would otherwise be loaded twice.",[418,25641,19873],{},[347,25643,25645],{"id":25644},"developer-experience","Developer Experience",[415,25647,25648],{},[418,25649,25594,25650,25652,25653,25655],{},[325,25651,19831],{},": Reclassifies PHP built‑in server access/startup lines (written to STDERR) as normal output to avoid false ",[325,25654,19881],{}," entries while preserving real error reporting.",[452,25657],{},[301,25659,25661],{"id":25660},"v173-pollux","v1.7.3 - Pollux",[293,25663,25664],{},[308,25665,19793],{},[312,25667,25668],{"color":3075,"icon":19227,"variant":316},[318,25669,25670],{"v-slot:description":320},[293,25671,25672],{},"Patch release fixing 2‑argument where/orWhere handling and refining dev‑server logging.",[347,25674,25572],{"id":25675},"whats-fixed-2",[415,25677,25678],{},[418,25679,25680,25681,542,25683,25685,25686,25688,25689,25692],{},"Database/QueryBuilder: The 2‑argument forms ",[325,25682,19811],{},[325,25684,19814],{}," now normalize to ",[325,25687,3168],{}," internally, avoiding a ",[325,25690,25691],{},"TypeError"," and improving portability of boolean and integer filters across PostgreSQL/MySQL/SQLite.",[347,25694,25645],{"id":25695},"developer-experience-1",[415,25697,25698],{},[418,25699,25594,25700,25702,25703,25705],{},[325,25701,19831],{},": Additional refinement of PHP built‑in server access/lifecycle lines (written to STDERR) so they appear as normal output instead of false ",[325,25704,19881],{}," entries; real errors remain highlighted.",[452,25707],{},[25709,25710,25711],"style",{},"html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .ss--_, html code.shiki .ss--_{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .ss7Ak, html code.shiki .ss7Ak{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html pre.shiki code .sTNss, html code.shiki .sTNss{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .srJo8, html code.shiki .srJo8{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sD0ED, html code.shiki .sD0ED{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .swvn1, html code.shiki .swvn1{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .shWJe, html code.shiki .shWJe{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .s_MOj, html code.shiki .s_MOj{--shiki-light:#E2931D;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sFhLe, html code.shiki .sFhLe{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sSBr1, html code.shiki .sSBr1{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#FD971F}html pre.shiki code .sRxSC, html code.shiki .sRxSC{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .s91G_, html code.shiki .s91G_{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#F8F8F2}html pre.shiki code .sv8o3, html code.shiki .sv8o3{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#F8F8F2}html pre.shiki code .seZir, html code.shiki .seZir{--shiki-light:#90A4AE;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sQqfL, html code.shiki .sQqfL{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#F8F8F2}html pre.shiki code .sMLJd, html code.shiki .sMLJd{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#66D9EF}html pre.shiki code .sQeA1, html code.shiki .sQeA1{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sYThS, html code.shiki .sYThS{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sKvfc, html code.shiki .sKvfc{--shiki-light:#E2931D;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html pre.shiki code .sW3Pz, html code.shiki .sW3Pz{--shiki-light:#E2931D;--shiki-light-font-style:inherit;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-font-style:inherit;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-font-style:italic;--shiki-sepia-text-decoration:underline}html pre.shiki code .sMTiH, html code.shiki .sMTiH{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .saDeg, html code.shiki .saDeg{--shiki-light:#39ADB5;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sEff5, html code.shiki .sEff5{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sh1VR, html code.shiki .sh1VR{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#CFCFC2}html pre.shiki code .sINAO, html code.shiki .sINAO{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#CFCFC2}html pre.shiki code .sTC9v, html code.shiki .sTC9v{--shiki-light:#F76D47;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .s41CE, html code.shiki .s41CE{--shiki-light:#F76D47;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .s6MXs, html code.shiki .s6MXs{--shiki-light:#E2931D;--shiki-light-font-style:italic;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}",{"title":320,"searchDepth":439,"depth":1132,"links":25713},[25714,25718,25722,25726,25730,25734,25738,25742,25746,25750,25754,25757,25761,25764,25767,25771,25775,25779,25783,25787,25791,25795,25799,25803,25807,25811,25815,25820,25825,25830,25836,25842,25847,25852,25857,25861,25865,25869,25877,25887,25896,25904,25911,25918,25927,25934,25941,25948,25954,25961,25967,25971,25975,25979,25982,25985,25989,25994,25998,26001,26005,26009,26013,26018,26024,26030,26037,26045,26051,26057,26058,26059,26060,26061,26066,26070,26074],{"id":303,"depth":1132,"text":304,"children":25715},[25716,25717],{"id":349,"depth":1158,"text":350},{"id":412,"depth":1158,"text":413},{"id":456,"depth":1132,"text":457,"children":25719},[25720,25721],{"id":481,"depth":1158,"text":350},{"id":613,"depth":1158,"text":413},{"id":666,"depth":1132,"text":667,"children":25723},[25724,25725],{"id":693,"depth":1158,"text":350},{"id":824,"depth":1158,"text":413},{"id":863,"depth":1132,"text":864,"children":25727},[25728,25729],{"id":902,"depth":1158,"text":350},{"id":1033,"depth":1158,"text":413},{"id":1174,"depth":1132,"text":1175,"children":25731},[25732,25733],{"id":1210,"depth":1158,"text":350},{"id":1304,"depth":1158,"text":413},{"id":1348,"depth":1132,"text":1349,"children":25735},[25736,25737],{"id":1385,"depth":1158,"text":350},{"id":1583,"depth":1158,"text":413},{"id":1688,"depth":1132,"text":1689,"children":25739},[25740,25741],{"id":1721,"depth":1158,"text":350},{"id":1967,"depth":1158,"text":413},{"id":2083,"depth":1132,"text":2084,"children":25743},[25744,25745],{"id":2103,"depth":1158,"text":350},{"id":2363,"depth":1158,"text":413},{"id":2504,"depth":1132,"text":2505,"children":25747},[25748,25749],{"id":2528,"depth":1158,"text":350},{"id":2793,"depth":1158,"text":413},{"id":2881,"depth":1132,"text":2882,"children":25751},[25752,25753],{"id":2898,"depth":1158,"text":350},{"id":3019,"depth":1158,"text":413},{"id":3066,"depth":1132,"text":3067,"children":25755},[25756],{"id":3088,"depth":1158,"text":413},{"id":3098,"depth":1132,"text":3099,"children":25758},[25759,25760],{"id":3117,"depth":1158,"text":350},{"id":3227,"depth":1158,"text":413},{"id":3237,"depth":1132,"text":3238,"children":25762},[25763],{"id":3256,"depth":1158,"text":413},{"id":3266,"depth":1132,"text":3267,"children":25765},[25766],{"id":3287,"depth":1158,"text":413},{"id":3297,"depth":1132,"text":3298,"children":25768},[25769,25770],{"id":3317,"depth":1158,"text":350},{"id":3433,"depth":1158,"text":413},{"id":3471,"depth":1132,"text":3472,"children":25772},[25773,25774],{"id":3492,"depth":1158,"text":350},{"id":3622,"depth":1158,"text":413},{"id":3705,"depth":1132,"text":3706,"children":25776},[25777,25778],{"id":3729,"depth":1158,"text":350},{"id":3816,"depth":1158,"text":413},{"id":3840,"depth":1132,"text":3841,"children":25780},[25781,25782],{"id":3864,"depth":1158,"text":350},{"id":3990,"depth":1158,"text":413},{"id":4035,"depth":1132,"text":4036,"children":25784},[25785,25786],{"id":4059,"depth":1158,"text":350},{"id":4115,"depth":1158,"text":413},{"id":4147,"depth":1132,"text":4148,"children":25788},[25789,25790],{"id":4164,"depth":1158,"text":350},{"id":4238,"depth":1158,"text":413},{"id":4254,"depth":1132,"text":4255,"children":25792},[25793,25794],{"id":4274,"depth":1158,"text":4275},{"id":4290,"depth":1158,"text":413},{"id":4300,"depth":1132,"text":4301,"children":25796},[25797,25798],{"id":4316,"depth":1158,"text":350},{"id":4393,"depth":1158,"text":413},{"id":4444,"depth":1132,"text":4445,"children":25800},[25801,25802],{"id":4461,"depth":1158,"text":350},{"id":4557,"depth":1158,"text":413},{"id":4588,"depth":1132,"text":4589,"children":25804},[25805,25806],{"id":4607,"depth":1158,"text":350},{"id":4662,"depth":1158,"text":4663},{"id":4691,"depth":1132,"text":4692,"children":25808},[25809,25810],{"id":4706,"depth":1158,"text":350},{"id":4816,"depth":1158,"text":4663},{"id":4836,"depth":1132,"text":4837,"children":25812},[25813,25814],{"id":4852,"depth":1158,"text":350},{"id":4925,"depth":1158,"text":4663},{"id":4944,"depth":1132,"text":4945,"children":25816},[25817,25818,25819],{"id":4960,"depth":1158,"text":350},{"id":5128,"depth":1158,"text":5129},{"id":5334,"depth":1158,"text":4663},{"id":5356,"depth":1132,"text":5357,"children":25821},[25822,25823,25824],{"id":5373,"depth":1158,"text":350},{"id":5524,"depth":1158,"text":5525},{"id":5616,"depth":1158,"text":4663},{"id":5636,"depth":1132,"text":5637,"children":25826},[25827,25828,25829],{"id":5653,"depth":1158,"text":350},{"id":5736,"depth":1158,"text":5737},{"id":5842,"depth":1158,"text":4663},{"id":5861,"depth":1132,"text":5862,"children":25831},[25832,25833,25834,25835],{"id":5876,"depth":1158,"text":350},{"id":5954,"depth":1158,"text":5955},{"id":5965,"depth":1158,"text":5966},{"id":6295,"depth":1158,"text":4663},{"id":6315,"depth":1132,"text":6316,"children":25837},[25838,25839,25840,25841],{"id":6330,"depth":1158,"text":350},{"id":6505,"depth":1158,"text":6506},{"id":6840,"depth":1158,"text":121},{"id":6971,"depth":1158,"text":4663},{"id":6991,"depth":1132,"text":6992,"children":25843},[25844,25845,25846],{"id":7006,"depth":1158,"text":350},{"id":7137,"depth":1158,"text":6506},{"id":7349,"depth":1158,"text":4663},{"id":7368,"depth":1132,"text":7369,"children":25848},[25849,25850,25851],{"id":7388,"depth":1158,"text":350},{"id":7535,"depth":1158,"text":7536},{"id":7725,"depth":1158,"text":4663},{"id":7746,"depth":1132,"text":7747,"children":25853},[25854,25855,25856],{"id":7763,"depth":1158,"text":350},{"id":7929,"depth":1158,"text":5966},{"id":8198,"depth":1158,"text":8199},{"id":8234,"depth":1132,"text":8235,"children":25858},[25859,25860],{"id":8250,"depth":1158,"text":350},{"id":8360,"depth":1158,"text":8199},{"id":8499,"depth":1132,"text":8500,"children":25862},[25863,25864],{"id":8515,"depth":1158,"text":350},{"id":8635,"depth":1158,"text":8199},{"id":8686,"depth":1132,"text":8687,"children":25866},[25867,25868],{"id":8702,"depth":1158,"text":8703},{"id":8776,"depth":1158,"text":8199},{"id":8879,"depth":1132,"text":8880,"children":25870},[25871,25872,25873,25874,25875,25876],{"id":8895,"depth":1158,"text":350},{"id":8982,"depth":1158,"text":8902},{"id":9105,"depth":1158,"text":9106},{"id":9390,"depth":1158,"text":9391},{"id":10101,"depth":1158,"text":121},{"id":10462,"depth":1158,"text":6453},{"id":10534,"depth":1132,"text":10535,"children":25878},[25879,25880,25881,25882,25883,25884,25885,25886],{"id":10550,"depth":1158,"text":350},{"id":10657,"depth":1158,"text":10658},{"id":10839,"depth":1158,"text":10840},{"id":10970,"depth":1158,"text":9391},{"id":11336,"depth":1158,"text":11337},{"id":11507,"depth":1158,"text":11508},{"id":11614,"depth":1158,"text":121},{"id":11899,"depth":1158,"text":413},{"id":11936,"depth":1132,"text":11937,"children":25888},[25889,25890,25891,25892,25893,25894,25895],{"id":11951,"depth":1158,"text":350},{"id":12049,"depth":1158,"text":12050},{"id":5272,"depth":1158,"text":12206},{"id":12388,"depth":1158,"text":12389},{"id":12401,"depth":1158,"text":9391},{"id":12806,"depth":1158,"text":121},{"id":13231,"depth":1158,"text":413},{"id":13262,"depth":1132,"text":13263,"children":25897},[25898,25899,25900,25901,25902,25903],{"id":13278,"depth":1158,"text":350},{"id":13362,"depth":1158,"text":13363},{"id":13525,"depth":1158,"text":9391},{"id":13875,"depth":1158,"text":13876},{"id":13888,"depth":1158,"text":121},{"id":14057,"depth":1158,"text":413},{"id":14087,"depth":1132,"text":14088,"children":25905},[25906,25907,25908,25909,25910],{"id":14103,"depth":1158,"text":350},{"id":14168,"depth":1158,"text":14169},{"id":14218,"depth":1158,"text":9391},{"id":14332,"depth":1158,"text":14333},{"id":14397,"depth":1158,"text":413},{"id":14428,"depth":1132,"text":14429,"children":25912},[25913,25914,25915,25916,25917],{"id":14444,"depth":1158,"text":350},{"id":14560,"depth":1158,"text":14561},{"id":14827,"depth":1158,"text":14828},{"id":14955,"depth":1158,"text":413},{"id":15000,"depth":1158,"text":15001},{"id":15014,"depth":1132,"text":15015,"children":25919},[25920,25921,25922,25923,25924,25925,25926],{"id":15030,"depth":1158,"text":350},{"id":15139,"depth":1158,"text":15140},{"id":15358,"depth":1158,"text":15359},{"id":15509,"depth":1158,"text":15510},{"id":15606,"depth":1158,"text":9391},{"id":16147,"depth":1158,"text":16148},{"id":16303,"depth":1158,"text":413},{"id":16341,"depth":1132,"text":16342,"children":25928},[25929,25930,25931,25932,25933],{"id":16358,"depth":1158,"text":350},{"id":16467,"depth":1158,"text":16468},{"id":16710,"depth":1158,"text":9391},{"id":17293,"depth":1158,"text":16148},{"id":17385,"depth":1158,"text":413},{"id":17401,"depth":1132,"text":17402,"children":25935},[25936,25937,25938,25939,25940],{"id":17416,"depth":1158,"text":350},{"id":17482,"depth":1158,"text":17483},{"id":17794,"depth":1158,"text":9391},{"id":18264,"depth":1158,"text":16148},{"id":18359,"depth":1158,"text":413},{"id":18379,"depth":1132,"text":18380,"children":25942},[25943,25944,25945,25946,25947],{"id":18394,"depth":1158,"text":350},{"id":18457,"depth":1158,"text":18458},{"id":18703,"depth":1158,"text":18704},{"id":18771,"depth":1158,"text":9391},{"id":19011,"depth":1158,"text":413},{"id":19030,"depth":1132,"text":19031,"children":25949},[25950,25951,25952,25953],{"id":19047,"depth":1158,"text":350},{"id":19143,"depth":1158,"text":19144},{"id":19162,"depth":1158,"text":19163},{"id":19187,"depth":1158,"text":413},{"id":19218,"depth":1132,"text":19219,"children":25955},[25956,25957,25958,25959,25960],{"id":19235,"depth":1158,"text":350},{"id":19315,"depth":1158,"text":19316},{"id":19333,"depth":1158,"text":19334},{"id":19352,"depth":1158,"text":9391},{"id":19408,"depth":1158,"text":413},{"id":19428,"depth":1132,"text":19429,"children":25962},[25963,25964,25965,25966],{"id":19445,"depth":1158,"text":4676},{"id":19472,"depth":1158,"text":350},{"id":19507,"depth":1158,"text":19508},{"id":19525,"depth":1158,"text":413},{"id":19570,"depth":1132,"text":19571,"children":25968},[25969,25970],{"id":19586,"depth":1158,"text":350},{"id":19616,"depth":1158,"text":413},{"id":19626,"depth":1132,"text":19627,"children":25972},[25973,25974],{"id":19642,"depth":1158,"text":350},{"id":19705,"depth":1158,"text":413},{"id":19725,"depth":1132,"text":19726,"children":25976},[25977,25978],{"id":19741,"depth":1158,"text":350},{"id":19771,"depth":1158,"text":413},{"id":19787,"depth":1132,"text":19788,"children":25980},[25981],{"id":19803,"depth":1158,"text":350},{"id":19841,"depth":1132,"text":19842,"children":25983},[25984],{"id":19856,"depth":1158,"text":350},{"id":19887,"depth":1132,"text":19888,"children":25986},[25987,25988],{"id":19902,"depth":1158,"text":350},{"id":19937,"depth":1158,"text":19938},{"id":19948,"depth":1132,"text":19949,"children":25990},[25991,25992,25993],{"id":19964,"depth":1158,"text":350},{"id":20089,"depth":1158,"text":20090},{"id":20133,"depth":1158,"text":413},{"id":20153,"depth":1132,"text":20154,"children":25995},[25996,25997],{"id":20169,"depth":1158,"text":20170},{"id":20187,"depth":1158,"text":413},{"id":20207,"depth":1132,"text":20208,"children":25999},[26000],{"id":20222,"depth":1158,"text":350},{"id":20245,"depth":1132,"text":20246,"children":26002},[26003,26004],{"id":20261,"depth":1158,"text":350},{"id":20368,"depth":1158,"text":20369},{"id":20379,"depth":1132,"text":20380,"children":26006},[26007,26008],{"id":20394,"depth":1158,"text":350},{"id":20443,"depth":1158,"text":20170},{"id":20456,"depth":1132,"text":20457,"children":26010},[26011,26012],{"id":20472,"depth":1158,"text":20473},{"id":20485,"depth":1158,"text":20486},{"id":20496,"depth":1132,"text":20497,"children":26014},[26015,26016,26017],{"id":20511,"depth":1158,"text":350},{"id":20550,"depth":1158,"text":9391},{"id":20600,"depth":1158,"text":20369},{"id":20610,"depth":1132,"text":20611,"children":26019},[26020,26021,26022,26023],{"id":20628,"depth":1158,"text":350},{"id":20659,"depth":1158,"text":20170},{"id":20680,"depth":1158,"text":19163},{"id":20691,"depth":1158,"text":413},{"id":20951,"depth":1132,"text":20952,"children":26025},[26026,26027,26028,26029],{"id":20970,"depth":1158,"text":350},{"id":21000,"depth":1158,"text":20170},{"id":21029,"depth":1158,"text":9391},{"id":21078,"depth":1158,"text":8199},{"id":21092,"depth":1132,"text":21093,"children":26031},[26032,26033,26034,26035,26036],{"id":21111,"depth":1158,"text":350},{"id":21136,"depth":1158,"text":21137},{"id":21184,"depth":1158,"text":21185},{"id":21474,"depth":1158,"text":21475},{"id":21481,"depth":1158,"text":21482},{"id":21499,"depth":1132,"text":21500,"children":26038},[26039,26040,26041,26042,26043,26044],{"id":21518,"depth":1158,"text":350},{"id":21539,"depth":1158,"text":21137},{"id":21676,"depth":1158,"text":21677},{"id":21688,"depth":1158,"text":21689},{"id":21697,"depth":1158,"text":5129},{"id":22137,"depth":1158,"text":21482},{"id":22161,"depth":1132,"text":22162,"children":26046},[26047,26048,26049,26050],{"id":22180,"depth":1158,"text":350},{"id":22205,"depth":1158,"text":21137},{"id":22241,"depth":1158,"text":22242},{"id":22390,"depth":1158,"text":21482},{"id":22406,"depth":1132,"text":22407,"children":26052},[26053,26054,26055,26056],{"id":22425,"depth":1158,"text":350},{"id":22455,"depth":1158,"text":21137},{"id":23415,"depth":1158,"text":5129},{"id":25197,"depth":1158,"text":21482},{"id":25236,"depth":1132,"text":25237},{"id":25314,"depth":1132,"text":25315},{"id":25345,"depth":1132,"text":25346},{"id":25369,"depth":1132,"text":25370},{"id":25463,"depth":1132,"text":25464,"children":26062},[26063,26064,26065],{"id":25478,"depth":1158,"text":350},{"id":25522,"depth":1158,"text":25523},{"id":25537,"depth":1158,"text":413},{"id":25556,"depth":1132,"text":25557,"children":26067},[26068,26069],{"id":25571,"depth":1158,"text":25572},{"id":25602,"depth":1158,"text":19938},{"id":25612,"depth":1132,"text":25613,"children":26071},[26072,26073],{"id":25627,"depth":1158,"text":25572},{"id":25644,"depth":1158,"text":25645},{"id":25660,"depth":1132,"text":25661,"children":26075},[26076,26077],{"id":25675,"depth":1158,"text":25572},{"id":25695,"depth":1158,"text":25645},"Full release notes for Glueful versions v1.49.1 and earlier.","md",null,{},{"title":284,"description":26078},"VkfHFy6MaZI1Ixem4XV1ULO2PoZmvQMWS_ENjknoRA0",[26085,26080],{"title":280,"path":281,"stem":282,"description":26086,"children":-1},"Curated highlights, migration guidance, and structured summaries of Glueful framework releases.",1780886134581]