timeback 0.1.0 → 0.1.2

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.
Files changed (44) hide show
  1. package/README.md +349 -121
  2. package/dist/client/adapters/vue/SignInButton.vue +260 -0
  3. package/dist/client/adapters/vue/SignInButton.vue.d.ts +53 -0
  4. package/dist/client/adapters/vue/index.d.ts +43 -0
  5. package/dist/client/adapters/vue/index.d.ts.map +1 -0
  6. package/dist/client/adapters/vue/index.ts +48 -0
  7. package/dist/client/adapters/vue/provider.d.ts +94 -0
  8. package/dist/client/adapters/vue/provider.d.ts.map +1 -0
  9. package/dist/client/adapters/vue/provider.ts +147 -0
  10. package/dist/index.d.ts +20 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +271 -22
  13. package/dist/server/adapters/express.d.ts +9 -5
  14. package/dist/server/adapters/express.d.ts.map +1 -1
  15. package/dist/server/adapters/express.js +19 -3
  16. package/dist/server/adapters/native.d.ts +5 -3
  17. package/dist/server/adapters/native.d.ts.map +1 -1
  18. package/dist/server/adapters/native.js +11 -3
  19. package/dist/server/adapters/nextjs.d.ts +5 -3
  20. package/dist/server/adapters/nextjs.d.ts.map +1 -1
  21. package/dist/server/adapters/nextjs.js +11 -3
  22. package/dist/server/adapters/nuxt.d.ts +98 -0
  23. package/dist/server/adapters/nuxt.d.ts.map +1 -0
  24. package/dist/server/adapters/nuxt.js +673 -0
  25. package/dist/server/adapters/solid-start.d.ts +5 -3
  26. package/dist/server/adapters/solid-start.d.ts.map +1 -1
  27. package/dist/server/adapters/solid-start.js +16 -6
  28. package/dist/server/adapters/svelte-kit.d.ts +5 -3
  29. package/dist/server/adapters/svelte-kit.d.ts.map +1 -1
  30. package/dist/server/adapters/svelte-kit.js +16 -6
  31. package/dist/server/adapters/tanstack-start.d.ts +42 -0
  32. package/dist/server/adapters/tanstack-start.d.ts.map +1 -0
  33. package/dist/server/adapters/tanstack-start.js +11 -3
  34. package/dist/server/adapters/types.d.ts +91 -9
  35. package/dist/server/adapters/types.d.ts.map +1 -1
  36. package/dist/server/adapters/utils.d.ts +24 -5
  37. package/dist/server/adapters/utils.d.ts.map +1 -1
  38. package/dist/server/index.d.ts +2 -2
  39. package/dist/server/index.d.ts.map +1 -1
  40. package/dist/server/timeback.d.ts +39 -2
  41. package/dist/server/timeback.d.ts.map +1 -1
  42. package/dist/server/types.d.ts +37 -0
  43. package/dist/server/types.d.ts.map +1 -1
  44. package/package.json +14 -2
package/dist/index.js CHANGED
@@ -358,19 +358,255 @@ var SubjectTrackInput = z4.object({
358
358
  targetCourseId: z4.string(),
359
359
  metadata: z4.record(z4.string(), z4.unknown()).optional()
360
360
  });
