@studyportals/sp-connect-backend-contracts 0.0.0-stage → 1.0.0-beta.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/README.md CHANGED
@@ -1,3 +1,12 @@
1
- # Temporary Holding Version
1
+ # @studyportals/sp-connect-backend-contracts
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Request and response contracts and business rules for the SP Connect API, published from
4
+ the backend repository so that clients and the service cannot drift apart. Every payload is
5
+ a zod schema with its type inferred from it, so `zod` is a peer dependency.
6
+
7
+ ```ts
8
+ import { SubmitQuestionRequestSchema, QUESTION_TEXT_MAX_LENGTH } from '@studyportals/sp-connect-backend-contracts';
9
+ import type { SubmitQuestionRequest } from '@studyportals/sp-connect-backend-contracts';
10
+ ```
11
+
12
+ This package contains no client: it describes the payloads, not how to send them.
@@ -0,0 +1,4 @@
1
+ /** Stable public route constants. */
2
+ export declare const API_PREFIX = "api";
3
+ export declare const API_VERSION = "1";
4
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1,4 @@
1
+ /** Stable public route constants. */
2
+ export const API_PREFIX = 'api';
3
+ export const API_VERSION = '1';
4
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ /** Error codes the API returns that no module owns; module codes live in each module's contracts. */
3
+ export declare const ErrorCode: {
4
+ readonly Internal: "internal_error";
5
+ readonly InvalidRequestBody: "request.invalid_body";
6
+ };
7
+ export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
8
+ /**
9
+ * `{ code, message, details? }` body of the API's own errors. Nest's built-in HTTP errors, such as
10
+ * a 401 from the auth guard, keep Nest's `{ statusCode, message, error }` body instead.
11
+ */
12
+ export declare const ErrorResponseSchema: z.ZodObject<{
13
+ code: z.ZodString;
14
+ message: z.ZodString;
15
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
16
+ }, z.core.$strip>;
17
+ export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
18
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ /** Error codes the API returns that no module owns; module codes live in each module's contracts. */
3
+ export const ErrorCode = {
4
+ Internal: 'internal_error',
5
+ InvalidRequestBody: 'request.invalid_body',
6
+ };
7
+ /**
8
+ * `{ code, message, details? }` body of the API's own errors. Nest's built-in HTTP errors, such as
9
+ * a 401 from the auth guard, keep Nest's `{ statusCode, message, error }` body instead.
10
+ */
11
+ export const ErrorResponseSchema = z.object({
12
+ code: z.string(),
13
+ message: z.string(),
14
+ details: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional(),
15
+ });
16
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,11 @@
1
+ export { API_PREFIX, API_VERSION } from './config/routes.js';
2
+ export { ErrorCode, ErrorResponseSchema } from './errors.js';
3
+ export type { ErrorResponse } from './errors.js';
4
+ export { ROLES, RoleSchema } from './roles.js';
5
+ export type { Role } from './roles.js';
6
+ export { CognitoPoolResponseSchema } from '../modules/auth/contracts/cognito-pool.js';
7
+ export type { CognitoPoolResponse } from '../modules/auth/contracts/cognito-pool.js';
8
+ export { EXTERNAL_ID_MAX_LENGTH, EXTERNAL_ID_PATTERN, QUESTION_TEXT_MAX_LENGTH, QUESTION_TEXT_MIN_LENGTH, QuestionErrorCode, } from '../modules/questions/contracts/question-rules.js';
9
+ export { SubmitQuestionRequestSchema, SubmitQuestionResponseSchema, } from '../modules/questions/contracts/submit-question.js';
10
+ export type { SubmitQuestionRequest, SubmitQuestionResponse, } from '../modules/questions/contracts/submit-question.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,7 @@
1
+ export { API_PREFIX, API_VERSION } from './config/routes.js';
2
+ export { ErrorCode, ErrorResponseSchema } from './errors.js';
3
+ export { ROLES, RoleSchema } from './roles.js';
4
+ export { CognitoPoolResponseSchema } from '../modules/auth/contracts/cognito-pool.js';
5
+ export { EXTERNAL_ID_MAX_LENGTH, EXTERNAL_ID_PATTERN, QUESTION_TEXT_MAX_LENGTH, QUESTION_TEXT_MIN_LENGTH, QuestionErrorCode, } from '../modules/questions/contracts/question-rules.js';
6
+ export { SubmitQuestionRequestSchema, SubmitQuestionResponseSchema, } from '../modules/questions/contracts/submit-question.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+ export declare const ROLES: readonly ["student", "expert", "admin"];
3
+ export declare const RoleSchema: z.ZodEnum<{
4
+ student: "student";
5
+ expert: "expert";
6
+ admin: "admin";
7
+ }>;
8
+ export type Role = z.infer<typeof RoleSchema>;
9
+ //# sourceMappingURL=roles.d.ts.map
@@ -0,0 +1,4 @@
1
+ import { z } from 'zod';
2
+ export const ROLES = ['student', 'expert', 'admin'];
3
+ export const RoleSchema = z.enum(ROLES);
4
+ //# sourceMappingURL=roles.js.map
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod';
2
+ export declare const CognitoPoolResponseSchema: z.ZodObject<{
3
+ userPoolId: z.ZodString;
4
+ userPoolClientId: z.ZodString;
5
+ }, z.core.$strip>;
6
+ export type CognitoPoolResponse = z.infer<typeof CognitoPoolResponseSchema>;
7
+ //# sourceMappingURL=cognito-pool.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ export const CognitoPoolResponseSchema = z.object({
3
+ userPoolId: z.string().min(1),
4
+ userPoolClientId: z.string().min(1),
5
+ });
6
+ //# sourceMappingURL=cognito-pool.js.map
@@ -0,0 +1,3 @@
1
+ export { EXTERNAL_ID_MAX_LENGTH, EXTERNAL_ID_PATTERN, QUESTION_TEXT_MAX_LENGTH, QUESTION_TEXT_MIN_LENGTH, } from '../domain/question-constraints.js';
2
+ export { QuestionErrorCode } from '../domain/question-error-codes.js';
3
+ //# sourceMappingURL=question-rules.d.ts.map
@@ -0,0 +1,3 @@
1
+ export { EXTERNAL_ID_MAX_LENGTH, EXTERNAL_ID_PATTERN, QUESTION_TEXT_MAX_LENGTH, QUESTION_TEXT_MIN_LENGTH, } from '../domain/question-constraints.js';
2
+ export { QuestionErrorCode } from '../domain/question-error-codes.js';
3
+ //# sourceMappingURL=question-rules.js.map
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod';
2
+ /** Public request and response shapes owned and published by the questions module. */
3
+ export declare const SubmitQuestionRequestSchema: z.ZodObject<{
4
+ programmeId: z.ZodString;
5
+ questionText: z.ZodString;
6
+ }, z.core.$strip>;
7
+ export type SubmitQuestionRequest = z.infer<typeof SubmitQuestionRequestSchema>;
8
+ export declare const SubmitQuestionResponseSchema: z.ZodObject<{
9
+ questionId: z.ZodUUID;
10
+ }, z.core.$strip>;
11
+ export type SubmitQuestionResponse = z.infer<typeof SubmitQuestionResponseSchema>;
12
+ //# sourceMappingURL=submit-question.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ import { EXTERNAL_ID_MAX_LENGTH, EXTERNAL_ID_PATTERN, QUESTION_TEXT_MAX_LENGTH, QUESTION_TEXT_MIN_LENGTH, } from './question-rules.js';
3
+ /** Public request and response shapes owned and published by the questions module. */
4
+ export const SubmitQuestionRequestSchema = z.object({
5
+ programmeId: z.string().trim().min(1).max(EXTERNAL_ID_MAX_LENGTH).regex(EXTERNAL_ID_PATTERN),
6
+ questionText: z.string().trim().min(QUESTION_TEXT_MIN_LENGTH).max(QUESTION_TEXT_MAX_LENGTH),
7
+ });
8
+ export const SubmitQuestionResponseSchema = z.object({
9
+ questionId: z.uuid(),
10
+ });
11
+ //# sourceMappingURL=submit-question.js.map
@@ -0,0 +1,5 @@
1
+ export declare const EXTERNAL_ID_MAX_LENGTH = 128;
2
+ export declare const EXTERNAL_ID_PATTERN: RegExp;
3
+ export declare const QUESTION_TEXT_MIN_LENGTH = 10;
4
+ export declare const QUESTION_TEXT_MAX_LENGTH = 280;
5
+ //# sourceMappingURL=question-constraints.d.ts.map
@@ -0,0 +1,5 @@
1
+ export const EXTERNAL_ID_MAX_LENGTH = 128;
2
+ export const EXTERNAL_ID_PATTERN = /^[A-Za-z0-9._:-]+$/;
3
+ export const QUESTION_TEXT_MIN_LENGTH = 10;
4
+ export const QUESTION_TEXT_MAX_LENGTH = 280;
5
+ //# sourceMappingURL=question-constraints.js.map
@@ -0,0 +1,9 @@
1
+ export declare const QuestionErrorCode: {
2
+ readonly InvalidId: "question.invalid_id";
3
+ readonly InvalidProgrammeId: "question.invalid_programme_id";
4
+ readonly InvalidStudentId: "question.invalid_student_id";
5
+ readonly InvalidText: "question.invalid_text";
6
+ readonly ProgrammeNotFound: "question.programme_not_found";
7
+ };
8
+ export type QuestionErrorCode = (typeof QuestionErrorCode)[keyof typeof QuestionErrorCode];
9
+ //# sourceMappingURL=question-error-codes.d.ts.map
@@ -0,0 +1,8 @@
1
+ export const QuestionErrorCode = {
2
+ InvalidId: 'question.invalid_id',
3
+ InvalidProgrammeId: 'question.invalid_programme_id',
4
+ InvalidStudentId: 'question.invalid_student_id',
5
+ InvalidText: 'question.invalid_text',
6
+ ProgrammeNotFound: 'question.programme_not_found',
7
+ };
8
+ //# sourceMappingURL=question-error-codes.js.map
package/package.json CHANGED
@@ -1,6 +1,29 @@
1
1
  {
2
2
  "name": "@studyportals/sp-connect-backend-contracts",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0-beta.0",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "exports": {
9
+ ".": {
10
+ "types": "./contracts/index.d.ts",
11
+ "import": "./contracts/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "contracts/**/*.js",
16
+ "contracts/**/*.d.ts",
17
+ "modules/**/*.js",
18
+ "modules/**/*.d.ts"
19
+ ],
20
+ "sideEffects": false,
21
+ "engines": {
22
+ "node": ">=20"
23
+ },
24
+ "peerDependencies": {
25
+ "zod": "^4.0.0"
26
+ },
27
+ "description": "Public API contracts and business rules of the SP Connect backend.",
28
+ "license": "UNLICENSED"
29
+ }