apps 0.0.1-beta.37 → 0.0.1-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/framework-reference.json +1 -1
- package/js/{chunk-GHDZEEPO.js → chunk-27TDXHRX.js} +395 -82
- package/js/{chunk-KOOJUMLR.js → chunk-3MMG2H6M.js} +2 -2
- package/js/{chunk-LQBR7AI7.js → chunk-3V575NIW.js} +217 -19
- package/js/{chunk-U74JVKTQ.js → chunk-5NIEOXRZ.js} +7 -7
- package/js/{chunk-BWUHMKHQ.js → chunk-5TJA7364.js} +2 -2
- package/js/{chunk-7KEKFBV7.js → chunk-7CSHVXVR.js} +3 -3
- package/js/{chunk-3LRFKLUX.js → chunk-BO4US6DZ.js} +9 -49
- package/js/{chunk-A4O72Z3A.js → chunk-DKUEYTYD.js} +167 -30
- package/js/{chunk-ENJCQWVF.js → chunk-E4BWL7KQ.js} +3 -3
- package/js/{chunk-CAOHGMNW.js → chunk-F3TBO2U3.js} +7 -94
- package/js/{chunk-POOIHRPF.js → chunk-GHXRRFZA.js} +11 -34
- package/js/{chunk-RSNZDT4L.js → chunk-JTMDWPCH.js} +2 -2
- package/js/{chunk-YW333DH3.js → chunk-KANDIVIH.js} +4 -4
- package/js/{chunk-2FWXCU5I.js → chunk-KAQD3DTI.js} +1 -1
- package/js/{chunk-QQKHJ72Y.js → chunk-LVWX4UWK.js} +9 -9
- package/js/{chunk-KEZ4YZSP.js → chunk-MLHNVYHT.js} +2 -2
- package/js/{chunk-IJQ5LE74.js → chunk-MXDKXAY4.js} +363 -401
- package/js/{chunk-BI6R577B.js → chunk-P7MGDPFD.js} +2 -2
- package/js/{chunk-24EIFQYZ.js → chunk-PCV73KVK.js} +35 -10
- package/js/{chunk-JU7F4PRK.js → chunk-RIXVGVA6.js} +2 -2
- package/js/{chunk-D45FU4TZ.js → chunk-SDHD6J37.js} +3 -3
- package/js/{chunk-UCOMVHGW.js → chunk-U5PFZDVB.js} +2 -2
- package/js/{chunk-PHO7HXTC.js → chunk-VIU2XXA7.js} +294 -47
- package/js/{chunk-TADLIUEU.js → chunk-VJQXXOQ3.js} +2 -2
- package/js/{chunk-NHCFIWN5.js → chunk-W2NV54JD.js} +1 -1
- package/js/{chunk-BI45HZWM.js → chunk-YQ35E7KS.js} +1 -1
- package/js/{chunk-WDBUOIWV.js → chunk-ZUKBIHMK.js} +3 -3
- package/js/client.js +13 -17
- package/js/contracts.js +16 -21
- package/js/effect.js +19 -24
- package/js/graphql.js +21 -26
- package/js/host.js +19 -24
- package/js/index.js +13 -26
- package/js/mcp/effect.js +21 -26
- package/js/mcp/stdio.js +21 -26
- package/js/mcp.js +23 -28
- package/js/openapi.js +17 -21
- package/js/react.js +2 -3
- package/js/skills/effect.js +6 -7
- package/js/skills.js +15 -17
- package/js/storage/facet.js +1 -214
- package/js/ui/auth/contracts.js +2 -2
- package/js/ui/auth.js +5 -5
- package/js/ui/contracts.js +5 -6
- package/js/ui/serving.js +10 -11
- package/package.json +1 -2
- package/runtime.json +1 -1
- package/types/apps/src/contracts/app.d.ts +0 -2
- package/types/apps/src/contracts/context.d.ts +12 -11
- package/types/apps/src/contracts/host.d.ts +10 -8
- package/types/apps/src/contracts/live.d.ts +2 -0
- package/types/apps/src/contracts/operations.d.ts +3 -3
- package/types/apps/src/contracts/protocol-version.d.ts +2 -2
- package/types/apps/src/contracts/protocols/10.d.ts +1450 -0
- package/types/apps/src/contracts/protocols/4.d.ts +3 -3
- package/types/apps/src/contracts/protocols/5.d.ts +1 -1
- package/types/apps/src/contracts/protocols/6.d.ts +1 -1
- package/types/apps/src/contracts/protocols/7.d.ts +1 -1
- package/types/apps/src/contracts/sql.d.ts +58 -0
- package/types/apps/src/facet.d.ts +4 -5
- package/types/apps/src/implementation/openapi-compile.d.ts +2 -2
- package/types/apps/src/implementation/schema.d.ts +1 -10
- package/types/apps/src/implementation/sql.d.ts +66 -0
- package/types/apps/src/index.d.ts +1 -2
- package/types/telemetry/src/transport.d.ts +8 -1
- package/js/chunk-73AV3JVU.js +0 -186
- package/js/chunk-HDAQBRT5.js +0 -1254
- package/js/chunk-IU7CCCUC.js +0 -630
- package/js/chunk-NHUHTWAF.js +0 -0
- package/js/chunk-V5DWGYRK.js +0 -268
- package/js/chunk-Y3XN4X4Q.js +0 -19
- package/types/app-data/src/implementation/cursor.d.ts +0 -10
- package/types/app-data/src/implementation/index-key.d.ts +0 -7
- package/types/app-data/src/implementation/promise.d.ts +0 -68
- package/types/app-data/src/implementation/range.d.ts +0 -8
- package/types/app-data/src/implementation/schema.d.ts +0 -18
- package/types/app-data/src/implementation/sqlite.d.ts +0 -11
- package/types/app-data/src/index.d.ts +0 -4
- package/types/apps/src/contracts/storage.d.ts +0 -68
- package/types/apps/src/implementation/storage.d.ts +0 -15
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
makeCache
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RIXVGVA6.js";
|
|
4
4
|
import {
|
|
5
5
|
accountSecrets,
|
|
6
6
|
boundFailureMessage,
|
|
@@ -11,35 +11,30 @@ import {
|
|
|
11
11
|
parseSkillLoadFailed,
|
|
12
12
|
readCatalog,
|
|
13
13
|
routerSkills
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BO4US6DZ.js";
|
|
15
15
|
import {
|
|
16
16
|
appInvocationFetch
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-SDHD6J37.js";
|
|
18
18
|
import {
|
|
19
19
|
folderSkillsEffect
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-5TJA7364.js";
|
|
21
21
|
import {
|
|
22
22
|
ResponseStatusError,
|
|
23
|
-
authorDatabase,
|
|
24
23
|
isApp,
|
|
25
|
-
toEffectApp
|
|
26
|
-
|
|
27
|
-
} from "./chunk-CAOHGMNW.js";
|
|
28
|
-
import {
|
|
29
|
-
parseDatabaseSchema
|
|
30
|
-
} from "./chunk-IU7CCCUC.js";
|
|
24
|
+
toEffectApp
|
|
25
|
+
} from "./chunk-F3TBO2U3.js";
|
|
31
26
|
import {
|
|
32
27
|
declaredOperations,
|
|
33
28
|
fromPromise,
|
|
34
29
|
locate,
|
|
35
30
|
nativeOperation,
|
|
36
31
|
toPromise
|
|
37
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-7CSHVXVR.js";
|
|
38
33
|
import {
|
|
39
34
|
accountProviderError,
|
|
40
35
|
httpProviderError,
|
|
41
36
|
parseProviderError
|
|
42
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-E4BWL7KQ.js";
|
|
43
38
|
import {
|
|
44
39
|
AccountCheckResult,
|
|
45
40
|
DeclaredProvider,
|
|
@@ -85,18 +80,20 @@ import {
|
|
|
85
80
|
approvalElicitation,
|
|
86
81
|
defaultWebhookTransportLimits,
|
|
87
82
|
maxInputProblems,
|
|
83
|
+
migrationsDirectory,
|
|
84
|
+
reservedTablePrefix,
|
|
88
85
|
workflowDurationMillis
|
|
89
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-3V575NIW.js";
|
|
90
87
|
import {
|
|
91
88
|
CacheError
|
|
92
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-P7MGDPFD.js";
|
|
93
90
|
import {
|
|
94
91
|
AppSkills,
|
|
95
92
|
SkillFile
|
|
96
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-MLHNVYHT.js";
|
|
97
94
|
import {
|
|
98
95
|
captureTelemetry
|
|
99
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-PCV73KVK.js";
|
|
100
97
|
import {
|
|
101
98
|
allowedValues,
|
|
102
99
|
decoderOf,
|
|
@@ -107,11 +104,11 @@ import {
|
|
|
107
104
|
maxAlternativeKeys,
|
|
108
105
|
objectShape,
|
|
109
106
|
unionShape
|
|
110
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-GHXRRFZA.js";
|
|
111
108
|
import {
|
|
112
109
|
JsonObject,
|
|
113
110
|
JsonValue
|
|
114
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-YQ35E7KS.js";
|
|
115
112
|
import {
|
|
116
113
|
Base64_exports,
|
|
117
114
|
Cause_exports,
|
|
@@ -124,7 +121,7 @@ import {
|
|
|
124
121
|
SchemaIssue_exports,
|
|
125
122
|
Schema_exports,
|
|
126
123
|
Stream_exports
|
|
127
|
-
} from "./chunk-
|
|
124
|
+
} from "./chunk-MXDKXAY4.js";
|
|
128
125
|
|
|
129
126
|
// src/implementation/elicitation.ts
|
|
130
127
|
var prepareElicitation = (input) => Effect_exports.gen(function* () {
|
|
@@ -575,6 +572,333 @@ var dispatchWebhook = (definition, command, context, accounts) => Effect_exports
|
|
|
575
572
|
);
|
|
576
573
|
});
|
|
577
574
|
|
|
575
|
+
// src/implementation/sql.ts
|
|
576
|
+
var receipts = `${reservedTablePrefix}step_receipts`;
|
|
577
|
+
var migrationsTable = `${reservedTablePrefix}migrations`;
|
|
578
|
+
var legacyRows = `${reservedTablePrefix}legacy_rows`;
|
|
579
|
+
var materialize = (cursor) => {
|
|
580
|
+
const rows = cursor.toArray();
|
|
581
|
+
return {
|
|
582
|
+
columnNames: cursor.columnNames,
|
|
583
|
+
rowsRead: cursor.rowsRead,
|
|
584
|
+
rowsWritten: cursor.rowsWritten,
|
|
585
|
+
toArray: () => [...rows],
|
|
586
|
+
one: () => {
|
|
587
|
+
if (rows.length !== 1)
|
|
588
|
+
throw new Error(`Expected exactly one row, but the statement returned ${rows.length}.`);
|
|
589
|
+
return rows[0];
|
|
590
|
+
},
|
|
591
|
+
[Symbol.iterator]: () => rows[Symbol.iterator]()
|
|
592
|
+
};
|
|
593
|
+
};
|
|
594
|
+
var isThenable = (value) => (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
595
|
+
var missingDatabase = () => {
|
|
596
|
+
throw new Error(
|
|
597
|
+
`This app has no database. Add its first migration, such as ${migrationsDirectory}/0001_create_notes.sql with a CREATE TABLE statement, and deploy again.`
|
|
598
|
+
);
|
|
599
|
+
};
|
|
600
|
+
var noDatabase = { exec: missingDatabase, transaction: missingDatabase };
|
|
601
|
+
var settings = [
|
|
602
|
+
"foreign_keys",
|
|
603
|
+
"defer_foreign_keys",
|
|
604
|
+
"ignore_check_constraints",
|
|
605
|
+
"legacy_alter_table",
|
|
606
|
+
"recursive_triggers",
|
|
607
|
+
"reverse_unordered_selects"
|
|
608
|
+
];
|
|
609
|
+
var readSettings = (storage) => new Map(
|
|
610
|
+
settings.map((name) => [name, Number(storage.sql.exec(`PRAGMA ${name}`).toArray()[0]?.[name])])
|
|
611
|
+
);
|
|
612
|
+
var changedSetting = (storage, baseline) => {
|
|
613
|
+
const current = readSettings(storage);
|
|
614
|
+
return settings.find((name) => current.get(name) !== baseline.get(name));
|
|
615
|
+
};
|
|
616
|
+
var restoreSettings = (storage, baseline) => {
|
|
617
|
+
const current = readSettings(storage);
|
|
618
|
+
for (const [name, value] of baseline)
|
|
619
|
+
if (current.get(name) !== value) storage.sql.exec(`PRAGMA ${name} = ${value}`);
|
|
620
|
+
storage.sql.exec("PRAGMA case_sensitive_like = OFF");
|
|
621
|
+
};
|
|
622
|
+
var ReadRolledBack = class extends Error {
|
|
623
|
+
};
|
|
624
|
+
var authorSql = (storage, options) => {
|
|
625
|
+
let closed = false;
|
|
626
|
+
const live = () => {
|
|
627
|
+
if (closed || options.signal.aborted)
|
|
628
|
+
throw new Error("This call has ended, so its ctx.sql no longer runs statements.");
|
|
629
|
+
};
|
|
630
|
+
let open = false;
|
|
631
|
+
let transactions = 0;
|
|
632
|
+
const baseline = readSettings(storage);
|
|
633
|
+
const checkSettings = () => {
|
|
634
|
+
const changed = changedSetting(storage, baseline);
|
|
635
|
+
if (changed !== void 0)
|
|
636
|
+
throw refuse(
|
|
637
|
+
new Error(
|
|
638
|
+
`SQLite connection settings belong to Executor, so app code cannot change PRAGMA ${changed}; the statement was rolled back. Migrations may change settings while they run.`
|
|
639
|
+
)
|
|
640
|
+
);
|
|
641
|
+
};
|
|
642
|
+
const changes = () => Number(storage.sql.exec("SELECT total_changes() AS n").toArray()[0]?.n);
|
|
643
|
+
let violation;
|
|
644
|
+
const refuse = (error) => {
|
|
645
|
+
if (open) violation ??= error;
|
|
646
|
+
return error;
|
|
647
|
+
};
|
|
648
|
+
const run = (query, bindings, mode) => {
|
|
649
|
+
try {
|
|
650
|
+
return runStatement(query, bindings, mode);
|
|
651
|
+
} finally {
|
|
652
|
+
restoreSettings(storage, baseline);
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
const runStatement = (query, bindings, mode) => {
|
|
656
|
+
live();
|
|
657
|
+
if (mode === "write") {
|
|
658
|
+
const statement = () => {
|
|
659
|
+
const cursor = materialize(storage.sql.exec(query, ...bindings));
|
|
660
|
+
checkSettings();
|
|
661
|
+
return cursor;
|
|
662
|
+
};
|
|
663
|
+
if (!open) return storage.transactionSync(statement);
|
|
664
|
+
try {
|
|
665
|
+
return statement();
|
|
666
|
+
} catch (error) {
|
|
667
|
+
refuse(error instanceof Error ? error : new Error(String(error)));
|
|
668
|
+
throw error;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (open) {
|
|
672
|
+
return runStatement(query, bindings, "write");
|
|
673
|
+
}
|
|
674
|
+
const before = changes();
|
|
675
|
+
let read;
|
|
676
|
+
let changed = false;
|
|
677
|
+
try {
|
|
678
|
+
storage.transactionSync(() => {
|
|
679
|
+
read = materialize(storage.sql.exec(query, ...bindings));
|
|
680
|
+
changed = changes() !== before;
|
|
681
|
+
checkSettings();
|
|
682
|
+
throw new ReadRolledBack();
|
|
683
|
+
});
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (!(error instanceof ReadRolledBack)) throw error;
|
|
686
|
+
}
|
|
687
|
+
if (changed || read === void 0)
|
|
688
|
+
throw new Error(
|
|
689
|
+
options.step !== void 0 ? "A workflow step mutation writes only inside ctx.sql.transaction(...), so a retried step applies its writes once." : "Queries are read-only. Change data from a mutation."
|
|
690
|
+
);
|
|
691
|
+
return read;
|
|
692
|
+
};
|
|
693
|
+
const reader = {
|
|
694
|
+
exec: (query, ...bindings) => run(query, bindings, "read")
|
|
695
|
+
};
|
|
696
|
+
const transactionHandle = () => {
|
|
697
|
+
let active = true;
|
|
698
|
+
const tx = {
|
|
699
|
+
exec: (query, ...bindings) => {
|
|
700
|
+
if (!active)
|
|
701
|
+
throw new Error("This transaction has ended, so its tx no longer runs statements.");
|
|
702
|
+
return run(query, bindings, "write");
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
return {
|
|
706
|
+
tx,
|
|
707
|
+
end: () => {
|
|
708
|
+
active = false;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
const transaction = (work) => {
|
|
713
|
+
live();
|
|
714
|
+
if (open) throw new Error("ctx.sql.transaction(...) cannot be nested.");
|
|
715
|
+
const step = options.step;
|
|
716
|
+
if (step !== void 0 && transactions > 0)
|
|
717
|
+
throw new Error(
|
|
718
|
+
"A workflow step mutation opens at most one ctx.sql.transaction(...), which records the step's result."
|
|
719
|
+
);
|
|
720
|
+
transactions += 1;
|
|
721
|
+
violation = void 0;
|
|
722
|
+
const handle = transactionHandle();
|
|
723
|
+
return storage.transactionSync(() => {
|
|
724
|
+
open = true;
|
|
725
|
+
try {
|
|
726
|
+
const complete = () => {
|
|
727
|
+
const value = work(handle.tx);
|
|
728
|
+
if (isThenable(value))
|
|
729
|
+
throw new Error(
|
|
730
|
+
"ctx.sql.transaction(...) callbacks are synchronous and cannot await. Call outside services before or after the transaction."
|
|
731
|
+
);
|
|
732
|
+
if (violation !== void 0) throw violation;
|
|
733
|
+
return value;
|
|
734
|
+
};
|
|
735
|
+
if (step === void 0) return complete();
|
|
736
|
+
storage.sql.exec(
|
|
737
|
+
`CREATE TABLE IF NOT EXISTS ${receipts} (id TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, result TEXT NOT NULL) WITHOUT ROWID`
|
|
738
|
+
);
|
|
739
|
+
const saved = storage.sql.exec(`SELECT fingerprint, result FROM ${receipts} WHERE id = ?`, step.key).toArray()[0];
|
|
740
|
+
if (saved !== void 0) {
|
|
741
|
+
if (saved.fingerprint !== step.fingerprint)
|
|
742
|
+
throw new Error("This workflow step already ran with different input.");
|
|
743
|
+
return JSON.parse(String(saved.result));
|
|
744
|
+
}
|
|
745
|
+
const encoded = JSON.stringify(complete() ?? null);
|
|
746
|
+
storage.sql.exec(
|
|
747
|
+
`INSERT INTO ${receipts} (id, fingerprint, result) VALUES (?, ?, ?)`,
|
|
748
|
+
step.key,
|
|
749
|
+
step.fingerprint,
|
|
750
|
+
encoded
|
|
751
|
+
);
|
|
752
|
+
return JSON.parse(encoded);
|
|
753
|
+
} finally {
|
|
754
|
+
open = false;
|
|
755
|
+
handle.end();
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
};
|
|
759
|
+
const writer = {
|
|
760
|
+
// A step's writes go through its one transaction, which also records its receipt.
|
|
761
|
+
exec: (query, ...bindings) => run(query, bindings, options.step ? "read" : "write"),
|
|
762
|
+
transaction
|
|
763
|
+
};
|
|
764
|
+
return {
|
|
765
|
+
reader,
|
|
766
|
+
writer,
|
|
767
|
+
close: () => {
|
|
768
|
+
closed = true;
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
};
|
|
772
|
+
var MigrationFileInvalid = class extends Schema_exports.TaggedError()(
|
|
773
|
+
"MigrationFileInvalid",
|
|
774
|
+
{ path: Schema_exports.String, reason: Schema_exports.String }
|
|
775
|
+
) {
|
|
776
|
+
get message() {
|
|
777
|
+
return `${this.path}: ${this.reason}`;
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
var MigrationHistoryChanged = class extends Schema_exports.TaggedError()(
|
|
781
|
+
"MigrationHistoryChanged",
|
|
782
|
+
{ reason: Schema_exports.String }
|
|
783
|
+
) {
|
|
784
|
+
get message() {
|
|
785
|
+
return `${this.reason} Applied migrations cannot change: restore the original file and add a new migration instead. Nothing was applied; the previous deployment is still active.`;
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
var MigrationFailed = class extends Schema_exports.TaggedError()("MigrationFailed", {
|
|
789
|
+
path: Schema_exports.String,
|
|
790
|
+
reason: Schema_exports.String
|
|
791
|
+
}) {
|
|
792
|
+
get message() {
|
|
793
|
+
return `${this.path} failed: ${this.reason}. No migrations were applied; the previous deployment is still active.`;
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
var migrationName = /^(\d+)_[A-Za-z0-9_-]+\.sql$/;
|
|
797
|
+
var sha256 = (text) => Effect_exports.promise(() => crypto.subtle.digest("SHA-256", new TextEncoder().encode(text))).pipe(
|
|
798
|
+
Effect_exports.map(
|
|
799
|
+
(digest) => Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")
|
|
800
|
+
)
|
|
801
|
+
);
|
|
802
|
+
var hasMigrations = (files) => files.some(
|
|
803
|
+
(file) => file.path.startsWith(`${migrationsDirectory}/`) && file.path.endsWith(".sql")
|
|
804
|
+
);
|
|
805
|
+
var migrationsOf = (files) => Effect_exports.gen(function* () {
|
|
806
|
+
const found = [];
|
|
807
|
+
for (const file of files) {
|
|
808
|
+
if (!file.path.startsWith(`${migrationsDirectory}/`) || !file.path.endsWith(".sql")) continue;
|
|
809
|
+
const name = file.path.slice(migrationsDirectory.length + 1);
|
|
810
|
+
const match = migrationName.exec(name);
|
|
811
|
+
if (name.includes("/") || match === null)
|
|
812
|
+
return yield* new MigrationFileInvalid({
|
|
813
|
+
path: file.path,
|
|
814
|
+
reason: "migrations are files directly in migrations/ named like 0001_create_notes.sql: a number that orders them, an underscore, then a name."
|
|
815
|
+
});
|
|
816
|
+
const content = file.content.replaceAll("\r\n", "\n");
|
|
817
|
+
found.push({
|
|
818
|
+
path: file.path,
|
|
819
|
+
order: Number(match[1]),
|
|
820
|
+
content,
|
|
821
|
+
hash: yield* sha256(content)
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
const ordered = [...found].sort((left, right) => left.order - right.order);
|
|
825
|
+
for (const [index, migration] of ordered.entries()) {
|
|
826
|
+
const previous = ordered[index - 1];
|
|
827
|
+
if (previous !== void 0 && previous.order === migration.order)
|
|
828
|
+
return yield* new MigrationFileInvalid({
|
|
829
|
+
path: migration.path,
|
|
830
|
+
reason: `it has the same number as ${previous.path}; give each migration its own number.`
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
return ordered;
|
|
834
|
+
});
|
|
835
|
+
var History = Schema_exports.Array(
|
|
836
|
+
Schema_exports.Struct({ id: Schema_exports.Number, path: Schema_exports.String, hash: Schema_exports.String })
|
|
837
|
+
);
|
|
838
|
+
var migrate = (storage, files) => Effect_exports.gen(function* () {
|
|
839
|
+
const migrations = yield* migrationsOf(files);
|
|
840
|
+
const baseline = readSettings(storage);
|
|
841
|
+
return yield* Effect_exports.sync(
|
|
842
|
+
() => storage.transactionSync(() => {
|
|
843
|
+
storage.sql.exec(
|
|
844
|
+
`CREATE TABLE IF NOT EXISTS ${migrationsTable} (id INTEGER PRIMARY KEY, path TEXT NOT NULL, hash TEXT NOT NULL, applied_at TEXT NOT NULL)`
|
|
845
|
+
);
|
|
846
|
+
const stored = storage.sql.exec("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'app_rows'").toArray().length > 0;
|
|
847
|
+
storage.sql.exec(`DROP VIEW IF EXISTS ${legacyRows}`);
|
|
848
|
+
storage.sql.exec(
|
|
849
|
+
`CREATE VIEW ${legacyRows} (table_name, id, body) AS ${stored ? "SELECT table_name, id, body FROM app_rows" : "SELECT '', '', '' WHERE 0"}`
|
|
850
|
+
);
|
|
851
|
+
const history = Schema_exports.decodeUnknownSync(History)(
|
|
852
|
+
storage.sql.exec(`SELECT id, path, hash FROM ${migrationsTable} ORDER BY id`).toArray()
|
|
853
|
+
);
|
|
854
|
+
for (const [index, applied] of history.entries()) {
|
|
855
|
+
const current = migrations[index];
|
|
856
|
+
if (current === void 0)
|
|
857
|
+
throw new MigrationHistoryChanged({
|
|
858
|
+
reason: `${applied.path} was applied to this app's database but is no longer in migrations/.`
|
|
859
|
+
});
|
|
860
|
+
if (current.path !== applied.path)
|
|
861
|
+
throw new MigrationHistoryChanged({
|
|
862
|
+
reason: `Migration ${index + 1} was applied as ${applied.path}, but the build has ${current.path} in its place.`
|
|
863
|
+
});
|
|
864
|
+
if (current.hash !== applied.hash)
|
|
865
|
+
throw new MigrationHistoryChanged({
|
|
866
|
+
reason: `${applied.path} changed after it was applied to this app's database.`
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
const pending = migrations.slice(history.length);
|
|
870
|
+
const appliedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
871
|
+
for (const [offset, migration] of pending.entries()) {
|
|
872
|
+
try {
|
|
873
|
+
storage.sql.exec(migration.content);
|
|
874
|
+
} catch (error) {
|
|
875
|
+
throw new MigrationFailed({
|
|
876
|
+
path: migration.path,
|
|
877
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
storage.sql.exec(
|
|
881
|
+
`INSERT INTO ${migrationsTable} (id, path, hash, applied_at) VALUES (?, ?, ?, ?)`,
|
|
882
|
+
history.length + offset + 1,
|
|
883
|
+
migration.path,
|
|
884
|
+
migration.hash,
|
|
885
|
+
appliedAt
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
return pending.map((migration, offset) => ({
|
|
889
|
+
id: history.length + offset + 1,
|
|
890
|
+
name: migration.path
|
|
891
|
+
}));
|
|
892
|
+
})
|
|
893
|
+
).pipe(
|
|
894
|
+
// Both are thrown inside the transaction so that it rolls back; they are expected failures.
|
|
895
|
+
Effect_exports.catchDefect(
|
|
896
|
+
(defect) => Schema_exports.is(MigrationFailed)(defect) || Schema_exports.is(MigrationHistoryChanged)(defect) ? Effect_exports.fail(defect) : Effect_exports.die(defect)
|
|
897
|
+
),
|
|
898
|
+
Effect_exports.ensuring(Effect_exports.sync(() => restoreSettings(storage, baseline)))
|
|
899
|
+
);
|
|
900
|
+
});
|
|
901
|
+
|
|
578
902
|
// src/implementation/cache.ts
|
|
579
903
|
var unavailableCache = {
|
|
580
904
|
transport: () => Effect_exports.fail(new CacheError({ reason: "unavailable" })),
|
|
@@ -720,7 +1044,7 @@ function providerDeclaration(provider) {
|
|
|
720
1044
|
`Account provider "${provider.name}" has an invalid declaration`
|
|
721
1045
|
);
|
|
722
1046
|
}
|
|
723
|
-
function requirements(slots,
|
|
1047
|
+
function requirements(slots, sql) {
|
|
724
1048
|
return Effect_exports.gen(function* () {
|
|
725
1049
|
const accounts = /* @__PURE__ */ new Map();
|
|
726
1050
|
for (const [slot, selection] of Object.entries(slots)) {
|
|
@@ -734,10 +1058,10 @@ function requirements(slots, database) {
|
|
|
734
1058
|
return yield* Schema_exports.decodeUnknownEffect(DeclaredRequirements)({
|
|
735
1059
|
accounts: Object.fromEntries(accounts),
|
|
736
1060
|
capabilities: { skills: true, toolIndex: true, skillSources: true, scheduledTools: true },
|
|
737
|
-
...
|
|
1061
|
+
...sql ? { sql: true } : {}
|
|
738
1062
|
}).pipe(
|
|
739
1063
|
Effect_exports.mapError(
|
|
740
|
-
(cause) => declarationInvalid("The app's account
|
|
1064
|
+
(cause) => declarationInvalid("The app's account declarations are invalid", cause)
|
|
741
1065
|
)
|
|
742
1066
|
);
|
|
743
1067
|
});
|
|
@@ -842,28 +1166,51 @@ function dispatch(app, request, context, signal) {
|
|
|
842
1166
|
);
|
|
843
1167
|
const native = toEffectApp(app);
|
|
844
1168
|
const secrets = accountSecrets(context.accounts);
|
|
845
|
-
const
|
|
846
|
-
const declared = yield* requirements(native.accounts,
|
|
847
|
-
if (request.operation === "requirements")
|
|
848
|
-
if (native.database !== void 0)
|
|
849
|
-
yield* parseDatabaseSchema(native.database.schema).pipe(
|
|
850
|
-
Effect_exports.catchTag(
|
|
851
|
-
"AppDatabaseError",
|
|
852
|
-
(cause) => Effect_exports.fail(
|
|
853
|
-
declarationInvalid("The app's account or database declarations are invalid", cause)
|
|
854
|
-
)
|
|
855
|
-
)
|
|
856
|
-
);
|
|
1169
|
+
const ownsSql = hasMigrations(context.files ?? []);
|
|
1170
|
+
const declared = yield* requirements(native.accounts, ownsSql);
|
|
1171
|
+
if (request.operation === "requirements")
|
|
857
1172
|
return yield* safe2(
|
|
858
1173
|
() => Schema_exports.decodeUnknownEffect(JsonValue)(declared),
|
|
859
1174
|
new HostDeclarationInvalid()
|
|
860
1175
|
);
|
|
1176
|
+
if (request.operation === "migrate") {
|
|
1177
|
+
if (!ownsSql) return yield* new HostOperationNotFound();
|
|
1178
|
+
const storage2 = context.storage;
|
|
1179
|
+
if (storage2 === void 0)
|
|
1180
|
+
return yield* new HostOperationFailed(
|
|
1181
|
+
failureDetail(new Error("This host gave the app no SQL storage."), secrets)
|
|
1182
|
+
);
|
|
1183
|
+
const sources = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(SkillFile))(
|
|
1184
|
+
context.files ?? []
|
|
1185
|
+
).pipe(Effect_exports.mapError(() => new HostDeclarationInvalid()));
|
|
1186
|
+
const applied = yield* migrate(storage2, sources).pipe(
|
|
1187
|
+
Effect_exports.mapError((error) => new HostOperationFailed(failureDetail(error, secrets))),
|
|
1188
|
+
Effect_exports.withSpan("app.sql.migrate")
|
|
1189
|
+
);
|
|
1190
|
+
return yield* safe2(
|
|
1191
|
+
() => Schema_exports.decodeUnknownEffect(JsonValue)(applied),
|
|
1192
|
+
new HostOutputInvalid()
|
|
1193
|
+
);
|
|
861
1194
|
}
|
|
862
1195
|
const lifetime = yield* Effect_exports.acquireRelease(
|
|
863
1196
|
Effect_exports.sync(() => new AbortController()),
|
|
864
1197
|
(controller) => Effect_exports.sync(() => controller.abort())
|
|
865
1198
|
);
|
|
866
1199
|
const invocationSignal = AbortSignal.any([signal, lifetime.signal]);
|
|
1200
|
+
const storage = context.storage;
|
|
1201
|
+
const sqlSession = (step) => !ownsSql ? Effect_exports.succeed({ reader: noDatabase, writer: noDatabase }) : storage === void 0 ? Effect_exports.fail(
|
|
1202
|
+
new HostOperationFailed(
|
|
1203
|
+
failureDetail(new Error("This host gave the app no SQL storage."), secrets)
|
|
1204
|
+
)
|
|
1205
|
+
) : Effect_exports.acquireRelease(
|
|
1206
|
+
Effect_exports.sync(
|
|
1207
|
+
() => authorSql(storage, {
|
|
1208
|
+
signal: invocationSignal,
|
|
1209
|
+
...step === void 0 ? {} : { step }
|
|
1210
|
+
})
|
|
1211
|
+
),
|
|
1212
|
+
(session2) => Effect_exports.sync(session2.close)
|
|
1213
|
+
);
|
|
867
1214
|
const deadline = context.deadline === void 0 ? void 0 : yield* safe2(
|
|
868
1215
|
() => Schema_exports.decodeUnknownEffect(InvocationDeadline)(context.deadline),
|
|
869
1216
|
new HostInputInvalid()
|
|
@@ -894,9 +1241,8 @@ function dispatch(app, request, context, signal) {
|
|
|
894
1241
|
deadline
|
|
895
1242
|
).pipe(withinDeadline);
|
|
896
1243
|
let running;
|
|
897
|
-
let transactionOpen = false;
|
|
898
1244
|
const delivery = (request2, signal2) => Effect_exports.suspend(
|
|
899
|
-
() =>
|
|
1245
|
+
() => running !== void 0 && context.elicitation !== void 0 ? context.elicitation(request2, signal2).pipe(
|
|
900
1246
|
Effect_exports.withSpan("app.tool.elicitation"),
|
|
901
1247
|
Effect_exports.provideContext(running.context)
|
|
902
1248
|
) : Effect_exports.fail(new ElicitationFailed({ reason: "unavailable" }))
|
|
@@ -1075,7 +1421,8 @@ function dispatch(app, request, context, signal) {
|
|
|
1075
1421
|
);
|
|
1076
1422
|
}
|
|
1077
1423
|
if (request.operation === "webhook-complete" || request.operation === "webhook-validate" || request.operation === "webhooks" || request.operation === "webhook-register" || request.operation === "webhook-handle" || request.operation === "webhook-unregister") {
|
|
1078
|
-
const
|
|
1424
|
+
const session2 = yield* sqlSession();
|
|
1425
|
+
return yield* dispatchWebhook(
|
|
1079
1426
|
definition,
|
|
1080
1427
|
request,
|
|
1081
1428
|
{
|
|
@@ -1085,23 +1432,10 @@ function dispatch(app, request, context, signal) {
|
|
|
1085
1432
|
workflows: workflowControls,
|
|
1086
1433
|
signal: bound.signal,
|
|
1087
1434
|
fetch: bound.fetch,
|
|
1088
|
-
|
|
1089
|
-
db: authorDatabase(native.database.tables, db, invocationSignal, true)
|
|
1090
|
-
}
|
|
1435
|
+
sql: session2.writer
|
|
1091
1436
|
},
|
|
1092
1437
|
Redacted_exports.value(context.accounts)
|
|
1093
1438
|
);
|
|
1094
|
-
if (native.database === void 0 || !["webhook-register", "webhook-handle", "webhook-unregister"].includes(request.operation))
|
|
1095
|
-
return yield* executeWebhook();
|
|
1096
|
-
const storage2 = context.storage ?? unavailableStorage;
|
|
1097
|
-
return yield* storage2.mutate(native.database.schema, executeWebhook).pipe(
|
|
1098
|
-
Effect_exports.catchTags({
|
|
1099
|
-
AppDatabaseError: storageFailure,
|
|
1100
|
-
DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
|
|
1101
|
-
AppStorageUnavailable: storageFailure,
|
|
1102
|
-
AppStorageError: storageFailure
|
|
1103
|
-
})
|
|
1104
|
-
);
|
|
1105
1439
|
}
|
|
1106
1440
|
const toolName = request.operation === "call" ? request.tool : request.name;
|
|
1107
1441
|
const location = locate(definition.tools, toolName);
|
|
@@ -1161,8 +1495,13 @@ function dispatch(app, request, context, signal) {
|
|
|
1161
1495
|
Match_exports.exhaustive
|
|
1162
1496
|
);
|
|
1163
1497
|
}
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1498
|
+
const replay = context.replay === void 0 ? void 0 : yield* safe2(
|
|
1499
|
+
() => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
|
|
1500
|
+
new HostInputInvalid()
|
|
1501
|
+
);
|
|
1502
|
+
if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
|
|
1503
|
+
const session = yield* sqlSession(replay);
|
|
1504
|
+
const execute = () => Effect_exports.gen(function* () {
|
|
1166
1505
|
const output = yield* Effect_exports.gen(function* () {
|
|
1167
1506
|
running = yield* captureTelemetry;
|
|
1168
1507
|
const fetch = yield* appInvocationFetch(fetching.signal);
|
|
@@ -1171,14 +1510,7 @@ function dispatch(app, request, context, signal) {
|
|
|
1171
1510
|
...bound,
|
|
1172
1511
|
fetch,
|
|
1173
1512
|
workflows: kind === "mutate" ? workflowControls : workflowReads,
|
|
1174
|
-
|
|
1175
|
-
db: authorDatabase(
|
|
1176
|
-
native.database.tables,
|
|
1177
|
-
db,
|
|
1178
|
-
invocationSignal,
|
|
1179
|
-
kind === "mutate"
|
|
1180
|
-
)
|
|
1181
|
-
}
|
|
1513
|
+
sql: kind === "mutate" ? session.writer : session.reader
|
|
1182
1514
|
},
|
|
1183
1515
|
input
|
|
1184
1516
|
);
|
|
@@ -1218,26 +1550,7 @@ function dispatch(app, request, context, signal) {
|
|
|
1218
1550
|
new HostOutputInvalid()
|
|
1219
1551
|
);
|
|
1220
1552
|
});
|
|
1221
|
-
|
|
1222
|
-
() => Schema_exports.decodeUnknownEffect(WorkflowReplay)(context.replay),
|
|
1223
|
-
new HostInputInvalid()
|
|
1224
|
-
);
|
|
1225
|
-
if (replay !== void 0 && kind !== "mutate") return yield* new HostInputInvalid();
|
|
1226
|
-
if (native.database === void 0) return yield* withinDeadline(execute());
|
|
1227
|
-
const storage = context.storage ?? unavailableStorage;
|
|
1228
|
-
return yield* storage[kind === "query" ? "read" : "mutate"](
|
|
1229
|
-
native.database.schema,
|
|
1230
|
-
(db) => withinDeadline(
|
|
1231
|
-
replay === void 0 ? execute(db) : db.once(replay.key, replay.fingerprint, () => execute(db))
|
|
1232
|
-
)
|
|
1233
|
-
).pipe(
|
|
1234
|
-
Effect_exports.catchTags({
|
|
1235
|
-
AppDatabaseError: storageFailure,
|
|
1236
|
-
DatabaseLimitExceeded: (error) => Effect_exports.fail(error),
|
|
1237
|
-
AppStorageUnavailable: storageFailure,
|
|
1238
|
-
AppStorageError: storageFailure
|
|
1239
|
-
})
|
|
1240
|
-
);
|
|
1553
|
+
return yield* withinDeadline(execute());
|
|
1241
1554
|
})
|
|
1242
1555
|
);
|
|
1243
1556
|
}
|
|
@@ -160,7 +160,7 @@ import {
|
|
|
160
160
|
pipeThroughChannel,
|
|
161
161
|
provide,
|
|
162
162
|
provide2,
|
|
163
|
-
|
|
163
|
+
provideContext,
|
|
164
164
|
provideMerge,
|
|
165
165
|
redact,
|
|
166
166
|
remove,
|
|
@@ -211,7 +211,7 @@ import {
|
|
|
211
211
|
withFiber,
|
|
212
212
|
withParentSpan,
|
|
213
213
|
zero2 as zero
|
|
214
|
-
} from "./chunk-
|
|
214
|
+
} from "./chunk-MXDKXAY4.js";
|
|
215
215
|
import {
|
|
216
216
|
__export
|
|
217
217
|
} from "./chunk-CZ7CSFO4.js";
|