okengine 0.7.0 → 0.9.0
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/package.json +3 -2
- package/site/content/docs/deployment/docker-swarm.mdx +228 -0
- package/site/content/docs/deployment/docker.mdx +212 -0
- package/site/content/docs/deployment/index.mdx +83 -0
- package/site/content/docs/deployment/kubernetes.mdx +176 -0
- package/site/content/docs/deployment/meta.json +5 -0
- package/site/content/docs/deployment/reverse-proxy.mdx +216 -0
- package/site/content/docs/elements/channel.mdx +25 -12
- package/site/content/docs/elements/clock.mdx +17 -15
- package/site/content/docs/elements/flow.mdx +6 -2
- package/site/content/docs/elements/signal.mdx +10 -8
- package/site/content/docs/elements/store.mdx +165 -0
- package/site/content/docs/get-started/index.mdx +5 -0
- package/site/content/docs/get-started/installation.mdx +18 -16
- package/site/content/docs/index.mdx +5 -0
- package/site/content/docs/meta.json +10 -1
- package/site/content/docs/plugins/index.mdx +1 -2
- package/site/content/docs/plugins/magic-link.mdx +44 -2
- package/site/content/docs/plugins/meta.json +1 -2
- package/site/content/docs/plugins/otp.mdx +202 -0
- package/site/content/docs/plugins/two-factor.mdx +2 -1
- package/site/content/docs/reference/cli.md +5 -2
- package/site/content/docs/reference/configuration.mdx +21 -3
- package/site/content/docs/reference/environment-variables.mdx +21 -8
- package/site/content/docs/reference/plugins.mdx +1 -1
- package/src/auth/auth.test.ts +36 -0
- package/src/auth/bindings.ts +3 -12
- package/src/auth/identity.ts +33 -0
- package/src/auth/index.ts +5 -0
- package/src/auth/otp-capability.ts +119 -0
- package/src/auth/otp-seal.test.ts +61 -0
- package/src/auth/otp-seal.ts +84 -0
- package/src/auth/schema.ts +3 -0
- package/src/auth/sessions.ts +26 -27
- package/src/auth/tables.ts +4 -0
- package/src/auth/verification.ts +61 -1
- package/src/cli/db-seed.ts +359 -0
- package/src/cli/db.test.ts +341 -3
- package/src/cli/db.ts +75 -8
- package/src/cli/dev-app-runner.ts +4 -0
- package/src/cli/docker.ts +4 -1
- package/src/cli/load-config.images.test.ts +26 -0
- package/src/cli/load-config.ts +10 -2
- package/src/cli/registry.ts +38 -2
- package/src/compiler/effects-infer.ts +1 -0
- package/src/config/index.ts +4 -0
- package/src/console/server/operator-db.ts +34 -9
- package/src/docker/compose.ts +162 -6
- package/src/docker/derive.ts +60 -3
- package/src/docker/docker.test.ts +374 -1
- package/src/docker/helpers.ts +2 -0
- package/src/docker/index.ts +11 -0
- package/src/docker/recipes/caddy.ts +51 -0
- package/src/docker/recipes/dragonfly.ts +31 -0
- package/src/docker/recipes/index.ts +25 -2
- package/src/docker/recipes/pgdog.ts +84 -0
- package/src/docker/recipes/redis.ts +6 -3
- package/src/docker/recipes/traefik.ts +83 -0
- package/src/docker/recipes/valkey.ts +30 -0
- package/src/docker/stack-id.ts +5 -0
- package/src/docker/types.ts +18 -0
- package/src/drivers/channel-sently.test.ts +8 -0
- package/src/drivers/channel-taqnyat-mail.ts +34 -0
- package/src/drivers/channel-taqnyat-whatsapp.ts +94 -0
- package/src/drivers/channel-types.ts +72 -0
- package/src/drivers/clock-postgres.test.ts +258 -0
- package/src/drivers/clock-postgres.ts +410 -0
- package/src/drivers/index.ts +18 -0
- package/src/drivers/journal-postgres.test.ts +175 -0
- package/src/drivers/journal-postgres.ts +492 -0
- package/src/elements/channel/otp-delivery.test.ts +76 -0
- package/src/elements/channel/otp-delivery.ts +291 -0
- package/src/elements/channel/runtime.ts +203 -114
- package/src/elements/channel.test.ts +71 -0
- package/src/elements/channel.ts +12 -2
- package/src/elements/clock/chaos-child.ts +280 -41
- package/src/elements/clock/durable.ts +7 -0
- package/src/elements/clock/reconcile.ts +2 -2
- package/src/elements/clock/runtime.ts +5 -3
- package/src/elements/clock.ts +1 -1
- package/src/elements/store/seed.test.ts +27 -0
- package/src/elements/store/seed.ts +68 -0
- package/src/elements/store/sql-session.test.ts +39 -0
- package/src/elements/store/sql-session.ts +55 -0
- package/src/elements/store/upsert-app.test.ts +103 -0
- package/src/elements/store.ts +5 -0
- package/src/index.ts +18 -0
- package/src/kernel/app.ts +221 -14
- package/src/kernel/boot-bind/channel.test.ts +16 -0
- package/src/kernel/boot-bind/channel.ts +64 -0
- package/src/kernel/boot-bind/clock.ts +17 -6
- package/src/kernel/boot-bind/gate.ts +14 -19
- package/src/kernel/boot-bind/honor-config.test.ts +123 -4
- package/src/kernel/boot-bind/journal.ts +89 -0
- package/src/kernel/boot-bind/signal.ts +20 -0
- package/src/kernel/boot-bind/store.test.ts +82 -0
- package/src/kernel/boot-bind/store.ts +22 -0
- package/src/kernel/boot.test.ts +6 -4
- package/src/kernel/boot.ts +53 -13
- package/src/kernel/concurrency.ts +1 -1
- package/src/kernel/fx.test.ts +9 -0
- package/src/kernel/fx.ts +175 -5
- package/src/kernel/graceful-shutdown.test.ts +76 -0
- package/src/kernel/graceful-shutdown.ts +106 -0
- package/src/kernel/horizontal-child.ts +257 -0
- package/src/kernel/horizontal.integration.test.ts +229 -0
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal-boot.test.ts +397 -0
- package/src/kernel/journal-suspend.ts +35 -0
- package/src/kernel/journal.test.ts +142 -0
- package/src/kernel/journal.ts +202 -27
- package/src/kernel/ready.test.ts +76 -0
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +5 -5
- package/src/plugins/auth-methods.security.test.ts +20 -27
- package/src/plugins/auth-methods.test.ts +7 -6
- package/src/plugins/index.ts +12 -8
- package/src/plugins/magic-link.ts +1 -23
- package/src/plugins/otp.test.ts +236 -0
- package/src/plugins/otp.ts +570 -0
- package/src/plugins/taqnyat.live.test.ts +172 -0
- package/src/release/official-plugins.ts +1 -2
- package/site/content/docs/plugins/email-otp.mdx +0 -117
- package/site/content/docs/plugins/phone-number.mdx +0 -111
- package/src/plugins/email-otp.ts +0 -214
- package/src/plugins/phone-number.ts +0 -149
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phone-number OTP Gate auth method plugin (E.164).
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { issueSessionWithScopes } from "../auth/sessions.ts";
|
|
6
|
-
import {
|
|
7
|
-
createVerificationStore,
|
|
8
|
-
findActiveVerification,
|
|
9
|
-
generateOtp,
|
|
10
|
-
hashChallenge,
|
|
11
|
-
putVerification,
|
|
12
|
-
type VerificationStore,
|
|
13
|
-
} from "../auth/verification.ts";
|
|
14
|
-
import { plugin, type PluginDef } from "../kernel/plugin.ts";
|
|
15
|
-
import {
|
|
16
|
-
AuthFailed,
|
|
17
|
-
AuthRateLimited,
|
|
18
|
-
SessionTokensOut,
|
|
19
|
-
bindPublicAuth,
|
|
20
|
-
createMethodRuntime,
|
|
21
|
-
fail,
|
|
22
|
-
flow,
|
|
23
|
-
z,
|
|
24
|
-
type AuthMethodOptions,
|
|
25
|
-
} from "./auth/shared.ts";
|
|
26
|
-
|
|
27
|
-
const E164 = /^\+[1-9]\d{7,14}$/;
|
|
28
|
-
const DEFAULT_TTL_MS = 10 * 60 * 1000;
|
|
29
|
-
const MAX_ATTEMPTS = 5;
|
|
30
|
-
|
|
31
|
-
/** Phone principal store (phone → userId). */
|
|
32
|
-
export interface PhoneStore {
|
|
33
|
-
readonly byPhone: Map<string, string>;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Create an empty phone → user map.
|
|
38
|
-
*/
|
|
39
|
-
export function createPhoneStore(): PhoneStore {
|
|
40
|
-
return { byPhone: new Map() };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** Options for {@link phoneNumber}. */
|
|
44
|
-
export interface PhoneNumberOptions extends AuthMethodOptions {
|
|
45
|
-
readonly ttlMs?: number;
|
|
46
|
-
readonly phones?: PhoneStore;
|
|
47
|
-
readonly verifications?: VerificationStore;
|
|
48
|
-
/** Return raw OTP in the request response (test / local). */
|
|
49
|
-
readonly exposeDevOtp?: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Phone OTP request + verify (E.164, 6-digit, hashed, 5 attempts).
|
|
54
|
-
*
|
|
55
|
-
* @param opts - TTL / stores / dev OTP
|
|
56
|
-
*/
|
|
57
|
-
export function phoneNumber(opts: PhoneNumberOptions = {}): PluginDef {
|
|
58
|
-
const runtime = createMethodRuntime(opts);
|
|
59
|
-
const phones = opts.phones ?? createPhoneStore();
|
|
60
|
-
const verifications = opts.verifications ?? createVerificationStore();
|
|
61
|
-
const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
62
|
-
|
|
63
|
-
const request = flow({
|
|
64
|
-
name: "auth.requestPhoneOtp",
|
|
65
|
-
unit: "auth",
|
|
66
|
-
plane: "user",
|
|
67
|
-
in: z.object({ phone: z.string().min(8) }),
|
|
68
|
-
out: z.object({
|
|
69
|
-
ok: z.literal(true),
|
|
70
|
-
devOtp: z.string().optional(),
|
|
71
|
-
}),
|
|
72
|
-
errors: { AuthFailed, AuthRateLimited },
|
|
73
|
-
do: async (input) => {
|
|
74
|
-
const phone = input.phone.trim();
|
|
75
|
-
if (!E164.test(phone)) return fail("AuthFailed", { reason: "invalid_phone" });
|
|
76
|
-
const otp = generateOtp(6);
|
|
77
|
-
const now = runtime.now();
|
|
78
|
-
for (const row of verifications.rows.values()) {
|
|
79
|
-
if (row.identifier === `phone-otp:${phone}` && row.consumedAt === null) {
|
|
80
|
-
row.consumedAt = now;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
putVerification(verifications, {
|
|
84
|
-
id: crypto.randomUUID(),
|
|
85
|
-
identifier: `phone-otp:${phone}`,
|
|
86
|
-
value: await hashChallenge(otp),
|
|
87
|
-
expiresAt: now + ttlMs,
|
|
88
|
-
createdAt: now,
|
|
89
|
-
consumedAt: null,
|
|
90
|
-
attempts: 0,
|
|
91
|
-
});
|
|
92
|
-
return {
|
|
93
|
-
ok: true as const,
|
|
94
|
-
...(opts.exposeDevOtp ? { devOtp: otp } : {}),
|
|
95
|
-
};
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const verify = flow({
|
|
100
|
-
name: "auth.verifyPhoneOtp",
|
|
101
|
-
unit: "auth",
|
|
102
|
-
plane: "user",
|
|
103
|
-
in: z.object({
|
|
104
|
-
phone: z.string().min(8),
|
|
105
|
-
otp: z.string().min(4).max(8),
|
|
106
|
-
}),
|
|
107
|
-
out: SessionTokensOut,
|
|
108
|
-
errors: { AuthFailed, AuthRateLimited },
|
|
109
|
-
do: async (input) => {
|
|
110
|
-
const phone = input.phone.trim();
|
|
111
|
-
if (!E164.test(phone)) return fail("AuthFailed", { reason: "invalid_phone" });
|
|
112
|
-
const now = runtime.now();
|
|
113
|
-
const row = findActiveVerification(verifications, `phone-otp:${phone}`, now);
|
|
114
|
-
if (!row) return fail("AuthFailed", { reason: "invalid_credentials" });
|
|
115
|
-
if (row.attempts >= MAX_ATTEMPTS) {
|
|
116
|
-
row.consumedAt = now;
|
|
117
|
-
return fail("AuthFailed", { reason: "invalid_credentials" });
|
|
118
|
-
}
|
|
119
|
-
const hash = await hashChallenge(input.otp.trim());
|
|
120
|
-
if (hash !== row.value) {
|
|
121
|
-
row.attempts += 1;
|
|
122
|
-
if (row.attempts >= MAX_ATTEMPTS) row.consumedAt = now;
|
|
123
|
-
return fail("AuthFailed", { reason: "invalid_credentials" });
|
|
124
|
-
}
|
|
125
|
-
row.consumedAt = now;
|
|
126
|
-
let userId = phones.byPhone.get(phone);
|
|
127
|
-
if (!userId) {
|
|
128
|
-
userId = crypto.randomUUID();
|
|
129
|
-
phones.byPhone.set(phone, userId);
|
|
130
|
-
}
|
|
131
|
-
const issued = await issueSessionWithScopes(runtime.sessions, runtime.crypto, {
|
|
132
|
-
id: userId,
|
|
133
|
-
plane: "user",
|
|
134
|
-
scopes: [],
|
|
135
|
-
});
|
|
136
|
-
return {
|
|
137
|
-
accessToken: issued.accessToken,
|
|
138
|
-
refreshToken: issued.refreshToken,
|
|
139
|
-
accessExpiresAt: issued.accessExpiresAt,
|
|
140
|
-
userId,
|
|
141
|
-
};
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
return plugin("phoneNumber", { version: "0.0.1", config: { method: "phone-number" } })
|
|
146
|
-
.needs("auth")
|
|
147
|
-
.binding(bindPublicAuth("/phone/request", request, "otp"))
|
|
148
|
-
.binding(bindPublicAuth("/phone/verify", verify, "otp"));
|
|
149
|
-
}
|