Compare commits

..

45 Commits

Author SHA1 Message Date
b55cc1e8c1 nodejs: request for a document when opening on client 2026-03-11 15:11:14 +03:00
9ec4621e48 fix(nodejs): correct formidable 4 filepath in forcesave 2026-03-11 15:11:14 +03:00
ee9324e691 fix(nodejs): saving file from buffer forceSave 2026-03-11 15:11:14 +03:00
7d6837c87b fix(nodejs): onSaveDocument only when file is opened from buffer 2026-03-11 15:11:13 +03:00
e60de8be91 fix(nodejs): using formidable to get opened from buffer file data 2026-03-11 15:11:13 +03:00
d0af413197 feat(nodejs): saving files opened from buffer with forcesave endpoint 2026-03-11 15:11:13 +03:00
bd1cc16793 feat(nodejs): opening and saving document from buffer 2026-03-11 15:10:56 +03:00
7b9623ce6a Merge remote-tracking branch 'remotes/origin/release/v9.4.0' into develop
# Conflicts:
#	.gitmodules
#	CHANGELOG.md
#	web/documentserver-example/nodejs/public/assets/document-formats
#	web/documentserver-example/nodejs/public/assets/plugin-aiautofill
2026-03-11 15:08:39 +03:00
b43af4a42b deps(php-laravel): bump laravel/pint to 1.28.0
# Conflicts:
#	web/documentserver-example/php-laravel/composer.lock
2026-03-11 13:51:04 +03:00
8778d492a1 Merge remote-tracking branch 'remotes/origin/release/1.15.0' into develop
# Conflicts:
#	web/documentserver-example/python/.check-licenses.yml
2026-03-11 13:48:38 +03:00
3c7aa7707c Merge pull request 'refactor(php-laravel): lint fix' from 1.15-lint-fix into release/1.15.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/100
2026-03-11 10:47:19 +00:00
b528be73d8 refactor(php-laravel): lint fix 2026-03-11 17:22:04 +07:00
dc9ff1ae4a ci: fix licenses-go.yml (added step Set up Go) 2026-03-11 13:14:19 +03:00
91551f4664 feat: update python/.check-licenses.yml 2026-03-11 13:07:25 +03:00
8271719817 Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-24 15:05:47 +03:00
395e2d1299 nodejs: update plugin ai-autofill guid (v0.1.3) 2026-02-24 14:59:41 +03:00
7d9d2fdf3d nodejs: conversion to md 2026-02-19 09:44:30 +03:00
3a0a713c5a Merge pull request 'update documentserver version to 9.3 in compose files' from 9.3.0-update-compose into release/v9.3.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/93
2026-02-18 06:08:08 +00:00
496092c09f update documentserver version to 9.3 in compose files 2026-02-17 15:48:09 +07:00
c0a870458b Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-16 09:46:28 +03:00
35da4e1de1 update autofill plugin 2026-02-16 09:46:03 +03:00
11974256a9 Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-11 13:21:25 +03:00
f69fabb44a nodejs: autofill auto started on Fill mode only 2026-02-11 13:21:05 +03:00
976d7072a9 Merge remote-tracking branch 'remotes/origin/feature/aiautofiller' into release/v9.3.0 2026-02-04 13:33:42 +03:00
8272c83660 update autofill plugin 2026-02-04 13:33:12 +03:00
c73aae1c4b Merge pull request 'fix: disable autofill plugin for 'comment' mode' from feature/aiautofiller into release/v9.3.0
Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/document-server-integration/pulls/87
2026-01-30 08:39:00 +00:00
4340c34c23 nodejs: fix lint 2026-01-30 11:38:01 +03:00
3eff9b469b fix: disable autofill plugin for 'comment' mode 2026-01-30 11:37:20 +03:00
eabda30bf7 Merge branch 'feature/aiautofiller' into release/v9.3.0
# Conflicts:
#	.gitmodules
2026-01-21 17:18:43 +03:00
548f24aaff nodejs: update autofill plugin 2026-01-21 17:16:24 +03:00
c1ec722b9f nodejs: anonymous without ai autofill 2026-01-21 17:16:24 +03:00
92a1aff932 nodejs: plugin data update 2026-01-21 17:16:23 +03:00
4fe6e961d3 nodejs: plugin for pdf only 2026-01-21 17:16:23 +03:00
e612717b0b fix: fallback to default plugins 2026-01-21 17:16:23 +03:00
e0e0bc96bf fix(plugins): merge configs with in-line plugin config 2026-01-21 17:16:23 +03:00
c3739fb08a fix: use plugin path without build 2026-01-21 17:16:23 +03:00
c22dbea9bf chore: added additional data 2026-01-21 17:16:23 +03:00
606a14ce8f deps: bumped autofill plugin 2026-01-21 17:16:22 +03:00
4cb50c752b chore: update plugin submodule 2026-01-21 17:16:22 +03:00
c304b5f526 chore: new sample data 2026-01-21 17:16:22 +03:00
f02726d138 refactor: move data to json, build path to the plugin from config 2026-01-21 17:16:22 +03:00
85b0fdc33f chore: strict check 2026-01-21 17:16:22 +03:00
0e8c99aaab fix: do not autostart non edit mode 2026-01-21 17:16:21 +03:00
5a4b47c4bd feat: initial aiautofiller example 2026-01-21 17:16:21 +03:00
9775c8e175 nodejs: support tsv 2026-01-21 17:02:57 +03:00
15 changed files with 232 additions and 135 deletions

