feat(todo): the server on halkyon_base
Todo's server includes halkyon_base (ADR 0014), configured for Todo: its basics say it serves `todo`, sign-in mails name Halkyon Todo, the source is this repository, minimumAppBuild 1. Authentication through the module (anonymous, GitHub, email codes, server-side sessions) in place of the scaffold's email-and-password provider; the module's pruning scheduled once however often the server starts. The scaffold's greeting, its Flutter web hosting, cloud storage and Docker files go; session logs are never persisted. Todo was never deployed, so its migrations start again with one initial migration. The root's lints apply, with the four constructor rules off as on Learn's server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
38770569ea
commit
28dd3ea65a
42 changed files with 1047 additions and 1741 deletions
|
|
@ -1,58 +0,0 @@
|
|||
# Build from the project root with:
|
||||
# docker build -f halkyon_todo_server/Dockerfile .
|
||||
|
||||
# Build stage
|
||||
FROM dart:3.12.2 AS build
|
||||
|
||||
# Create a minimal workspace that preserves locked server dependency versions.
|
||||
WORKDIR /app
|
||||
COPY pubspec.lock .
|
||||
COPY halkyon_todo_server halkyon_todo_server
|
||||
RUN printf '%s\n' \
|
||||
'name: _' \
|
||||
'environment:' \
|
||||
' sdk: ^3.12.2' \
|
||||
'workspace:' \
|
||||
' - halkyon_todo_server' \
|
||||
> pubspec.yaml
|
||||
RUN dart pub get
|
||||
|
||||
# Compile the server executable.
|
||||
WORKDIR /app/halkyon_todo_server
|
||||
RUN dart build cli --target bin/main.dart --output build
|
||||
RUN mv build/bundle/bin/main build/bundle/bin/server
|
||||
|
||||
# Add a fallback for the copy of possibly missing directories.
|
||||
RUN mkdir -p config web migrations
|
||||
|
||||
# Final stage
|
||||
FROM alpine:latest
|
||||
WORKDIR /app
|
||||
|
||||
# Environment variables
|
||||
ENV runmode=production
|
||||
ENV serverid=default
|
||||
ENV logging=normal
|
||||
ENV role=monolith
|
||||
|
||||
# Copy runtime dependencies
|
||||
COPY --from=build /runtime/ /
|
||||
|
||||
# Copy compiled server executable and native libraries
|
||||
COPY --from=build /app/halkyon_todo_server/build/bundle/ ./
|
||||
|
||||
# Copy configuration files and resources
|
||||
COPY --from=build /app/halkyon_todo_server/config/ config/
|
||||
COPY --from=build /app/halkyon_todo_server/web/ web/
|
||||
COPY --from=build /app/halkyon_todo_server/migrations/ migrations/
|
||||
|
||||
# This file is required to enable the endpoint log filter in Insights.
|
||||
COPY --from=build /app/halkyon_todo_server/lib/src/generated/protocol.yaml lib/src/generated/protocol.yaml
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
EXPOSE 8082
|
||||
|
||||
# Define the entrypoint command
|
||||
ENTRYPOINT ./bin/server --mode=$runmode --server-id=$serverid --logging=$logging --role=$role
|
||||
|
|
@ -1,34 +1,21 @@
|
|||
# This file configures the static analysis results for your project (errors,
|
||||
# warnings, and lints).
|
||||
#
|
||||
# This enables the 'recommended' set of lints from `package:lints`.
|
||||
# This set helps identify many issues that may lead to problems when running
|
||||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||
# style and format.
|
||||
#
|
||||
# If you want a smaller set of lints you can change this to specify
|
||||
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||
# (the recommended set includes the core lints).
|
||||
# The core lints are also what is used by pub.dev for scoring packages.
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
# Uncomment the following section to specify additional rules.
|
||||
|
||||
linter:
|
||||
rules:
|
||||
unawaited_futures: true
|
||||
avoid_print: true
|
||||
# The workspace's lint rules (see ../../../analysis_options.yaml), minus generated code.
|
||||
include: ../../../analysis_options.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- lib/src/generated/**
|
||||
- test/integration/test_tools/serverpod_test_tools.dart
|
||||
# For more information about the core and recommended set of lints, see
|
||||
# https://dart.dev/go/core-lints
|
||||
|
||||
# For additional information about configuring this file, see
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
# Serverpod's code generator reads this package with an analyzer that doesn't know
|
||||
# Dart v3.13's primary constructors yet, and fails on them in endpoint files, so the
|
||||
# server keeps the classic constructor and class-body syntax, as Learn's does; switch
|
||||
# these back on once Serverpod parses it.
|
||||
linter:
|
||||
rules:
|
||||
empty_container_bodies: false
|
||||
unnecessary_type_name_in_constructor: false
|
||||
use_declaring_parameters: false
|
||||
use_primary_constructors: false
|
||||
|
||||
formatter:
|
||||
trailing_commas: preserve
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
import 'package:halkyon_todo_server/server.dart';
|
||||
|
||||
/// This is the starting point for your Serverpod server. Typically, there is
|
||||
/// no need to modify this file.
|
||||
void main(List<String> args) {
|
||||
run(args);
|
||||
}
|
||||
/// Starts Halkyon Todo's server (lib/server.dart).
|
||||
Future<void> main(List<String> args) => run(args);
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ database:
|
|||
|
||||
maxRequestSize: 524288 # The maximum size of requests allowed in bytes
|
||||
|
||||
# Session logs stay out of the database, for privacy, as Learn's (never re-enable).
|
||||
sessionLogs:
|
||||
persistentEnabled: true
|
||||
persistentEnabled: false
|
||||
consoleEnabled: true
|
||||
consoleLogFormat: text # Defaults to "json", options are "text" or "json"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,3 +2,8 @@ type: server
|
|||
|
||||
client_package_path: ../halkyon_todo_client
|
||||
server_test_tools_path: test/integration/test_tools
|
||||
|
||||
modules:
|
||||
# What every Halkyon server has (ADR 0014): `client.modules.base` in the app.
|
||||
halkyon_base:
|
||||
nickname: base
|
||||
|
|
|
|||
|
|
@ -41,9 +41,10 @@ database:
|
|||
|
||||
maxRequestSize: 524288 # The maximum size of requests allowed in bytes
|
||||
|
||||
# Session logs stay out of the database, for privacy, as Learn's (never re-enable).
|
||||
sessionLogs:
|
||||
consoleEnabled: false
|
||||
# persistentEnabled: true
|
||||
persistentEnabled: false
|
||||
# consoleLogFormat: json # Defaults to "json", options are "text" or "json"
|
||||
|
||||
#futureCall:
|
||||
|
|
|
|||
|
|
@ -45,8 +45,9 @@ database:
|
|||
|
||||
maxRequestSize: 524288 # The maximum size of requests allowed in bytes
|
||||
|
||||
# Session logs stay out of the database, for privacy, as Learn's (never re-enable).
|
||||
sessionLogs:
|
||||
# persistentEnabled: true
|
||||
persistentEnabled: false
|
||||
# consoleEnabled: true
|
||||
# consoleLogFormat: json # Defaults to "json", options are "text" or "json"
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@ database:
|
|||
#maxConnectionCount: 10 # Defaults to 10, a negative or null value removes the limit
|
||||
|
||||
|
||||
# Session logs stay out of the database, for privacy, as Learn's (never re-enable).
|
||||
sessionLogs:
|
||||
persistentEnabled: true
|
||||
persistentEnabled: false
|
||||
consoleEnabled: true
|
||||
# consoleLogFormat: json # Defaults to "json", options are "text" or "json"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
services:
|
||||
# Development services
|
||||
postgres:
|
||||
image: ghcr.io/serverpod/postgres:16
|
||||
ports:
|
||||
- "8090:5432"
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: halkyon_todo
|
||||
POSTGRES_PASSWORD: "aKpX2DK-n57tgkIr0XqP0hZSxmcwLQdj"
|
||||
volumes:
|
||||
- halkyon_todo_data:/var/lib/postgresql/data
|
||||
|
||||
|
||||
# Test services
|
||||
postgres_test:
|
||||
image: ghcr.io/serverpod/postgres:16
|
||||
ports:
|
||||
- "9090:5432"
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: halkyon_todo_test
|
||||
POSTGRES_PASSWORD: "ls3BpmIUIv2u_Ud0eZ2h3bunjU5nDzkh"
|
||||
volumes:
|
||||
- halkyon_todo_test_data:/var/lib/postgresql/data
|
||||
|
||||
|
||||
volumes:
|
||||
halkyon_todo_data:
|
||||
halkyon_todo_test_data:
|
||||
|
|
@ -1,109 +1,25 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:halkyon_base_server/base.dart';
|
||||
import 'package:halkyon_todo_server/src/generated/serverpod.dart';
|
||||
import 'package:halkyon_todo_server/src/pruning.dart';
|
||||
import 'package:halkyon_todo_server/src/todo_base.dart';
|
||||
import 'package:serverpod_auth_idp_server/core.dart';
|
||||
import 'package:serverpod_auth_idp_server/providers/email.dart';
|
||||
import 'package:serverpod_cloud_storage/serverpod_cloud_storage.dart';
|
||||
|
||||
import 'src/cache_busting.dart';
|
||||
import 'src/generated/serverpod.dart';
|
||||
import 'src/web/routes/app_config_route.dart';
|
||||
|
||||
/// The starting point of the Serverpod server.
|
||||
void run(List<String> args) async {
|
||||
// Initialize Serverpod. The generated Serverpod class is already connected
|
||||
// with your project's generated code.
|
||||
/// The starting point of Halkyon Todo's server.
|
||||
Future<void> run(List<String> args) async {
|
||||
// The generated Serverpod is already connected with the generated code.
|
||||
final pod = Serverpod(args);
|
||||
|
||||
// Initialize authentication services for the server.
|
||||
// Token managers will be used to validate and issue authentication keys,
|
||||
// and the identity providers will be the authentication options available for users.
|
||||
// What every Halkyon server has (ADR 0014): sign-in, the account and its
|
||||
// deletion, the pruning, the instance's basics, set up for Todo.
|
||||
HalkyonBase.configure(pod, todoBase());
|
||||
// Token managers validate and issue authentication keys; identity
|
||||
// providers are the ways people can sign in (halkyon_base's
|
||||
// auth_config.dart).
|
||||
pod.initializeAuthServices(
|
||||
tokenManagerBuilders: [
|
||||
// Server-side sessions: every request looks its session up in the
|
||||
// database, so signing out or deleting an account takes effect at once.
|
||||
// A session unused for 90 days expires; one in use never does.
|
||||
ServerSideSessionsConfigFromPasswords(
|
||||
defaultSessionInactivityTimeout: const Duration(days: 90),
|
||||
),
|
||||
],
|
||||
identityProviderBuilders: [
|
||||
// Configure the email identity provider for email/password authentication.
|
||||
// The default setup works with Serverpod Cloud without configuration. In
|
||||
// development the verification codes are logged to the console, and in
|
||||
// staging and production they are sent through the Serverpod Cloud email
|
||||
// service. If you want to use a custom provider for sending emails, use
|
||||
// `EmailIdpConfigFromPasswords`.
|
||||
ServerpodCloudEmailIdpConfig(
|
||||
appDisplayName: 'halkyon_todo',
|
||||
),
|
||||
],
|
||||
tokenManagerBuilders: tokenManagerBuilders,
|
||||
identityProviderBuilders: identityProviderBuilders(pod),
|
||||
);
|
||||
|
||||
// Serve all files in the web/static relative directory under /web.
|
||||
// These are used by the default web page.
|
||||
pod.webServer.addRoute(
|
||||
StaticRoute.withCacheBusting(cacheBustingConfig),
|
||||
cacheBustingConfig.mountPrefix,
|
||||
);
|
||||
|
||||
// Setup the app config route.
|
||||
// We build this configuration based on the servers api url and serve it to
|
||||
// the flutter app.
|
||||
pod.webServer.addRoute(
|
||||
AppConfigRoute(apiConfig: pod.config.apiServer),
|
||||
'/assets/assets/config.json',
|
||||
);
|
||||
|
||||
// Checks if the flutter web app has been built and serves it if it has.
|
||||
final appDir = Directory(Uri(path: 'web/app').toFilePath());
|
||||
if (appDir.existsSync()) {
|
||||
// Serve the flutter web app under /.
|
||||
pod.webServer.addRoute(
|
||||
FlutterRoute(
|
||||
appDir,
|
||||
// If building the Flutter app with WASM, set the below parameter to
|
||||
// true and add the --wasm flag to the flutter build command.
|
||||
enableWasmHeaders: false,
|
||||
),
|
||||
'/',
|
||||
);
|
||||
} else {
|
||||
// If the flutter web app has not been built, serve the build app page.
|
||||
final defaultRoute = StaticRoute.file(
|
||||
File(
|
||||
Uri(path: 'web/pages/build_flutter_app.html').toFilePath(),
|
||||
),
|
||||
);
|
||||
|
||||
pod.webServer.addMiddleware(
|
||||
FallbackMiddleware(
|
||||
fallback: defaultRoute,
|
||||
on: (response) => response.statusCode == 404,
|
||||
).call,
|
||||
'/',
|
||||
);
|
||||
|
||||
pod.webServer.addRoute(
|
||||
defaultRoute,
|
||||
'/**',
|
||||
);
|
||||
}
|
||||
|
||||
// Configure cloud storage.
|
||||
// This setup works with Serverpod Cloud without extra configuration.
|
||||
// If you want to use a custom provider for cloud storage, replace these
|
||||
// with your preferred provider.
|
||||
pod.addCloudStorage(
|
||||
await ServerpodCloudProvider.private(
|
||||
fallback: () => DatabaseCloudStorage('private'),
|
||||
),
|
||||
);
|
||||
pod.addCloudStorage(
|
||||
await ServerpodCloudProvider.public(
|
||||
fallback: () => DatabaseCloudStorage('public'),
|
||||
),
|
||||
);
|
||||
|
||||
// Start the server.
|
||||
await pod.start();
|
||||
|
||||
await schedulePruning(pod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
import 'package:serverpod_auth_idp_server/providers/email.dart';
|
||||
|
||||
/// By extending [EmailIdpBaseEndpoint], the email identity provider endpoints
|
||||
/// are made available on the server and enable the corresponding sign-in widget
|
||||
/// on the client.
|
||||
class EmailIdpEndpoint extends EmailIdpBaseEndpoint {}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:serverpod/serverpod.dart';
|
||||
|
||||
/// Cache busting configuration.
|
||||
/// Used in WidgetRoutes to cache-bust asset paths.
|
||||
final cacheBustingConfig = CacheBustingConfig(
|
||||
mountPrefix: '/web',
|
||||
fileSystemRoot: Directory(Uri(path: 'web/static').toFilePath()),
|
||||
);
|
||||
|
|
@ -10,239 +10,29 @@
|
|||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:halkyon_base_server/halkyon_base_server.dart' as _ik8molhd;
|
||||
import 'package:halkyon_todo_server/src/generated/future_calls.dart'
|
||||
as _i772x17y;
|
||||
import 'package:serverpod/serverpod.dart' as _is;
|
||||
import 'package:serverpod_auth_core_server/serverpod_auth_core_server.dart'
|
||||
as _iacs;
|
||||
import 'package:serverpod_auth_idp_server/serverpod_auth_idp_server.dart'
|
||||
as _iais;
|
||||
import '../auth/email_idp_endpoint.dart' as _iuc1hd5t;
|
||||
import '../greetings/greeting_endpoint.dart' as _il624ik7;
|
||||
export 'future_calls.dart' show ServerpodFutureCallsGetter;
|
||||
|
||||
class Endpoints extends _is.EndpointDispatch {
|
||||
@override
|
||||
void initializeEndpoints(_is.Server server) {
|
||||
var endpoints = <String, _is.Endpoint>{
|
||||
'emailIdp': _iuc1hd5t.EmailIdpEndpoint()
|
||||
..initialize(
|
||||
server,
|
||||
'emailIdp',
|
||||
null,
|
||||
),
|
||||
'greeting': _il624ik7.GreetingEndpoint()
|
||||
..initialize(
|
||||
server,
|
||||
'greeting',
|
||||
null,
|
||||
),
|
||||
};
|
||||
connectors['emailIdp'] = _is.EndpointConnector(
|
||||
name: 'emailIdp',
|
||||
endpoint: endpoints['emailIdp']!,
|
||||
methodConnectors: {
|
||||
'login': _is.MethodConnector(
|
||||
name: 'login',
|
||||
params: {
|
||||
'email': _is.ParameterDescription(
|
||||
name: 'email',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
'password': _is.ParameterDescription(
|
||||
name: 'password',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async =>
|
||||
(endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint).login(
|
||||
session,
|
||||
email: params['email'],
|
||||
password: params['password'],
|
||||
),
|
||||
),
|
||||
'startRegistration': _is.MethodConnector(
|
||||
name: 'startRegistration',
|
||||
params: {
|
||||
'email': _is.ParameterDescription(
|
||||
name: 'email',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.startRegistration(
|
||||
session,
|
||||
email: params['email'],
|
||||
),
|
||||
),
|
||||
'verifyRegistrationCode': _is.MethodConnector(
|
||||
name: 'verifyRegistrationCode',
|
||||
params: {
|
||||
'accountRequestId': _is.ParameterDescription(
|
||||
name: 'accountRequestId',
|
||||
type: _is.getType<_is.UuidValue>(),
|
||||
nullable: false,
|
||||
),
|
||||
'verificationCode': _is.ParameterDescription(
|
||||
name: 'verificationCode',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.verifyRegistrationCode(
|
||||
session,
|
||||
accountRequestId: params['accountRequestId'],
|
||||
verificationCode: params['verificationCode'],
|
||||
),
|
||||
),
|
||||
'finishRegistration': _is.MethodConnector(
|
||||
name: 'finishRegistration',
|
||||
params: {
|
||||
'registrationToken': _is.ParameterDescription(
|
||||
name: 'registrationToken',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
'password': _is.ParameterDescription(
|
||||
name: 'password',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.finishRegistration(
|
||||
session,
|
||||
registrationToken: params['registrationToken'],
|
||||
password: params['password'],
|
||||
),
|
||||
),
|
||||
'startPasswordReset': _is.MethodConnector(
|
||||
name: 'startPasswordReset',
|
||||
params: {
|
||||
'email': _is.ParameterDescription(
|
||||
name: 'email',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.startPasswordReset(
|
||||
session,
|
||||
email: params['email'],
|
||||
),
|
||||
),
|
||||
'verifyPasswordResetCode': _is.MethodConnector(
|
||||
name: 'verifyPasswordResetCode',
|
||||
params: {
|
||||
'passwordResetRequestId': _is.ParameterDescription(
|
||||
name: 'passwordResetRequestId',
|
||||
type: _is.getType<_is.UuidValue>(),
|
||||
nullable: false,
|
||||
),
|
||||
'verificationCode': _is.ParameterDescription(
|
||||
name: 'verificationCode',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.verifyPasswordResetCode(
|
||||
session,
|
||||
passwordResetRequestId: params['passwordResetRequestId'],
|
||||
verificationCode: params['verificationCode'],
|
||||
),
|
||||
),
|
||||
'finishPasswordReset': _is.MethodConnector(
|
||||
name: 'finishPasswordReset',
|
||||
params: {
|
||||
'finishPasswordResetToken': _is.ParameterDescription(
|
||||
name: 'finishPasswordResetToken',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
'newPassword': _is.ParameterDescription(
|
||||
name: 'newPassword',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.finishPasswordReset(
|
||||
session,
|
||||
finishPasswordResetToken:
|
||||
params['finishPasswordResetToken'],
|
||||
newPassword: params['newPassword'],
|
||||
),
|
||||
),
|
||||
'hasAccount': _is.MethodConnector(
|
||||
name: 'hasAccount',
|
||||
params: {},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async => (endpoints['emailIdp'] as _iuc1hd5t.EmailIdpEndpoint)
|
||||
.hasAccount(session),
|
||||
),
|
||||
},
|
||||
);
|
||||
connectors['greeting'] = _is.EndpointConnector(
|
||||
name: 'greeting',
|
||||
endpoint: endpoints['greeting']!,
|
||||
methodConnectors: {
|
||||
'hello': _is.MethodConnector(
|
||||
name: 'hello',
|
||||
params: {
|
||||
'name': _is.ParameterDescription(
|
||||
name: 'name',
|
||||
type: _is.getType<String>(),
|
||||
nullable: false,
|
||||
),
|
||||
},
|
||||
call:
|
||||
(
|
||||
_is.Session session,
|
||||
Map<String, dynamic> params,
|
||||
) async =>
|
||||
(endpoints['greeting'] as _il624ik7.GreetingEndpoint).hello(
|
||||
session,
|
||||
params['name'],
|
||||
),
|
||||
),
|
||||
},
|
||||
);
|
||||
modules['halkyon_base'] = _ik8molhd.Endpoints()
|
||||
..initializeEndpoints(server);
|
||||
modules['serverpod_auth_idp'] = _iais.Endpoints()
|
||||
..initializeEndpoints(server);
|
||||
modules['serverpod_auth_core'] = _iacs.Endpoints()
|
||||
..initializeEndpoints(server);
|
||||
}
|
||||
|
||||
@override
|
||||
_is.FutureCallDispatch? get futureCalls {
|
||||
return _i772x17y.FutureCalls();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,232 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
// ignore_for_file: depend_on_referenced_packages
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _ida;
|
||||
import 'package:clock/clock.dart' as _io0w16m8;
|
||||
import 'package:serverpod/serverpod.dart' as _is;
|
||||
import '../pruning_future_call.dart' as _ibrplims;
|
||||
|
||||
/// Invokes a future call.
|
||||
typedef _InvokeFutureCall =
|
||||
Future<void> Function(String name, _is.SerializableModel? object);
|
||||
|
||||
extension ServerpodFutureCallsGetter on _is.Serverpod {
|
||||
/// Generated future calls.
|
||||
FutureCalls get futureCalls => FutureCalls();
|
||||
}
|
||||
|
||||
class FutureCalls extends _is.FutureCallDispatch<_FutureCallRef> {
|
||||
FutureCalls._();
|
||||
|
||||
factory FutureCalls() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static final FutureCalls _instance = FutureCalls._();
|
||||
|
||||
_is.FutureCallManager? _futureCallManager;
|
||||
|
||||
String? _serverId;
|
||||
|
||||
String get _effectiveServerId {
|
||||
if (_serverId == null) {
|
||||
throw StateError('FutureCalls is not initialized.');
|
||||
}
|
||||
return _serverId!;
|
||||
}
|
||||
|
||||
_is.FutureCallManager get _effectiveFutureCallManager {
|
||||
if (_futureCallManager == null) {
|
||||
throw StateError('FutureCalls is not initialized.');
|
||||
}
|
||||
return _futureCallManager!;
|
||||
}
|
||||
|
||||
@override
|
||||
void initialize(
|
||||
_is.FutureCallManager futureCallManager,
|
||||
String serverId,
|
||||
) {
|
||||
var registeredFutureCalls = <String, _is.InvokableFutureCall>{
|
||||
'PruningPruneAnonymousPeopleFutureCall':
|
||||
PruningPruneAnonymousPeopleFutureCall(),
|
||||
'PruningForgetSignUpAttemptsFutureCall':
|
||||
PruningForgetSignUpAttemptsFutureCall(),
|
||||
};
|
||||
_futureCallManager = futureCallManager;
|
||||
_serverId = serverId;
|
||||
for (final entry in registeredFutureCalls.entries) {
|
||||
_futureCallManager?.registerFutureCall(entry.value, entry.key);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
_FutureCallRef callAtTime(
|
||||
DateTime time, {
|
||||
String? identifier,
|
||||
}) {
|
||||
return _FutureCallRef(
|
||||
(name, object) {
|
||||
return _effectiveFutureCallManager.scheduleFutureCall(
|
||||
name,
|
||||
object,
|
||||
time,
|
||||
_effectiveServerId,
|
||||
identifier,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
_FutureCallRef callWithDelay(
|
||||
Duration delay, {
|
||||
String? identifier,
|
||||
}) {
|
||||
return _FutureCallRef(
|
||||
(name, object) {
|
||||
return _effectiveFutureCallManager.scheduleFutureCall(
|
||||
name,
|
||||
object,
|
||||
DateTime.now().toUtc().add(delay),
|
||||
_effectiveServerId,
|
||||
identifier,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
_is.RecurringFutureCallDispatch<_FutureCallRef> callRecurring({
|
||||
String? identifier,
|
||||
}) {
|
||||
return _RecurringFutureCallDispatchImpl(
|
||||
_effectiveFutureCallManager,
|
||||
_effectiveServerId,
|
||||
identifier,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> cancel(String identifier) async {
|
||||
await _effectiveFutureCallManager.cancelFutureCall(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
class _RecurringFutureCallDispatchImpl
|
||||
extends _is.RecurringFutureCallDispatch<_FutureCallRef> {
|
||||
_RecurringFutureCallDispatchImpl(
|
||||
this._futureCallManager,
|
||||
this._serverId,
|
||||
this._identifier,
|
||||
);
|
||||
|
||||
final _is.FutureCallManager _futureCallManager;
|
||||
|
||||
final String _serverId;
|
||||
|
||||
final String? _identifier;
|
||||
|
||||
@override
|
||||
_FutureCallRef cron(String cronExpression) {
|
||||
return _FutureCallRef(
|
||||
(name, object) {
|
||||
return _futureCallManager.scheduleFutureCall(
|
||||
name,
|
||||
object,
|
||||
_is.Cron.parse(cronExpression).nextTime(),
|
||||
_serverId,
|
||||
_identifier,
|
||||
scheduling: _is.CronFutureCallScheduling(cron: cronExpression),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
_FutureCallRef every(
|
||||
Duration interval, {
|
||||
DateTime? start,
|
||||
}) {
|
||||
final now = _io0w16m8.clock.now().toUtc();
|
||||
return _FutureCallRef(
|
||||
(name, object) {
|
||||
return _futureCallManager.scheduleFutureCall(
|
||||
name,
|
||||
object,
|
||||
start ?? now.add(interval),
|
||||
_serverId,
|
||||
_identifier,
|
||||
scheduling: _is.IntervalFutureCallScheduling(
|
||||
interval: interval,
|
||||
start: start,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FutureCallRef {
|
||||
_FutureCallRef(this._invokeFutureCall);
|
||||
|
||||
final _InvokeFutureCall _invokeFutureCall;
|
||||
|
||||
late final pruning = _PruningFutureCallDispatcher(_invokeFutureCall);
|
||||
}
|
||||
|
||||
class _PruningFutureCallDispatcher {
|
||||
_PruningFutureCallDispatcher(this._invokeFutureCall);
|
||||
|
||||
final _InvokeFutureCall _invokeFutureCall;
|
||||
|
||||
Future<void> pruneAnonymousPeople() {
|
||||
return _invokeFutureCall(
|
||||
'PruningPruneAnonymousPeopleFutureCall',
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> forgetSignUpAttempts() {
|
||||
return _invokeFutureCall(
|
||||
'PruningForgetSignUpAttemptsFutureCall',
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prunes one batch and logs how many people went.
|
||||
class PruningPruneAnonymousPeopleFutureCall extends _is.FutureCall
|
||||
implements _is.InvokableFutureCall {
|
||||
@override
|
||||
_ida.Future<void> invoke(
|
||||
_is.Session session,
|
||||
_is.SerializableModel? object,
|
||||
) async {
|
||||
await _ibrplims.PruningFutureCall().pruneAnonymousPeople(session);
|
||||
}
|
||||
}
|
||||
|
||||
/// Forgets the sign-up attempts the rate limit is done with, with their IP
|
||||
/// addresses, and the email sign-in codes past their time, and logs how
|
||||
/// many.
|
||||
class PruningForgetSignUpAttemptsFutureCall extends _is.FutureCall
|
||||
implements _is.InvokableFutureCall {
|
||||
@override
|
||||
_ida.Future<void> invoke(
|
||||
_is.Session session,
|
||||
_is.SerializableModel? object,
|
||||
) async {
|
||||
await _ibrplims.PruningFutureCall().forgetSignUpAttempts(session);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:serverpod/serverpod.dart' as _is;
|
||||
|
||||
/// A greeting message which can be sent to or from the server.
|
||||
abstract class Greeting
|
||||
implements _is.SerializableModel, _is.ProtocolSerialization {
|
||||
Greeting._({
|
||||
required this.message,
|
||||
required this.author,
|
||||
required this.timestamp,
|
||||
});
|
||||
|
||||
factory Greeting({
|
||||
required String message,
|
||||
required String author,
|
||||
required DateTime timestamp,
|
||||
}) = _GreetingImpl;
|
||||
|
||||
factory Greeting.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return Greeting(
|
||||
message: jsonSerialization['message'] as String,
|
||||
author: jsonSerialization['author'] as String,
|
||||
timestamp: _is.DateTimeJsonExtension.fromJson(
|
||||
jsonSerialization['timestamp'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// The greeting message.
|
||||
String message;
|
||||
|
||||
/// The author of the greeting message.
|
||||
String author;
|
||||
|
||||
/// The time when the message was created.
|
||||
DateTime timestamp;
|
||||
|
||||
/// Returns a shallow copy of this [Greeting]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
Greeting copyWith({
|
||||
String? message,
|
||||
String? author,
|
||||
DateTime? timestamp,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'Greeting',
|
||||
'message': message,
|
||||
'author': author,
|
||||
'timestamp': timestamp.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'Greeting',
|
||||
'message': message,
|
||||
'author': author,
|
||||
'timestamp': timestamp.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _is.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _GreetingImpl extends Greeting {
|
||||
_GreetingImpl({
|
||||
required String message,
|
||||
required String author,
|
||||
required DateTime timestamp,
|
||||
}) : super._(
|
||||
message: message,
|
||||
author: author,
|
||||
timestamp: timestamp,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [Greeting]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
@override
|
||||
Greeting copyWith({
|
||||
String? message,
|
||||
String? author,
|
||||
DateTime? timestamp,
|
||||
}) {
|
||||
return Greeting(
|
||||
message: message ?? this.message,
|
||||
author: author ?? this.author,
|
||||
timestamp: timestamp ?? this.timestamp,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,14 +11,13 @@
|
|||
// ignore_for_file: dead_code, unnecessary_type_check
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:halkyon_base_server/halkyon_base_server.dart' as _ik8molhd;
|
||||
import 'package:serverpod/protocol.dart' as _isp;
|
||||
import 'package:serverpod/serverpod.dart' as _is;
|
||||
import 'package:serverpod_auth_core_server/serverpod_auth_core_server.dart'
|
||||
as _iacs;
|
||||
import 'package:serverpod_auth_idp_server/serverpod_auth_idp_server.dart'
|
||||
as _iais;
|
||||
import 'greetings/greeting.dart' as _izw8z7ou;
|
||||
export 'greetings/greeting.dart';
|
||||
|
||||
class Protocol extends _is.DatabaseSerializationManager {
|
||||
Protocol._();
|
||||
|
|
@ -28,6 +27,7 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
static final Protocol _instance = Protocol._().._registerHostProtocols();
|
||||
|
||||
static List<_isp.TableDefinition> get targetTableDefinitions => [
|
||||
..._ik8molhd.Protocol.targetTableDefinitions,
|
||||
..._iais.Protocol.targetTableDefinitions,
|
||||
..._iacs.Protocol.targetTableDefinitions,
|
||||
..._isp.Protocol.targetTableDefinitions,
|
||||
|
|
@ -60,12 +60,9 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
}
|
||||
}
|
||||
|
||||
if (t == _izw8z7ou.Greeting) {
|
||||
return _izw8z7ou.Greeting.fromJson(data) as T;
|
||||
}
|
||||
if (t == _is.getType<_izw8z7ou.Greeting?>()) {
|
||||
return (data != null ? _izw8z7ou.Greeting.fromJson(data) : null) as T;
|
||||
}
|
||||
try {
|
||||
return _ik8molhd.Protocol().deserialize<T>(data, t);
|
||||
} on _is.DeserializationTypeNotFoundException catch (_) {}
|
||||
try {
|
||||
return _iais.Protocol().deserialize<T>(data, t);
|
||||
} on _is.DeserializationTypeNotFoundException catch (_) {}
|
||||
|
|
@ -80,7 +77,6 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
|
||||
static String? getClassNameForType(Type type) {
|
||||
return switch (type) {
|
||||
_izw8z7ou.Greeting => 'Greeting',
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
|
@ -97,9 +93,9 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
);
|
||||
}
|
||||
|
||||
switch (data) {
|
||||
case _izw8z7ou.Greeting():
|
||||
return 'Greeting';
|
||||
className = _ik8molhd.Protocol().getClassNameForObject(data);
|
||||
if (className != null) {
|
||||
return className.contains('.') ? className : 'halkyon_base.$className';
|
||||
}
|
||||
className = _iais.Protocol().getClassNameForObject(data);
|
||||
if (className != null) {
|
||||
|
|
@ -126,8 +122,9 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
if (dataClassName is! String) {
|
||||
return super.deserializeByClassName(data);
|
||||
}
|
||||
if (dataClassName == 'Greeting') {
|
||||
return deserialize<_izw8z7ou.Greeting>(data['data']);
|
||||
if (dataClassName.startsWith('halkyon_base.')) {
|
||||
data['className'] = dataClassName.substring(13);
|
||||
return _ik8molhd.Protocol().deserializeByClassName(data);
|
||||
}
|
||||
if (dataClassName.startsWith('serverpod_auth_idp.')) {
|
||||
data['className'] = dataClassName.substring(19);
|
||||
|
|
@ -145,12 +142,19 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
}
|
||||
|
||||
void _registerHostProtocols() {
|
||||
_ik8molhd.Protocol().registerHostProtocol('halkyon_todo', this);
|
||||
_iais.Protocol().registerHostProtocol('halkyon_todo', this);
|
||||
_iacs.Protocol().registerHostProtocol('halkyon_todo', this);
|
||||
}
|
||||
|
||||
@override
|
||||
_is.Table? getTableForType(Type t) {
|
||||
{
|
||||
var table = _ik8molhd.Protocol().getTableForType(t);
|
||||
if (table != null) {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
{
|
||||
var table = _iais.Protocol().getTableForType(t);
|
||||
if (table != null) {
|
||||
|
|
@ -188,6 +192,9 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return _ik8molhd.Protocol().mapRecordToJson(record);
|
||||
} catch (_) {}
|
||||
try {
|
||||
return _iais.Protocol().mapRecordToJson(record);
|
||||
} catch (_) {}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
emailIdp:
|
||||
- login:
|
||||
- startRegistration:
|
||||
- verifyRegistrationCode:
|
||||
- finishRegistration:
|
||||
- startPasswordReset:
|
||||
- verifyPasswordResetCode:
|
||||
- finishPasswordReset:
|
||||
- hasAccount:
|
||||
greeting:
|
||||
- hello:
|
||||
|
|
@ -15,6 +15,7 @@ import 'package:serverpod/serverpod.dart' as _is;
|
|||
import 'endpoints.dart' as _iavctuc6;
|
||||
import 'protocol.dart' as _il2as5qe;
|
||||
export 'package:serverpod/serverpod.dart' hide Serverpod;
|
||||
export 'future_calls.dart' show ServerpodFutureCallsGetter;
|
||||
|
||||
/// The Serverpod server for this project.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
# Yaml-files in the `models` directory specify which serializable objects
|
||||
# should be generated. When you add or modify a file, you will need to run
|
||||
# `serverpod generate` to make the generated classes available in the server and
|
||||
# client.
|
||||
#
|
||||
# Please consult the documentation for more information on what you can add to
|
||||
# your yaml-files.
|
||||
|
||||
### A greeting message which can be sent to or from the server.
|
||||
class: Greeting
|
||||
|
||||
# Add the table key, if this class represents a row in the database.
|
||||
#table: greeting
|
||||
|
||||
# The fields (and columns if connected to the database) of the class.
|
||||
# For a list of supported types, please see the documentation.
|
||||
# https://docs.serverpod.dev/concepts/working-with-endpoints
|
||||
fields:
|
||||
### The greeting message.
|
||||
message: String
|
||||
### The author of the greeting message.
|
||||
author: String
|
||||
### The time when the message was created.
|
||||
timestamp: DateTime
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import '../generated/protocol.dart';
|
||||
|
||||
import 'package:serverpod/serverpod.dart';
|
||||
|
||||
// This is an example endpoint of your server. It's best practice to use the
|
||||
// `Endpoint` ending of the class name, but it will be removed when accessing
|
||||
// the endpoint from the client. I.e., this endpoint can be accessed through
|
||||
// `client.greeting` on the client side.
|
||||
|
||||
// After adding or modifying an endpoint, you will need to run
|
||||
// `serverpod generate` to update the server and client code.
|
||||
|
||||
/// This is an example endpoint that returns a greeting message through
|
||||
/// its [hello] method.
|
||||
class GreetingEndpoint extends Endpoint {
|
||||
// This method is called when the client calls the `hello` method on the
|
||||
// `greeting` endpoint.
|
||||
//
|
||||
// The `Session` parameter contains the context of the client request.
|
||||
// It provides access to the database and other server-side resources like
|
||||
// secrets from your password file, the cache, storage, and server-event
|
||||
// messaging.
|
||||
//
|
||||
// You can use any serializable type as a parameter or return type, read more
|
||||
// in the [docs](https://docs.serverpod.dev/concepts/working-with-endpoints).
|
||||
|
||||
/// Returns a personalized greeting message: "Hello {name}".
|
||||
Future<Greeting> hello(Session session, String name) async {
|
||||
return Greeting(
|
||||
message: 'Hello $name',
|
||||
author: 'Serverpod',
|
||||
timestamp: DateTime.now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue