@nextsparkjs/plugin-ai 0.1.0-beta.68 → 0.1.0-beta.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -308,6 +308,25 @@ export const aiHistoryFields: EntityField[] = [
|
|
|
308
308
|
readOnly: true,
|
|
309
309
|
},
|
|
310
310
|
},
|
|
311
|
+
{
|
|
312
|
+
name: 'updatedAt',
|
|
313
|
+
type: 'datetime',
|
|
314
|
+
required: false,
|
|
315
|
+
display: {
|
|
316
|
+
label: 'Updated At',
|
|
317
|
+
description: 'When the record was last updated',
|
|
318
|
+
showInList: false,
|
|
319
|
+
showInDetail: true,
|
|
320
|
+
showInForm: false,
|
|
321
|
+
order: 98,
|
|
322
|
+
columnWidth: 6,
|
|
323
|
+
},
|
|
324
|
+
api: {
|
|
325
|
+
searchable: false,
|
|
326
|
+
sortable: true,
|
|
327
|
+
readOnly: true,
|
|
328
|
+
},
|
|
329
|
+
},
|
|
311
330
|
{
|
|
312
331
|
name: 'completedAt',
|
|
313
332
|
type: 'datetime',
|
|
@@ -318,7 +337,7 @@ export const aiHistoryFields: EntityField[] = [
|
|
|
318
337
|
showInList: false,
|
|
319
338
|
showInDetail: true,
|
|
320
339
|
showInForm: false,
|
|
321
|
-
order:
|
|
340
|
+
order: 99,
|
|
322
341
|
columnWidth: 6,
|
|
323
342
|
},
|
|
324
343
|
api: {
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
-- MAIN AI_HISTORY TABLE
|
|
11
11
|
-- =============================================
|
|
12
12
|
|
|
13
|
-
DROP TABLE IF EXISTS "
|
|
13
|
+
DROP TABLE IF EXISTS "ai-history" CASCADE;
|
|
14
14
|
|
|
15
|
-
CREATE TABLE "
|
|
15
|
+
CREATE TABLE "ai-history" (
|
|
16
16
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
17
17
|
"userId" TEXT NOT NULL REFERENCES "users"(id) ON DELETE CASCADE,
|
|
18
18
|
|
|
@@ -41,6 +41,7 @@ CREATE TABLE "ai_history" (
|
|
|
41
41
|
|
|
42
42
|
-- Timestamps
|
|
43
43
|
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
44
|
+
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
44
45
|
"completedAt" TIMESTAMPTZ
|
|
45
46
|
);
|
|
46
47
|
|
|
@@ -48,46 +49,46 @@ CREATE TABLE "ai_history" (
|
|
|
48
49
|
-- INDEXES
|
|
49
50
|
-- =============================================
|
|
50
51
|
|
|
51
|
-
CREATE INDEX IF NOT EXISTS
|
|
52
|
-
CREATE INDEX IF NOT EXISTS
|
|
53
|
-
CREATE INDEX IF NOT EXISTS
|
|
54
|
-
CREATE INDEX IF NOT EXISTS
|
|
55
|
-
CREATE INDEX IF NOT EXISTS
|
|
56
|
-
CREATE INDEX IF NOT EXISTS
|
|
57
|
-
CREATE INDEX IF NOT EXISTS
|
|
58
|
-
CREATE INDEX IF NOT EXISTS
|
|
59
|
-
CREATE INDEX IF NOT EXISTS
|
|
60
|
-
CREATE INDEX IF NOT EXISTS
|
|
61
|
-
CREATE INDEX IF NOT EXISTS
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_user_id ON "ai-history"("userId");
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_entity ON "ai-history"("relatedEntityType", "relatedEntityId") WHERE "relatedEntityType" IS NOT NULL;
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_status ON "ai-history"(status);
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_operation ON "ai-history"(operation);
|
|
56
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_model ON "ai-history"(model);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_provider ON "ai-history"(provider);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_created_at ON "ai-history"("createdAt" DESC);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_user_status ON "ai-history"("userId", status);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_user_operation ON "ai-history"("userId", operation);
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_tokens_input ON "ai-history"("tokensInput") WHERE "tokensInput" IS NOT NULL;
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_ai-history_tokens_output ON "ai-history"("tokensOutput") WHERE "tokensOutput" IS NOT NULL;
|
|
62
63
|
|
|
63
64
|
-- =============================================
|
|
64
65
|
-- ROW LEVEL SECURITY (enableRLS: true)
|
|
65
66
|
-- =============================================
|
|
66
67
|
|
|
67
68
|
-- Enable RLS
|
|
68
|
-
ALTER TABLE "
|
|
69
|
+
ALTER TABLE "ai-history" ENABLE ROW LEVEL SECURITY;
|
|
69
70
|
|
|
70
|
-
-- Policies for
|
|
71
|
-
DROP POLICY IF EXISTS "Users can view own ai history" ON "
|
|
72
|
-
CREATE POLICY "Users can view own ai history" ON "
|
|
71
|
+
-- Policies for ai-history table
|
|
72
|
+
DROP POLICY IF EXISTS "Users can view own ai history" ON "ai-history";
|
|
73
|
+
CREATE POLICY "Users can view own ai history" ON "ai-history"
|
|
73
74
|
FOR SELECT USING ("userId" = public.get_auth_user_id());
|
|
74
75
|
|
|
75
|
-
DROP POLICY IF EXISTS "Users can insert own ai history" ON "
|
|
76
|
-
CREATE POLICY "Users can insert own ai history" ON "
|
|
76
|
+
DROP POLICY IF EXISTS "Users can insert own ai history" ON "ai-history";
|
|
77
|
+
CREATE POLICY "Users can insert own ai history" ON "ai-history"
|
|
77
78
|
FOR INSERT WITH CHECK ("userId" = public.get_auth_user_id());
|
|
78
79
|
|
|
79
|
-
DROP POLICY IF EXISTS "Users can update own ai history" ON "
|
|
80
|
-
CREATE POLICY "Users can update own ai history" ON "
|
|
80
|
+
DROP POLICY IF EXISTS "Users can update own ai history" ON "ai-history";
|
|
81
|
+
CREATE POLICY "Users can update own ai history" ON "ai-history"
|
|
81
82
|
FOR UPDATE USING ("userId" = public.get_auth_user_id())
|
|
82
83
|
WITH CHECK ("userId" = public.get_auth_user_id());
|
|
83
84
|
|
|
84
|
-
DROP POLICY IF EXISTS "Users can delete own ai history" ON "
|
|
85
|
-
CREATE POLICY "Users can delete own ai history" ON "
|
|
85
|
+
DROP POLICY IF EXISTS "Users can delete own ai history" ON "ai-history";
|
|
86
|
+
CREATE POLICY "Users can delete own ai history" ON "ai-history"
|
|
86
87
|
FOR DELETE USING ("userId" = public.get_auth_user_id());
|
|
87
88
|
|
|
88
89
|
-- Admins can manage all ai history
|
|
89
|
-
DROP POLICY IF EXISTS "Admins can manage all ai history" ON "
|
|
90
|
-
CREATE POLICY "Admins can manage all ai history" ON "
|
|
90
|
+
DROP POLICY IF EXISTS "Admins can manage all ai history" ON "ai-history";
|
|
91
|
+
CREATE POLICY "Admins can manage all ai history" ON "ai-history"
|
|
91
92
|
FOR ALL USING (
|
|
92
93
|
EXISTS (
|
|
93
94
|
SELECT 1 FROM "users"
|
|
@@ -103,10 +104,17 @@ CREATE POLICY "Admins can manage all ai history" ON "ai_history"
|
|
|
103
104
|
)
|
|
104
105
|
);
|
|
105
106
|
|
|
107
|
+
-- =============================================
|
|
108
|
+
-- TRIGGER: Auto-update updatedAt
|
|
109
|
+
-- =============================================
|
|
110
|
+
CREATE TRIGGER ai-history_set_updated_at
|
|
111
|
+
BEFORE UPDATE ON "ai-history"
|
|
112
|
+
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
|
113
|
+
|
|
106
114
|
-- =============================================
|
|
107
115
|
-- TRIGGER: Auto-update completedAt
|
|
108
116
|
-- =============================================
|
|
109
|
-
CREATE OR REPLACE FUNCTION
|
|
117
|
+
CREATE OR REPLACE FUNCTION update_ai-history_completed_at()
|
|
110
118
|
RETURNS TRIGGER AS $$
|
|
111
119
|
BEGIN
|
|
112
120
|
IF NEW.status IN ('completed', 'failed') AND OLD.status NOT IN ('completed', 'failed') THEN
|
|
@@ -116,16 +124,16 @@ BEGIN
|
|
|
116
124
|
END;
|
|
117
125
|
$$ LANGUAGE plpgsql;
|
|
118
126
|
|
|
119
|
-
CREATE TRIGGER
|
|
120
|
-
BEFORE UPDATE ON "
|
|
127
|
+
CREATE TRIGGER ai-history_completed_at
|
|
128
|
+
BEFORE UPDATE ON "ai-history"
|
|
121
129
|
FOR EACH ROW
|
|
122
|
-
EXECUTE FUNCTION
|
|
130
|
+
EXECUTE FUNCTION update_ai-history_completed_at();
|
|
123
131
|
|
|
124
132
|
-- =============================================
|
|
125
133
|
-- CONSTRAINT: Token Split Validation
|
|
126
134
|
-- =============================================
|
|
127
135
|
-- Ensures data integrity: tokensUsed = tokensInput + tokensOutput when both present
|
|
128
|
-
ALTER TABLE "
|
|
136
|
+
ALTER TABLE "ai-history"
|
|
129
137
|
ADD CONSTRAINT chk_tokens_sum
|
|
130
138
|
CHECK (
|
|
131
139
|
("tokensInput" IS NULL AND "tokensOutput" IS NULL)
|
|
@@ -136,23 +144,24 @@ CHECK (
|
|
|
136
144
|
-- =============================================
|
|
137
145
|
-- COMMENTS
|
|
138
146
|
-- =============================================
|
|
139
|
-
COMMENT ON TABLE "
|
|
140
|
-
COMMENT ON COLUMN "
|
|
141
|
-
COMMENT ON COLUMN "
|
|
142
|
-
COMMENT ON COLUMN "
|
|
143
|
-
COMMENT ON COLUMN "
|
|
144
|
-
COMMENT ON COLUMN "
|
|
145
|
-
COMMENT ON COLUMN "
|
|
146
|
-
COMMENT ON COLUMN "
|
|
147
|
-
COMMENT ON COLUMN "
|
|
148
|
-
COMMENT ON COLUMN "
|
|
149
|
-
COMMENT ON COLUMN "
|
|
150
|
-
COMMENT ON COLUMN "
|
|
151
|
-
COMMENT ON COLUMN "
|
|
152
|
-
COMMENT ON COLUMN "
|
|
153
|
-
COMMENT ON COLUMN "
|
|
154
|
-
COMMENT ON COLUMN "
|
|
155
|
-
COMMENT ON COLUMN "
|
|
147
|
+
COMMENT ON TABLE "ai-history" IS 'Generic audit trail for AI interactions with cost and performance metrics';
|
|
148
|
+
COMMENT ON COLUMN "ai-history"."userId" IS 'User who initiated the AI operation';
|
|
149
|
+
COMMENT ON COLUMN "ai-history"."relatedEntityType" IS 'Type of entity this operation relates to (e.g., ''contents'', ''products'', ''campaigns'')';
|
|
150
|
+
COMMENT ON COLUMN "ai-history"."relatedEntityId" IS 'ID of the related entity (polymorphic relationship)';
|
|
151
|
+
COMMENT ON COLUMN "ai-history".operation IS 'Type of AI operation: generate, refine, analyze, chat, completion, or other';
|
|
152
|
+
COMMENT ON COLUMN "ai-history".model IS 'AI model used (e.g., claude-3-5-sonnet-20241022, gpt-4)';
|
|
153
|
+
COMMENT ON COLUMN "ai-history".provider IS 'AI provider: anthropic, openai, etc.';
|
|
154
|
+
COMMENT ON COLUMN "ai-history".status IS 'Processing status: pending, processing, completed, or failed';
|
|
155
|
+
COMMENT ON COLUMN "ai-history"."tokensUsed" IS 'Total tokens consumed (input + output) - kept for backward compatibility';
|
|
156
|
+
COMMENT ON COLUMN "ai-history"."tokensInput" IS 'Input tokens (prompt) - for precise cost calculation with asymmetric pricing';
|
|
157
|
+
COMMENT ON COLUMN "ai-history"."tokensOutput" IS 'Output tokens (completion) - for precise cost calculation with asymmetric pricing';
|
|
158
|
+
COMMENT ON COLUMN "ai-history"."creditsUsed" IS 'Credits deducted for this operation';
|
|
159
|
+
COMMENT ON COLUMN "ai-history"."estimatedCost" IS 'Cost in USD based on model pricing';
|
|
160
|
+
COMMENT ON COLUMN "ai-history"."balanceAfter" IS 'User credit balance after this operation';
|
|
161
|
+
COMMENT ON COLUMN "ai-history"."errorMessage" IS 'Error message if operation failed';
|
|
162
|
+
COMMENT ON COLUMN "ai-history"."createdAt" IS 'When the AI operation was initiated';
|
|
163
|
+
COMMENT ON COLUMN "ai-history"."updatedAt" IS 'When the record was last updated';
|
|
164
|
+
COMMENT ON COLUMN "ai-history"."completedAt" IS 'When the AI operation finished (success or failure)';
|
|
156
165
|
|
|
157
166
|
-- =============================================
|
|
158
167
|
-- MIGRATION COMPLETE
|
|
@@ -162,6 +171,6 @@ DO $$
|
|
|
162
171
|
BEGIN
|
|
163
172
|
RAISE NOTICE 'AI History entity migration completed successfully!';
|
|
164
173
|
RAISE NOTICE 'Plugin: ai';
|
|
165
|
-
RAISE NOTICE 'Table created:
|
|
174
|
+
RAISE NOTICE 'Table created: ai-history';
|
|
166
175
|
RAISE NOTICE 'RLS policies enabled for user isolation';
|
|
167
176
|
END $$;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
-- Entity: ai-history
|
|
5
5
|
-- =============================================
|
|
6
6
|
--
|
|
7
|
-
-- This migration adds comprehensive metadata capabilities through
|
|
7
|
+
-- This migration adds comprehensive metadata capabilities through ai-history_metas table
|
|
8
8
|
--
|
|
9
9
|
-- Purpose: Flexible metadata storage for AI operations
|
|
10
10
|
-- - Better query performance (indexed key-value lookups)
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
-- AI_HISTORY_METAS TABLE
|
|
30
30
|
-- =============================================
|
|
31
31
|
|
|
32
|
-
CREATE TABLE IF NOT EXISTS public."
|
|
32
|
+
CREATE TABLE IF NOT EXISTS public."ai-history_metas" (
|
|
33
33
|
id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
|
|
34
|
-
"entityId" TEXT NOT NULL REFERENCES public."
|
|
34
|
+
"entityId" TEXT NOT NULL REFERENCES public."ai-history"(id) ON DELETE CASCADE,
|
|
35
35
|
"metaKey" TEXT NOT NULL,
|
|
36
36
|
"metaValue" JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
37
37
|
"dataType" TEXT DEFAULT 'json' CHECK ("dataType" IN ('string', 'number', 'boolean', 'json', 'array')),
|
|
@@ -41,54 +41,54 @@ CREATE TABLE IF NOT EXISTS public."ai_history_metas" (
|
|
|
41
41
|
"updatedAt" TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
42
42
|
|
|
43
43
|
-- Prevent duplicate keys per history record
|
|
44
|
-
CONSTRAINT
|
|
44
|
+
CONSTRAINT ai-history_metas_unique_key UNIQUE ("entityId", "metaKey")
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
-- Trigger for auto-updating updatedAt (using Better Auth's function)
|
|
48
|
-
CREATE TRIGGER
|
|
49
|
-
BEFORE UPDATE ON public."
|
|
48
|
+
CREATE TRIGGER ai-history_metas_set_updated_at
|
|
49
|
+
BEFORE UPDATE ON public."ai-history_metas"
|
|
50
50
|
FOR EACH ROW EXECUTE FUNCTION public.set_updated_at();
|
|
51
51
|
|
|
52
52
|
-- Indexes for efficient queries
|
|
53
|
-
CREATE INDEX
|
|
54
|
-
CREATE INDEX
|
|
55
|
-
CREATE INDEX
|
|
53
|
+
CREATE INDEX idx_ai-history_metas_entity_id ON public."ai-history_metas"("entityId");
|
|
54
|
+
CREATE INDEX idx_ai-history_metas_key ON public."ai-history_metas"("metaKey");
|
|
55
|
+
CREATE INDEX idx_ai-history_metas_composite ON public."ai-history_metas"("entityId", "metaKey");
|
|
56
56
|
|
|
57
57
|
-- GIN index for JSONB queries (enables @>, ?, ?&, ?| operators)
|
|
58
|
-
CREATE INDEX
|
|
58
|
+
CREATE INDEX idx_ai-history_metas_value_gin ON public."ai-history_metas" USING GIN ("metaValue");
|
|
59
59
|
|
|
60
60
|
-- RLS Policies
|
|
61
|
-
ALTER TABLE public."
|
|
61
|
+
ALTER TABLE public."ai-history_metas" ENABLE ROW LEVEL SECURITY;
|
|
62
62
|
|
|
63
63
|
-- Cleanup existing policies
|
|
64
|
-
DROP POLICY IF EXISTS "AI history metas owner can do all" ON public."
|
|
65
|
-
DROP POLICY IF EXISTS "AI history metas inherit parent access" ON public."
|
|
64
|
+
DROP POLICY IF EXISTS "AI history metas owner can do all" ON public."ai-history_metas";
|
|
65
|
+
DROP POLICY IF EXISTS "AI history metas inherit parent access" ON public."ai-history_metas";
|
|
66
66
|
|
|
67
|
-
-- Policy: Inherit access from parent
|
|
67
|
+
-- Policy: Inherit access from parent ai-history record
|
|
68
68
|
CREATE POLICY "AI history metas inherit parent access"
|
|
69
|
-
ON public."
|
|
69
|
+
ON public."ai-history_metas"
|
|
70
70
|
FOR ALL TO authenticated
|
|
71
71
|
USING (
|
|
72
72
|
EXISTS (
|
|
73
|
-
SELECT 1 FROM public."
|
|
74
|
-
WHERE "
|
|
75
|
-
AND "
|
|
73
|
+
SELECT 1 FROM public."ai-history"
|
|
74
|
+
WHERE "ai-history".id = "ai-history_metas"."entityId"
|
|
75
|
+
AND "ai-history"."userId" = public.get_auth_user_id()
|
|
76
76
|
)
|
|
77
77
|
)
|
|
78
78
|
WITH CHECK (
|
|
79
79
|
EXISTS (
|
|
80
|
-
SELECT 1 FROM public."
|
|
81
|
-
WHERE "
|
|
82
|
-
AND "
|
|
80
|
+
SELECT 1 FROM public."ai-history"
|
|
81
|
+
WHERE "ai-history".id = "ai-history_metas"."entityId"
|
|
82
|
+
AND "ai-history"."userId" = public.get_auth_user_id()
|
|
83
83
|
)
|
|
84
84
|
);
|
|
85
85
|
|
|
86
86
|
-- Comments for documentation
|
|
87
|
-
COMMENT ON TABLE public."
|
|
88
|
-
COMMENT ON COLUMN public."
|
|
89
|
-
COMMENT ON COLUMN public."
|
|
90
|
-
COMMENT ON COLUMN public."
|
|
91
|
-
COMMENT ON COLUMN public."
|
|
87
|
+
COMMENT ON TABLE public."ai-history_metas" IS 'Flexible metadata storage for AI history records. Supports any key-value pairs with JSONB values.';
|
|
88
|
+
COMMENT ON COLUMN public."ai-history_metas"."metaValue" IS 'JSONB value allows storing any data structure (string, number, boolean, object, array)';
|
|
89
|
+
COMMENT ON COLUMN public."ai-history_metas"."dataType" IS 'Hint for parsing metaValue on client side (actual type is always JSONB in DB)';
|
|
90
|
+
COMMENT ON COLUMN public."ai-history_metas"."isPublic" IS 'Whether this meta is publicly accessible or private to owner';
|
|
91
|
+
COMMENT ON COLUMN public."ai-history_metas"."isSearchable" IS 'Whether this meta should be included in search operations';
|
|
92
92
|
|
|
93
93
|
-- =============================================
|
|
94
94
|
-- MIGRATION COMPLETE
|
|
@@ -97,7 +97,7 @@ COMMENT ON COLUMN public."ai_history_metas"."isSearchable" IS 'Whether this meta
|
|
|
97
97
|
DO $$
|
|
98
98
|
BEGIN
|
|
99
99
|
RAISE NOTICE 'AI History metadata migration completed successfully!';
|
|
100
|
-
RAISE NOTICE 'Created:
|
|
100
|
+
RAISE NOTICE 'Created: ai-history_metas table for flexible metadata';
|
|
101
101
|
RAISE NOTICE 'Performance: GIN indexes for fast JSONB queries';
|
|
102
|
-
RAISE NOTICE 'Security: RLS policies enabled on
|
|
102
|
+
RAISE NOTICE 'Security: RLS policies enabled on ai-history_metas';
|
|
103
103
|
END $$;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/plugin-ai",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.73",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./plugin.config.ts",
|
|
6
6
|
"requiredPlugins": [],
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"ollama-ai-provider": "^1.2.0"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
+
"@nextsparkjs/core": "workspace:*",
|
|
15
16
|
"@tanstack/react-query": "^5.0.0",
|
|
16
17
|
"lucide-react": "^0.539.0",
|
|
17
18
|
"next": "^15.0.0",
|
|
18
19
|
"react": "^19.0.0",
|
|
19
20
|
"react-dom": "^19.0.0",
|
|
20
|
-
"zod": "^4.0.0"
|
|
21
|
-
"@nextsparkjs/core": "0.1.0-beta.68"
|
|
21
|
+
"zod": "^4.0.0"
|
|
22
22
|
},
|
|
23
23
|
"nextspark": {
|
|
24
24
|
"type": "plugin",
|
|
25
25
|
"name": "ai"
|
|
26
26
|
}
|
|
27
|
-
}
|
|
27
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 NextSpark
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|