361
+ // ../types/src/zod/qti.ts
362
+ import { z as z5 } from "zod/v4";
363
+ var QtiAssessmentItemType = z5.enum([
364
+ "choice",
365
+ "text-entry",
366
+ "extended-text",
367
+ "inline-choice",
368
+ "match",
369
+ "order",
370
+ "associate",
371
+ "select-point",
372
+ "graphic-order",
373
+ "graphic-associate",
374
+ "graphic-gap-match",
375
+ "hotspot",
376
+ "hottext",
377
+ "slider",
378
+ "drawing",
379
+ "media",
380
+ "upload"
381
+ ]);
382
+ var QtiCardinality = z5.enum(["single", "multiple", "ordered", "record"]);
383
+ var QtiBaseType = z5.enum([
384
+ "identifier",
385
+ "boolean",
386
+ "integer",
387
+ "float",
388
+ "string",
389
+ "point",
390
+ "pair",
391
+ "directedPair",
392
+ "duration",
393
+ "file",
394
+ "uri"
395
+ ]);
396
+ var QtiDifficulty = z5.enum(["easy", "medium", "hard"]);
397
+ var QtiNavigationMode = z5.enum(["linear", "nonlinear"]);
398
+ var QtiSubmissionMode = z5.enum(["individual", "simultaneous"]);
399
+ var QtiShowHide = z5.enum(["show", "hide"]);
400
+ var QtiValidationSchema = z5.enum(["test", "item", "stimulus"]);
401
+ var QtiFeedbackType = z5.enum(["QUESTION", "LESSON"]);
402
+ var QtiCorrectResponse = z5.object({
403
+ value: z5.array(z5.string())
404
+ }).strict();
405
+ var QtiResponseDeclaration = z5.object({
406
+ identifier: z5.string().min(1),
407
+ cardinality: QtiCardinality,
408
+ baseType: QtiBaseType.optional(),
409
+ correctResponse: QtiCorrectResponse
410
+ }).strict();
411
+ var QtiOutcomeDeclaration = z5.object({
412
+ identifier: z5.string().min(1),
413
+ cardinality: QtiCardinality,
414
+ baseType: QtiBaseType.optional()
415
+ }).strict();
416
+ var QtiTestOutcomeDeclaration = z5.object({
417
+ identifier: z5.string().min(1),
418
+ cardinality: QtiCardinality.optional(),
419
+ baseType: QtiBaseType,
420
+ normalMaximum: z5.number().optional(),
421
+ normalMinimum: z5.number().optional(),
422
+ defaultValue: z5.object({
423
+ value: z5.unknown().optional()
424
+ }).strict().optional()
425
+ }).strict();
426
+ var QtiInlineFeedback = z5.object({
427
+ outcomeIdentifier: z5.string().min(1),
428
+ variableIdentifier: z5.string().min(1)
429
+ }).strict();
430
+ var QtiResponseProcessing = z5.object({
431
+ templateType: z5.enum(["match_correct", "map_response"]),
432
+ responseDeclarationIdentifier: z5.string().min(1),
433
+ outcomeIdentifier: z5.string().min(1),
434
+ correctResponseIdentifier: z5.string().min(1),
435
+ incorrectResponseIdentifier: z5.string().min(1),
436
+ inlineFeedback: QtiInlineFeedback.optional()
437
+ }).strict();
438
+ var QtiLearningObjectiveSet = z5.object({
439
+ source: z5.string().min(1),
440
+ learningObjectiveIds: z5.array(z5.string())
441
+ }).strict();
442
+ var QtiItemMetadata = z5.object({
443
+ subject: z5.string().optional(),
444
+ grade: TimebackGrade.optional(),
445
+ difficulty: QtiDifficulty.optional(),
446
+ learningObjectiveSet: z5.array(QtiLearningObjectiveSet).optional()
447
+ }).strict();
448
+ var QtiModalFeedback = z5.object({
449
+ outcomeIdentifier: z5.string().min(1),
450
+ identifier: z5.string().min(1),
451
+ showHide: QtiShowHide,
452
+ content: z5.string(),
453
+ title: z5.string()
454
+ }).strict();
455
+ var QtiFeedbackInline = z5.object({
456
+ outcomeIdentifier: z5.string().min(1),
457
+ identifier: z5.string().min(1),
458
+ showHide: QtiShowHide,
459
+ content: z5.string(),
460
+ class: z5.array(z5.string())
461
+ }).strict();
462
+ var QtiFeedbackBlock = z5.object({
463
+ outcomeIdentifier: z5.string().min(1),
464
+ identifier: z5.string().min(1),
465
+ showHide: QtiShowHide,
466
+ content: z5.string(),
467
+ class: z5.array(z5.string())
468
+ }).strict();
469
+ var QtiStylesheet = z5.object({
470
+ href: z5.string().min(1),
471
+ type: z5.string().min(1)
472
+ }).strict();
473
+ var QtiCatalogInfo = z5.object({
474
+ id: z5.string().min(1),
475
+ support: z5.string(),
476
+ content: z5.string()
477
+ }).strict();
478
+ var QtiAssessmentItemCreateInput = z5.object({
479
+ identifier: z5.string().min(1),
480
+ title: z5.string().min(1),
481
+ type: QtiAssessmentItemType,
482
+ qtiVersion: z5.string().optional(),
483
+ timeDependent: z5.boolean().optional(),
484
+ adaptive: z5.boolean().optional(),
485
+ responseDeclarations: z5.array(QtiResponseDeclaration).optional(),
486
+ outcomeDeclarations: z5.array(QtiOutcomeDeclaration).optional(),
487
+ responseProcessing: QtiResponseProcessing.optional(),
488
+ metadata: QtiItemMetadata.optional(),
489
+ modalFeedback: z5.array(QtiModalFeedback).optional(),
490
+ feedbackInline: z5.array(QtiFeedbackInline).optional(),
491
+ feedbackBlock: z5.array(QtiFeedbackBlock).optional()
492
+ }).strict();
493
+ var QtiAssessmentItemUpdateInput = z5.object({
494
+ title: z5.string().min(1),
495
+ type: QtiAssessmentItemType,
496
+ qtiVersion: z5.string().optional(),
497
+ timeDependent: z5.boolean().optional(),
498
+ adaptive: z5.boolean().optional(),
499
+ responseDeclarations: z5.array(QtiResponseDeclaration).optional(),
500
+ outcomeDeclarations: z5.array(QtiOutcomeDeclaration).optional(),
501
+ responseProcessing: QtiResponseProcessing.optional(),
502
+ metadata: QtiItemMetadata.optional(),
503
+ modalFeedback: z5.array(QtiModalFeedback).optional(),
504
+ feedbackInline: z5.array(QtiFeedbackInline).optional(),
505
+ feedbackBlock: z5.array(QtiFeedbackBlock).optional(),
506
+ rawXml: z5.string(),
507
+ content: z5.record(z5.string(), z5.unknown())
508
+ }).strict();
509
+ var QtiAssessmentItemProcessResponseInput = z5.object({
510
+ response: z5.union([z5.string(), z5.array(z5.string())])
511
+ }).strict();
512
+ var QtiAssessmentItemRef = z5.object({
513
+ identifier: z5.string().min(1),
514
+ href: z5.union([z5.string(), z5.array(z5.string()), z5.array(z5.array(z5.string()))]).optional(),
515
+ sequence: z5.number().optional()
516
+ }).strict();
517
+ var QtiAssessmentSection = z5.object({
518
+ identifier: z5.string().min(1),
519
+ title: z5.string().min(1),
520
+ visible: z5.boolean(),
521
+ required: z5.boolean().optional(),
522
+ fixed: z5.boolean().optional(),
523
+ sequence: z5.number().optional(),
524
+ "qti-assessment-item-ref": z5.array(QtiAssessmentItemRef).optional()
525
+ }).strict();
526
+ var QtiTestPart = z5.object({
527
+ identifier: z5.string().min(1),
528
+ navigationMode: QtiNavigationMode,
529
+ submissionMode: QtiSubmissionMode,
530
+ "qti-assessment-section": z5.union([QtiAssessmentSection, z5.array(QtiAssessmentSection)])
531
+ }).strict();
532
+ var QtiAssessmentTestCreateInput = z5.object({
533
+ identifier: z5.string().min(1),
534
+ title: z5.string().min(1),
535
+ qtiVersion: z5.string().optional(),
536
+ toolName: z5.string().optional(),
537
+ toolVersion: z5.string().optional(),
538
+ timeLimit: z5.number().optional(),
539
+ maxAttempts: z5.number().optional(),
540
+ toolsEnabled: z5.record(z5.string(), z5.boolean()).optional(),
541
+ metadata: z5.record(z5.string(), z5.unknown()).optional(),
542
+ "qti-test-part": QtiTestPart,
543
+ "qti-outcome-declaration": z5.array(QtiTestOutcomeDeclaration).optional()
544
+ }).strict();
545
+ var QtiAssessmentTestUpdateInput = z5.object({
546
+ title: z5.string().min(1),
547
+ qtiVersion: z5.string().optional(),
548
+ toolName: z5.string().optional(),
549
+ toolVersion: z5.string().optional(),
550
+ timeLimit: z5.number().optional(),
551
+ maxAttempts: z5.number().optional(),
552
+ toolsEnabled: z5.record(z5.string(), z5.boolean()).optional(),
553
+ metadata: z5.record(z5.string(), z5.unknown()).optional(),
554
+ "qti-test-part": QtiTestPart,
555
+ "qti-outcome-declaration": z5.array(QtiTestOutcomeDeclaration).optional()
556
+ }).strict();
557
+ var QtiStimulusCreateInput = z5.object({
558
+ identifier: z5.string().min(1),
559
+ title: z5.string().min(1),
560
+ label: z5.string().optional(),
561
+ language: z5.string().optional(),
562
+ stylesheet: QtiStylesheet.optional(),
563
+ content: z5.string(),
564
+ catalogInfo: z5.array(QtiCatalogInfo).optional(),
565
+ toolName: z5.string().optional(),
566
+ toolVersion: z5.string().optional(),
567
+ metadata: z5.record(z5.string(), z5.unknown()).optional()
568
+ }).strict();
569
+ var QtiStimulusUpdateInput = z5.object({
570
+ title: z5.string().min(1),
571
+ label: z5.string().optional(),
572
+ language: z5.string().optional(),
573
+ stylesheet: QtiStylesheet.optional(),
574
+ content: z5.string(),
575
+ catalogInfo: z5.array(QtiCatalogInfo).optional(),
576
+ toolName: z5.string().optional(),
577
+ toolVersion: z5.string().optional(),
578
+ metadata: z5.record(z5.string(), z5.unknown()).optional()
579
+ }).strict();
580
+ var QtiValidateInput = z5.object({
581
+ xml: z5.string().optional(),
582
+ schema: QtiValidationSchema,
583
+ entityId: z5.string().optional()
584
+ }).strict();
585
+ var QtiValidateBatchInput = z5.object({
586
+ xml: z5.array(z5.string()),
587
+ schema: QtiValidationSchema,
588
+ entityIds: z5.array(z5.string())
589
+ }).strict();
590
+ var QtiLessonFeedbackInput = z5.object({
591
+ questionId: z5.string().optional(),
592
+ userId: z5.string().min(1),
593
+ feedback: z5.string().min(1),
594
+ lessonId: z5.string().min(1),
595
+ humanApproved: z5.boolean().optional()
596
+ }).strict();
361
597
  // ../internal/cli-infra/src/credentials/store.ts