View File

@ -15,6 +15,10 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.23'
- name: Submodule Update
run: |
cd ${{ github.workspace }}

View File

@ -29,7 +29,6 @@ const config = require('config');
const mime = require('mime');
const urllib = require('urllib');
const urlModule = require('url');
const { emitWarning } = require('process');
const DocManager = require('./helpers/docManager');
const documentService = require('./helpers/documentService');
const fileUtility = require('./helpers/fileUtility');
@ -721,12 +720,38 @@ app.put('/restore', async (req, res) => { // define a handler for restore file v
res.end();
});
app.post('/forcesave', async (req, res) => {
req.DocManager = new DocManager(req, res);
const uAddress = req.query.useraddress;
const fName = fileUtility.getFileName(req.query.filename);
if (req.headers['content-type'] === 'application/octet-stream') {
const form = new formidable.IncomingForm();
form.parse(req, async (err, fields, files) => {
if (err) {
res.write('{"error":1, "message":"document data is empty"}');
res.end();
return;
}
const filePath = files.file.filepath || files.file[0].filepath;
const data = fileSystem.readFileSync(filePath);
await req.DocManager.forcesaveFile(data, fName, fileUtility.getFileExtension(fName), uAddress);
fileSystem.unlinkSync(filePath);
res.write('{"error":0}');
res.end();
});
} else {
res.write('{"error":0}');
res.end();
}
});
app.post('/track', async (req, res) => { // define a handler for tracking file changes
req.DocManager = new DocManager(req, res);
let uAddress = req.query.useraddress;
let fName = fileUtility.getFileName(req.query.filename);
let version = 0;
// track file changes
const processTrack = async function processTrack(response, bodyTrack, fileNameTrack, userAddressTrack) {
@ -751,56 +776,7 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
if (status !== 200) throw new Error(`Document editing service returned status: ${status}`);
const storagePath = req.DocManager.storagePath(newFileName, userAddress);
let historyPath = req.DocManager.historyPath(newFileName, userAddress); // get the path to the history data
if (historyPath === '') { // if the history path doesn't exist
historyPath = req.DocManager.historyPath(newFileName, userAddress, true); // create it
req.DocManager.createDirectory(historyPath); // and create a directory for the history data
}
const countVersion = req.DocManager.countVersion(historyPath); // get the next file version number
version = countVersion + 1;
// get the path to the specified file version
const versionPath = req.DocManager.versionPath(newFileName, userAddress, version);
req.DocManager.createDirectory(versionPath); // create a directory to the specified file version
const downloadZip = body.changesurl;
if (downloadZip) {
// get the path to the file with document versions differences
const pathChanges = req.DocManager.diffPath(newFileName, userAddress, version);
const zip = await urllib.request(downloadZip, { method: 'GET' });
const statusZip = zip.status;
const dataZip = zip.data;
if (statusZip === 200) {
fileSystem.writeFileSync(pathChanges, dataZip); // write the document version differences to the archive
} else {
emitWarning(`Document editing service returned status: ${statusZip}`);
}
}
const changeshistory = JSON.stringify(body.history);
if (changeshistory) {
// get the path to the file with document changes
const pathChangesJson = req.DocManager.changesPath(newFileName, userAddress, version);
fileSystem.writeFileSync(pathChangesJson, changeshistory); // and write this data to the path in json format
}
const pathKey = req.DocManager.keyPath(newFileName, userAddress, version); // get the path to the key.txt file
fileSystem.writeFileSync(pathKey, body.key); // write the key value to the key.txt file
// get the path to the previous file version
const pathPrev = path.join(versionPath, `prev${fileUtility.getFileExtension(fileName)}`);
// and write it to the current path
fileSystem.renameSync(req.DocManager.storagePath(fileName, userAddress), pathPrev);
fileSystem.writeFileSync(storagePath, data);
// get the path to the forcesaved file
const forcesavePath = req.DocManager.forcesavePath(newFileName, userAddress, false);
if (forcesavePath !== '') { // if this path is empty
fileSystem.unlinkSync(forcesavePath); // remove it
}
await req.DocManager.saveFile(fileName, newFileName, userAddress, body, data);
} catch (ex) {
console.log(ex);
response.setHeader('Content-Type', 'application/json');
@ -870,64 +846,8 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
const downloadExt = `.${body.fileType}`;
const isSubmitForm = body.forcesavetype === 3; // SubmitForm
let correctName = fileName;
let forcesavePath = '';
if (isSubmitForm) {
// new file
if (newFileName) {
correctName = req.DocManager.getCorrectName(
`${fileUtility.getFileName(fileName, true)}-form${downloadExt}`,
userAddress,
);
} else {
const ext = fileUtility.getFileExtension(fileName);
correctName = req.DocManager.getCorrectName(
`${fileUtility.getFileName(fileName, true)}-form${ext}`,
userAddress,
);
}
forcesavePath = req.DocManager.storagePath(correctName, userAddress);
} else {
if (newFileName) {
correctName = req.DocManager.getCorrectName(fileUtility.getFileName(
fileName,
true,
) + downloadExt, userAddress);
}
// create forcesave path if it doesn't exist
forcesavePath = req.DocManager.forcesavePath(correctName, userAddress, false);
if (forcesavePath === '') {
forcesavePath = req.DocManager.forcesavePath(correctName, userAddress, true);
}
}
fileSystem.writeFileSync(forcesavePath, data);
if (isSubmitForm) {
const uid = body.actions[0].userid;
req.DocManager.saveFileData(correctName, uid, 'Filling Form', userAddress);
const { formsdataurl } = body;
if (formsdataurl) {
const formsdataName = req.DocManager.getCorrectName(
`${fileUtility.getFileName(correctName, true)}.txt`,
userAddress,
);
// get the path to the file with forms data
const formsdataPath = req.DocManager.storagePath(formsdataName, userAddress);
const formsdata = await urllib.request(formsdataurl, { method: 'GET' });
const statusFormsdata = formsdata.status;
const dataFormsdata = formsdata.data;
if (statusFormsdata === 200) {
fileSystem.writeFileSync(formsdataPath, dataFormsdata); // write the forms data
} else {
emitWarning(`Document editing service returned status: ${statusFormsdata}`);
}
} else {
emitWarning('Document editing service do not returned formsdataurl');
}
}
await req.DocManager.forcesaveFile(data, fileName, downloadExt, userAddress, body, newFileName, isSubmitForm);
} catch (ex) {
console.log(ex);
response.write(`{ "error":1, "message":${JSON.stringify(ex)} }`);
@ -989,6 +909,9 @@ app.post('/track', async (req, res) => { // define a handler for tracking file c
}
}
}
if (bodyTrack.users.length <= 0 && req.DocManager.forcesavePath(fName, uAddress, false)) {
await req.DocManager.saveFile(fName, fName, uAddress, bodyTrack);
}
} else if (bodyTrack.status === 2 || bodyTrack.status === 3) { // MustSave, Corrupted
await processSave(bodyTrack.url, bodyTrack, fileNameTrack, userAddressTrack); // save file
return;
@ -1107,6 +1030,7 @@ app.get('/editor', (req, res) => { // define a handler for editing document
req.DocManager = new DocManager(req, res);
let { fileExt } = req.query;
const fromBuffer = req.query.fromBuffer === 'true';
const user = users.getUser(req.query.userid);
const userid = user.id;
const { name } = user;
@ -1250,11 +1174,12 @@ app.get('/editor', (req, res) => { // define a handler for editing document
// file config data
const argss = {
bufferCallback: req.DocManager.getCallback(fileName, fromBuffer),
apiUrl: siteUrl + configServer.get('apiUrl'),
file: {
name: fileName,
ext: fileUtility.getFileExtension(fileName, true),
uri: url,
uri: fromBuffer ? '_data_' : url,
directUrl: !userDirectUrl ? null : directUrl,
uriUser: directUrl,
created: new Date().toDateString(),

View File

@ -18,6 +18,8 @@
const path = require('path');
const fileSystem = require('fs');
const urllib = require('urllib');
const { emitWarning } = require('process');
const configServer = require('config').get('server');
const fileUtility = require('./fileUtility');
const documentService = require('./documentService');
@ -203,11 +205,12 @@ DocManager.prototype.getProtocol = function getProtocol() {
};
// get callback url
DocManager.prototype.getCallback = function getCallback(fileName) {
DocManager.prototype.getCallback = function getCallback(fileName, fromBuffer = false) {
const server = this.getServerUrl(true);
const hostAddress = this.curUserHostAddress();
const route = fromBuffer ? '/forcesave' : '/track';
// get callback handler
const handler = `/track?filename=${encodeURIComponent(fileName)}&useraddress=${encodeURIComponent(hostAddress)}`;
const handler = `${route}?filename=${encodeURIComponent(fileName)}&useraddress=${encodeURIComponent(hostAddress)}`;
return server + handler;
};
@ -269,6 +272,129 @@ DocManager.prototype.forcesavePath = function forcesavePath(fileName, userAddres
return directory;
};
DocManager.prototype.forcesaveFile = async function forcesaveFile(
data,
fileName,
downloadExt,
userAddress,
body = null,
newFileName = false,
isSubmitForm = false,
) {
let correctName = fileName;
let forcesavePath = '';
if (isSubmitForm) {
// new file
if (newFileName) {
correctName = this.getCorrectName(
`${fileUtility.getFileName(fileName, true)}-form${downloadExt}`,
userAddress,
);
} else {
const ext = fileUtility.getFileExtension(fileName);
correctName = this.getCorrectName(
`${fileUtility.getFileName(fileName, true)}-form${ext}`,
userAddress,
);
}
forcesavePath = this.storagePath(correctName, userAddress);
} else {
if (newFileName) {
correctName = this.getCorrectName(fileUtility.getFileName(
fileName,
true,
) + downloadExt, userAddress);
}
// create forcesave path if it doesn't exist
forcesavePath = this.forcesavePath(correctName, userAddress, false);
if (forcesavePath === '') {
forcesavePath = this.forcesavePath(correctName, userAddress, true);
}
}
fileSystem.writeFileSync(forcesavePath, data);
if (isSubmitForm) {
const uid = body.actions[0].userid;
this.saveFileData(correctName, uid, 'Filling Form', userAddress);
const { formsdataurl } = body;
if (formsdataurl) {
const formsdataName = this.getCorrectName(
`${fileUtility.getFileName(correctName, true)}.txt`,
userAddress,
);
// get the path to the file with forms data
const formsdataPath = this.storagePath(formsdataName, userAddress);
const formsdata = await urllib.request(formsdataurl, { method: 'GET' });
const statusFormsdata = formsdata.status;
const dataFormsdata = formsdata.data;
if (statusFormsdata === 200) {
fileSystem.writeFileSync(formsdataPath, dataFormsdata); // write the forms data
} else {
emitWarning(`Document editing service returned status: ${statusFormsdata}`);
}
} else {
emitWarning('Document editing service do not returned formsdataurl');
}
}
};
DocManager.prototype.saveFile = async function saveFile(fileName, newFileName, userAddress, body, data = null) {
const storagePath = this.storagePath(newFileName, userAddress);
let historyPath = this.historyPath(newFileName, userAddress); // get the path to the history data
if (historyPath === '') { // if the history path doesn't exist
historyPath = this.historyPath(newFileName, userAddress, true); // create it
this.createDirectory(historyPath); // and create a directory for the history data
}
const countVersion = this.countVersion(historyPath); // get the next file version number
const version = countVersion + 1;
// get the path to the specified file version
const versionPath = this.versionPath(newFileName, userAddress, version);
this.createDirectory(versionPath); // create a directory to the specified file version
const downloadZip = body.changesurl;
if (downloadZip) {
// get the path to the file with document versions differences
const pathChanges = this.diffPath(newFileName, userAddress, version);
const zip = await urllib.request(downloadZip, { method: 'GET' });
const statusZip = zip.status;
const dataZip = zip.data;
if (statusZip === 200) {
fileSystem.writeFileSync(pathChanges, dataZip); // write the document version differences to the archive
} else {
emitWarning(`Document editing service returned status: ${statusZip}`);
}
}
const changeshistory = body.changeshistory || JSON.stringify(body.history);
if (changeshistory) {
// get the path to the file with document changes
const pathChangesJson = this.changesPath(newFileName, userAddress, version);
fileSystem.writeFileSync(pathChangesJson, changeshistory); // and write this data to the path in json format
}
const pathKey = this.keyPath(newFileName, userAddress, version); // get the path to the key.txt file
fileSystem.writeFileSync(pathKey, body.key); // write the key value to the key.txt file
// get the path to the previous file version
const pathPrev = path.join(versionPath, `prev${fileUtility.getFileExtension(fileName)}`);
// and write it to the current path
fileSystem.renameSync(this.storagePath(fileName, userAddress), pathPrev);
// get the path to the forcesaved file
const forcesavePath = this.forcesavePath(newFileName, userAddress, false);
if (forcesavePath !== '') { // if this path is not empty
if (data === null) fileSystem.writeFileSync(storagePath, fileSystem.readFileSync(forcesavePath));
fileSystem.unlinkSync(forcesavePath); // remove it
}
if (data !== null) fileSystem.writeFileSync(storagePath, data);
};
// create the path to the file history
DocManager.prototype.historyPath = function historyPath(fileName, userAddress, create) {
let directory = this.storageRootPath(userAddress);

View File

@ -77,8 +77,30 @@
var onAppReady = function () { // the application is loaded into the browser
innerAlert("Document editor ready");
if (config.document.url === "_data_") {
let xhr = new XMLHttpRequest();
xhr.open("GET", "download?fileName=" + encodeURIComponent(config.document.title));
xhr.responseType = "arraybuffer";
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
docEditor.openDocument(new Uint8Array(xhr.response));
} else {
innerAlert("Failed to download document");
}
};
};
};
var onSaveDocument = function (event) {
if (config.document.url !== "_data_") return;
let xhr = new XMLHttpRequest();
xhr.open("POST", "<%- bufferCallback %>");
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.send(event.data);
}
var onDocumentStateChange = function (event) { // the document is modified
var title = document.title.replace(/^\*/g, "");
document.title = (event.data ? "*" : "") + title;
@ -454,6 +476,7 @@
"onRequestSelectDocument": onRequestSelectDocument,
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet,
"onRequestOpen": onRequestOpen,
"onSaveDocument": onSaveDocument,
};
if (<%- JSON.stringify(editor.userid) %> != null) {

View File

@ -111,11 +111,19 @@
<tr>
<td valign="middle">
<label class="side-option">
<input id="directUrl" type="checkbox" class="checkbox collectable" name="directUrl" />Try opening on client
<input id="directUrl" type="checkbox" class="checkbox collectable" name="directUrl" />Opening direct link
<img id="directUrlInfo" class="info info-tooltip" data-id="directUrlInfo" data-tooltip="Some files can be opened in the user's browser without connecting to the document server. Open each file in only one way." src="images/info.svg" />
</label>
</td>
</tr>
<tr>
<td valign="middle">
<label class="side-option">
<input id="fromBuffer" type="checkbox" class="checkbox collectable" name="fromBuffer" />Opening on client
<img id="fromBufferInfo" class="info info-tooltip" data-id="fromBufferInfo" data-tooltip="Download the file and transfer it to the editor on the client without requests from the document server." src="images/info.svg" />
</label>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -14,7 +14,7 @@ class CheckAndDecodeJWTPayload
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -11,7 +11,7 @@ class EnsureForgottenPageEnabled
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -14,7 +14,7 @@ class EnsureJWTTokenIsPresent
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -12,7 +12,7 @@ class EnsureUserDirectoryExists
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{

View File

@ -1,5 +1,7 @@
<?php
use App\Providers\AppServiceProvider;
return [
App\Providers\AppServiceProvider::class,
AppServiceProvider::class,
];

View File

@ -6229,16 +6229,16 @@
},
{
"name": "laravel/pint",
"version": "v1.27.1",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
"reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
"url": "https://api.github.com/repos/laravel/pint/zipball/1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9",
"reference": "1feae84bf9c1649d99ba8f7b8193bf0f09f04cc9",
"shasum": ""
},
"require": {
@ -6249,13 +6249,14 @@
"php": "^8.2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.93.1",
"illuminate/view": "^12.51.0",
"larastan/larastan": "^3.9.2",
"friendsofphp/php-cs-fixer": "^3.94.2",
"illuminate/view": "^12.54.1",
"larastan/larastan": "^3.9.3",
"laravel-zero/framework": "^12.0.5",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3.3",
"pestphp/pest": "^3.8.5"
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest": "^3.8.5",
"shipfastlabs/agent-detector": "^1.0.2"
},
"bin": [
"builds/pint"
@ -6292,7 +6293,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2026-02-10T20:00:20+00:00"
"time": "2026-03-10T20:37:18+00:00"
},
{
"name": "laravel/sail",
@ -8726,6 +8727,6 @@
"platform": {
"php": "^8.2"
},
"platform-dev": [],
"plugin-api-version": "2.6.0"
"platform-dev": {},
"plugin-api-version": "2.9.0"
}

View File

@ -1,5 +1,7 @@
<?php
use App\Models\User;
return [
/*
@ -62,7 +64,7 @@ return [
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
'model' => env('AUTH_MODEL', User::class),
],
// 'users' => [

View File

@ -2,12 +2,13 @@
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
* @extends Factory<User>
*/
class UserFactory extends Factory
{

View File

@ -51,6 +51,11 @@
- msgspec
- :who:
:why: BSD-3-Clause
:versions:
- 0.20.0
:versions: []
:when: 2025-11-07 10:13:51.477550000 Z
- - :approve
- pyjwt
- :who:
:why: MIT
:versions: []
:when: 2025-11-07 10:13:51.477550000 Z

View File

@ -5,7 +5,7 @@ requires = [
[project]
name = "online-editor-example"
version = "1.15.0"
version = "1.6.0"
requires-python = ">=3.11.4"
dependencies = [
"django>=3.1.3",