362
598
  import { homedir, platform as platform2 } from "node:os";
363
599
  import { join } from "node:path";
364
600
 
365
601
  // ../internal/cli-infra/src/credentials/schema.ts
366
- import { z as z5 } from "zod";
367
- var CredentialsSchema = z5.object({
368
- clientId: z5.string().min(1, "Client ID is required"),
369
- clientSecret: z5.string().min(1, "Client secret is required"),
370
- email: z5.email("Valid email is required").optional()
602
+ import { z as z6 } from "zod";
603
+ var CredentialsSchema = z6.object({
604
+ clientId: z6.string().min(1, "Client ID is required"),
605
+ clientSecret: z6.string().min(1, "Client secret is required"),
606
+ email: z6.email("Valid email is required").optional()
371
607
  });
372
- var ClientIdSchema = z5.string().min(1, "Client ID is required").regex(/^[a-z0-9]+$/, "Client ID must contain only lowercase letters and numbers").length(26, "Client ID must be exactly 26 characters");
373
- var ClientSecretSchema = z5.string().min(1, "Client secret is required").regex(/^[a-z0-9]+$/, "Client secret must contain only lowercase letters and numbers").max(53, "Client secret must be less than 53 characters");
608
+ var ClientIdSchema = z6.string().min(1, "Client ID is required").regex(/^[a-z0-9]+$/, "Client ID must contain only lowercase letters and numbers").length(26, "Client ID must be exactly 26 characters");
609
+ var ClientSecretSchema = z6.string().min(1, "Client secret is required").regex(/^[a-z0-9]+$/, "Client secret must contain only lowercase letters and numbers").max(53, "Client secret must be less than 53 characters");
374
610
 
375
611
  // ../internal/cli-infra/src/credentials/store.ts
376
612
  function getConfigDir() {
@@ -1036,21 +1272,21 @@ function createIdentityHandlers(params) {
1036
1272
  };
1037
1273
  }
1038
1274
  // src/server/handlers/activity.ts
1039
- import * as z6 from "zod";
1040
- var activityMetricsSchema = z6.object({
1041
- totalQuestions: z6.number().int().nonnegative().optional(),
1042
- correctQuestions: z6.number().int().nonnegative().optional(),
1043
- xpEarned: z6.number().int().nonnegative().optional(),
1044
- masteredUnits: z6.number().int().nonnegative().optional()
1275
+ import * as z7 from "zod";
1276
+ var activityMetricsSchema = z7.object({
1277
+ totalQuestions: z7.number().int().nonnegative().optional(),
1278
+ correctQuestions: z7.number().int().nonnegative().optional(),
1279
+ xpEarned: z7.number().int().nonnegative().optional(),
1280
+ masteredUnits: z7.number().int().nonnegative().optional()
1045
1281
  });
1046
- var activityEndPayloadSchema = z6.object({
1047
- id: z6.string().min(1),
1048
- name: z6.string().min(1),
1049
- courseCode: z6.string().min(1),
1050
- startedAt: z6.iso.datetime(),
1051
- endedAt: z6.iso.datetime(),
1052
- elapsedMs: z6.number().int().nonnegative(),
1053
- pausedMs: z6.number().int().nonnegative(),
1282
+ var activityEndPayloadSchema = z7.object({
1283
+ id: z7.string().min(1),
1284
+ name: z7.string().min(1),
1285
+ courseCode: z7.string().min(1),
1286
+ startedAt: z7.iso.datetime(),
1287
+ endedAt: z7.iso.datetime(),
1288
+ elapsedMs: z7.number().int().nonnegative(),
1289
+ pausedMs: z7.number().int().nonnegative(),
1054
1290
  metrics: activityMetricsSchema
1055
1291
  });
1056
1292
  function createActivityHandler(config2) {
@@ -1138,6 +1374,19 @@ async function createServer(config2) {
1138
1374
  }
1139
1375
  };
1140
1376
  }
1377
+ function createIdentityServer(config2) {
1378
+ const identity = createIdentityHandlers({
1379
+ env: config2.env,
1380
+ identity: config2.identity
1381
+ });
1382
+ return {
1383
+ config: config2,
1384
+ handle: {
1385
+ identity
1386
+ }
1387
+ };
1388
+ }
1141
1389
  export {
1142
- createServer
1390
+ createServer,
1391
+ createIdentityServer
1143
1392
  };
@@ -7,7 +7,7 @@
7
7
  * Uses minimal generic interfaces that work with any framework implementing
8
8
  * the Express middleware pattern.
9
9
  */
10
- import type { ExpressLikeHandler, ExpressLikeRouter, TimebackInput } from './types';
10
+ import type { AnyTimebackInput, ExpressLikeHandler, ExpressLikeRouter } from './types';
11
11
  /**
12
12
  * Convert Timeback instance to Express middleware.
13
13
  *
@@ -15,7 +15,9 @@ import type { ExpressLikeHandler, ExpressLikeRouter, TimebackInput } from './typ
15
15
  * - `toExpressMiddleware(timeback)`
16
16
  * - `toExpressMiddleware(timeback.handle)`
17
17
  *
18
- * @param input - Timeback instance or handlers
18
+ * Also accepts identity-only instances from `createIdentityServer()`.
19
+ *
20
+ * @param input - Timeback instance or handlers (full or identity-only)
19
21
  * @returns Express middleware function
20
22
  *
21
23
  * @example
@@ -32,7 +34,7 @@ import type { ExpressLikeHandler, ExpressLikeRouter, TimebackInput } from './typ
32
34
  * app.listen(3000)
33
35
  * ```
34
36
  */
35
- export declare function toExpressMiddleware(input: TimebackInput): ExpressLikeHandler;
37
+ export declare function toExpressMiddleware(input: AnyTimebackInput): ExpressLikeHandler;
36
38
  /**
37
39
  * Mount Timeback routes on an Express router.
38
40
  *
@@ -40,7 +42,9 @@ export declare function toExpressMiddleware(input: TimebackInput): ExpressLikeHa
40
42
  * - `mountExpressRoutes(timeback, router)`
41
43
  * - `mountExpressRoutes(timeback.handle, router)`
42
44
  *
43
- * @param input - Timeback instance or handlers
45
+ * Also accepts identity-only instances from `createIdentityServer()`.
46
+ *
47
+ * @param input - Timeback instance or handlers (full or identity-only)
44
48
  * @param router - Express router to mount routes on
45
49
  *
46
50
  * @example
@@ -58,5 +62,5 @@ export declare function toExpressMiddleware(input: TimebackInput): ExpressLikeHa
58
62
  * app.listen(3000)
59
63
  * ```
60
64
  */
61
- export declare function mountExpressRoutes(input: TimebackInput, router: ExpressLikeRouter): void;
65
+ export declare function mountExpressRoutes(input: AnyTimebackInput, router: ExpressLikeRouter): void;
62
66
  //# sourceMappingURL=express.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACX,kBAAkB,EAIlB,iBAAiB,EACjB,aAAa,EACb,MAAM,SAAS,CAAA;AA6FhB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,kBAAkB,CA+C5E;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAiDxF"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAIlB,iBAAiB,EACjB,MAAM,SAAS,CAAA;AA6FhB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,kBAAkB,CAqD/E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAyD3F"}
@@ -470,6 +470,12 @@ function decodeBase64Url(encoded) {
470
470
  function getHandlers(input) {
471
471
  return "handle" in input ? input.handle : input;
472
472
  }
473
+ function hasActivityHandler(handlers) {
474
+ return "activity" in handlers;
475
+ }
476
+ function hasUserHandler(handlers) {
477
+ return "user" in handlers;
478
+ }
473
479
 
474
480
  // src/server/adapters/express.ts
475
481
  function toWebRequest(req) {
@@ -525,8 +531,13 @@ function toExpressMiddleware(input) {
525
531
  return Promise.resolve(handle.identity.signOut());
526
532
  }
527
533
  }
528
- if (req.method === "POST") {
529
- if (path.endsWith(ROUTES.ACTIVITY)) {
534
+ if (hasUserHandler(handle)) {
535
+ if (req.method === "GET" && path.endsWith(ROUTES.USER.ME)) {
536
+ return handle.user.me(webReq);
537
+ }
538
+ }
539
+ if (hasActivityHandler(handle)) {
540
+ if (req.method === "POST" && path.endsWith(ROUTES.ACTIVITY)) {
530
541
  return handle.activity(webReq);
531
542
  }
532
543
  }
@@ -557,7 +568,12 @@ function mountExpressRoutes(input, router) {
557
568
  router.get(ROUTES.IDENTITY.SIGNIN, createHandler((req) => handle.identity.signIn(req)));
558
569
  router.get(ROUTES.IDENTITY.CALLBACK, createHandler((req) => handle.identity.callback(req)));
559
570
  router.get(ROUTES.IDENTITY.SIGNOUT, createHandler(() => handle.identity.signOut()));
560
- router.post(ROUTES.ACTIVITY, createHandler((req) => handle.activity(req)));
571
+ if (hasUserHandler(handle)) {
572
+ router.get(ROUTES.USER.ME, createHandler((req) => handle.user.me(req)));
573
+ }
574
+ if (hasActivityHandler(handle)) {
575
+ router.post(ROUTES.ACTIVITY, createHandler((req) => handle.activity(req)));
576
+ }
561
577
  }
562
578
  export {
563
579
  toExpressMiddleware,
@@ -4,7 +4,7 @@
4
4
  * Universal handler for any runtime that supports the Web Fetch API:
5
5
  * Bun, Deno, Cloudflare Workers, Hono, etc.
6
6
  */
7
- import type { NativeHandlerOptions, TimebackInput } from './types';
7
+ import type { AnyTimebackInput, NativeHandlerOptions } from './types';
8
8
  /**
9
9
  * Create a native Fetch API handler.
10
10
  *
@@ -15,7 +15,9 @@ import type { NativeHandlerOptions, TimebackInput } from './types';
15
15
  * - `toNativeHandler(timeback)`
16
16
  * - `toNativeHandler(timeback.handle)`
17
17
  *
18
- * @param input - Timeback instance or handlers
18
+ * Also accepts identity-only instances from `createIdentityServer()`.
19
+ *
20
+ * @param input - Timeback instance or handlers (full or identity-only)
19
21
  * @returns Universal request handler
20
22
  *
21
23
  * @example
@@ -41,5 +43,5 @@ import type { NativeHandlerOptions, TimebackInput } from './types';
41
43
  * Deno.serve(handler)
42
44
  * ```
43
45
  */
44
- export declare function toNativeHandler(input: TimebackInput | NativeHandlerOptions): (req: Request) => Promise<Response>;
46
+ export declare function toNativeHandler(input: AnyTimebackInput | NativeHandlerOptions): (req: Request) => Promise<Response>;
45
47
  //# sourceMappingURL=native.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/native.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAYlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,aAAa,GAAG,oBAAoB,GACzC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAyCrC"}
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/native.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAYrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,eAAe,CAC9B,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAC5C,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA2CrC"}
@@ -470,6 +470,12 @@ function decodeBase64Url(encoded) {
470
470
  function getHandlers(input) {
471
471
  return "handle" in input ? input.handle : input;
472
472
  }
473
+ function hasActivityHandler(handlers) {
474
+ return "activity" in handlers;
475
+ }
476
+ function hasUserHandler(handlers) {
477
+ return "user" in handlers;
478
+ }
473
479
 
474
480
  // src/server/adapters/native.ts
475
481
  function isNativeHandlerOptions(v) {
@@ -492,12 +498,14 @@ function toNativeHandler(input) {
492
498
  if (path.endsWith(ROUTES.IDENTITY.SIGNOUT)) {
493
499
  return Promise.resolve(handle.identity.signOut());
494
500
  }
495
- if (path.endsWith(ROUTES.USER.ME)) {
501
+ }
502
+ if (hasUserHandler(handle)) {
503
+ if (method === "GET" && path.endsWith(ROUTES.USER.ME)) {
496
504
  return handle.user.me(req);
497
505
  }
498
506
  }
499
- if (method === "POST") {
500
- if (path.endsWith(ROUTES.ACTIVITY)) {
507
+ if (hasActivityHandler(handle)) {
508
+ if (method === "POST" && path.endsWith(ROUTES.ACTIVITY)) {
501
509
  return handle.activity(req);
502
510
  }
503
511
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Adapts Timeback handlers for Next.js App Router.
5
5
  */
6
- import type { NextjsHandlers, TimebackInput } from './types';
6
+ import type { AnyTimebackInput, NextjsHandlers } from './types';
7
7
  /**
8
8
  * Convert Timeback instance to Next.js App Router handlers.
9
9
  *
@@ -14,7 +14,9 @@ import type { NextjsHandlers, TimebackInput } from './types';
14
14
  * - `toNextjsHandler(timeback)`
15
15
  * - `toNextjsHandler(timeback.handle)`
16
16
  *
17
- * @param input - Timeback instance or handlers
17
+ * Also accepts identity-only instances from `createIdentityServer()`.
18
+ *
19
+ * @param input - Timeback instance or handlers (full or identity-only)
18
20
  * @returns Object with HTTP method handlers for Next.js App Router
19
21
  *
20
22
  * @example
@@ -26,5 +28,5 @@ import type { NextjsHandlers, TimebackInput } from './types';
26
28
  * export const { GET, POST } = toNextjsHandler(timeback)
27
29
  * ```
28
30
  */
29
- export declare function toNextjsHandler(input: TimebackInput): NextjsHandlers;
31
+ export declare function toNextjsHandler(input: AnyTimebackInput): NextjsHandlers;
30
32
  //# sourceMappingURL=nextjs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/nextjs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAUpE"}
1
+ {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/nextjs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,CAUvE"}
@@ -470,6 +470,12 @@ function decodeBase64Url(encoded) {
470
470
  function getHandlers(input) {
471
471
  return "handle" in input ? input.handle : input;
472
472
  }
473
+ function hasActivityHandler(handlers) {
474
+ return "activity" in handlers;
475
+ }
476
+ function hasUserHandler(handlers) {
477
+ return "user" in handlers;
478
+ }
473
479
 
474
480
  // src/server/adapters/native.ts
475
481
  function isNativeHandlerOptions(v) {
@@ -492,12 +498,14 @@ function toNativeHandler(input) {
492
498
  if (path.endsWith(ROUTES.IDENTITY.SIGNOUT)) {
493
499
  return Promise.resolve(handle.identity.signOut());
494
500
  }
495
- if (path.endsWith(ROUTES.USER.ME)) {
501
+ }
502
+ if (hasUserHandler(handle)) {
503
+ if (method === "GET" && path.endsWith(ROUTES.USER.ME)) {
496
504
  return handle.user.me(req);
497
505
  }
498
506
  }
499
- if (method === "POST") {
500
- if (path.endsWith(ROUTES.ACTIVITY)) {
507
+ if (hasActivityHandler(handle)) {
508
+ if (method === "POST" && path.endsWith(ROUTES.ACTIVITY)) {
501
509
  return handle.activity(req);
502
510
  }
503
511
  }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Nuxt Adapter
3
+ *
4
+ * Adapts Timeback handlers for Nuxt 3.
5
+ * Supports both middleware-based (recommended) and route-based approaches.
6
+ *
7
+ * This adapter does NOT import h3 or nuxt - it uses minimal interfaces
8
+ * that are compatible with H3's event structure.
9
+ */
10
+ import type { AnyTimebackInput, NuxtHandlerOptions, NuxtHandlers, NuxtLikeEvent } from './types';
11
+ /**
12
+ * Nuxt server middleware handler for Timeback.
13
+ *
14
+ * This is the **recommended** approach for Nuxt 3 integration.
15
+ * It intercepts requests at the middleware level before they reach route handlers.
16
+ *
17
+ * Returns a Response if the request matches a Timeback route, or undefined
18
+ * to let the request continue to other handlers.
19
+ *
20
+ * @param options - Handler options
21
+ * @returns Response from Timeback or undefined to continue
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // server/middleware/timeback.ts
26
+ * import { timeback } from '~/lib/timeback'
27
+ * import { nuxtHandler } from 'timeback/nuxt'
28
+ *
29
+ * export default defineEventHandler(async (event) => {
30
+ * const response = await nuxtHandler({
31
+ * timeback,
32
+ * event,
33
+ * })
34
+ *
35
+ * if (response) {
36
+ * return response
37
+ * }
38
+ * })
39
+ * ```
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // server/middleware/timeback.ts - with custom callback path
44
+ * import { timeback } from '~/lib/timeback'
45
+ * import { nuxtHandler } from 'timeback/nuxt'
46
+ *
47
+ * export default defineEventHandler(async (event) => {
48
+ * const response = await nuxtHandler({
49
+ * timeback,
50
+ * event,
51
+ * callbackPath: '/api/auth/sso/callback/timeback',
52
+ * })
53
+ *
54
+ * if (response) {
55
+ * return response
56
+ * }
57
+ * })
58
+ * ```
59
+ */
60
+ export declare function nuxtHandler<TEvent extends NuxtLikeEvent>(options: NuxtHandlerOptions<TEvent>): Promise<Response | undefined>;
61
+ /**
62
+ * Convert Timeback instance to Nuxt route handlers.
63
+ *
64
+ * This is an **alternative** approach using Nuxt's catch-all route handlers.
65
+ * Use this if you prefer explicit route files over middleware.
66
+ *
67
+ * Accepts either the full Timeback instance or just the handlers:
68
+ * - `toNuxtHandler(timeback)`
69
+ * - `toNuxtHandler(timeback.handle)`
70
+ *
71
+ * Also accepts identity-only instances from `createIdentityServer()`.
72
+ *
73
+ * @param input - Timeback instance or handlers (full or identity-only), or options object
74
+ * @returns Object with HTTP method handlers for Nuxt
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * // server/api/timeback/[...timeback].ts
79
+ * import { timeback } from '~/lib/timeback'
80
+ * import { toNuxtHandler } from 'timeback/nuxt'
81
+ *
82
+ * const handlers = toNuxtHandler(timeback)
83
+ *
84
+ * export default defineEventHandler(async (event) => {
85
+ * const method = event.request?.method ?? event.node?.req?.method ?? 'GET'
86
+ * const handler = handlers[method as keyof typeof handlers]
87
+ * if (handler) {
88
+ * return handler(event)
89
+ * }
90
+ * return new Response('Method not allowed', { status: 405 })
91
+ * })
92
+ * ```
93
+ */
94
+ export declare function toNuxtHandler(input: AnyTimebackInput | {
95
+ timeback: AnyTimebackInput;
96
+ callbackPath?: string;
97
+ }): NuxtHandlers;
98
+ //# sourceMappingURL=nuxt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/nuxt.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACX,gBAAgB,EAEhB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,MAAM,SAAS,CAAA;AAsNhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,WAAW,CAAC,MAAM,SAAS,aAAa,EAC7D,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CA+C/B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,gBAAgB,GAAG;IAAE,QAAQ,EAAE,gBAAgB,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,YAAY,CAyDd"}